blob: 876953f11324293ccc4b4d95ce26407e72fa36ef [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'
Simon Glass4e353e22019-08-24 07:23:04 -060046U_BOOT_SPL_DATA = b'56780123456789abcdefghi'
47U_BOOT_TPL_DATA = b'tpl9876543210fedcbazyw'
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"'
Simon Glassa435cd12020-09-01 05:13:59 -060094
95# Subdirectory of the input dir to use to put test FDTs
96TEST_FDT_SUBDIR = 'fdts'
Simon Glassdb168d42018-07-17 13:25:39 -060097
Simon Glass2c6adba2019-07-20 12:23:47 -060098# The expected size for the device tree in some tests
Simon Glass4c613bf2019-07-08 14:25:50 -060099EXTRACT_DTB_SIZE = 0x3c9
100
Simon Glass2c6adba2019-07-20 12:23:47 -0600101# Properties expected to be in the device tree when update_dtb is used
102BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
103
Simon Glassfb30e292019-07-20 12:23:51 -0600104# Extra properties expected to be in the device tree when allow-repack is used
105REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
106
Simon Glass57454f42016-11-25 20:15:52 -0700107
108class TestFunctional(unittest.TestCase):
109 """Functional tests for binman
110
111 Most of these use a sample .dts file to build an image and then check
112 that it looks correct. The sample files are in the test/ subdirectory
113 and are numbered.
114
115 For each entry type a very small test file is created using fixed
116 string contents. This makes it easy to test that things look right, and
117 debug problems.
118
119 In some cases a 'real' file must be used - these are also supplied in
120 the test/ diurectory.
121 """
122 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600123 def setUpClass(cls):
Simon Glassb3393262017-11-12 21:52:20 -0700124 global entry
Simon Glassc585dd42020-04-17 18:09:03 -0600125 from binman import entry
Simon Glassb3393262017-11-12 21:52:20 -0700126
Simon Glass57454f42016-11-25 20:15:52 -0700127 # Handle the case where argv[0] is 'python'
Simon Glass862f8e22019-08-24 07:22:43 -0600128 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
129 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
Simon Glass57454f42016-11-25 20:15:52 -0700130
131 # Create a temporary directory for input files
Simon Glass862f8e22019-08-24 07:22:43 -0600132 cls._indir = tempfile.mkdtemp(prefix='binmant.')
Simon Glass57454f42016-11-25 20:15:52 -0700133
134 # Create some test files
135 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
136 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
137 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glass8425a1f2018-07-17 13:25:48 -0600138 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700139 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glass72232452016-11-25 20:15:53 -0700140 TestFunctional._MakeInputFile('me.bin', ME_DATA)
141 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glass862f8e22019-08-24 07:22:43 -0600142 cls._ResetDtbs()
Simon Glass0b074d62019-08-24 07:22:48 -0600143
Jagdish Gediya311d4842018-09-03 21:35:08 +0530144 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glass0b074d62019-08-24 07:22:48 -0600145
Simon Glassabab18c2019-08-24 07:22:49 -0600146 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
147 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
Simon Glasse83679d2017-11-12 21:52:26 -0700148 X86_START16_SPL_DATA)
Simon Glassabab18c2019-08-24 07:22:49 -0600149 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
Simon Glassed40e962018-09-14 04:57:10 -0600150 X86_START16_TPL_DATA)
Simon Glass0b074d62019-08-24 07:22:48 -0600151
152 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
153 X86_RESET16_DATA)
154 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
155 X86_RESET16_SPL_DATA)
156 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
157 X86_RESET16_TPL_DATA)
158
Simon Glass57454f42016-11-25 20:15:52 -0700159 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass3d274232017-11-12 21:52:27 -0700160 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
161 U_BOOT_SPL_NODTB_DATA)
Simon Glass3fb4f422018-09-14 04:57:32 -0600162 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
163 U_BOOT_TPL_NODTB_DATA)
Simon Glassb4176d42016-11-25 20:15:56 -0700164 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
165 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Mengd7bcdf52017-08-15 22:41:54 -0700166 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassa409c932017-11-12 21:52:28 -0700167 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassdb168d42018-07-17 13:25:39 -0600168 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600169 TestFunctional._MakeInputDir('devkeys')
170 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass41902e42018-10-01 12:22:31 -0600171 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glassba7985d2019-08-24 07:23:07 -0600172 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
Simon Glass4d9086d2019-10-20 21:31:35 -0600173 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
Simon Glass9ea87b22019-10-20 21:31:36 -0600174 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700175
Simon Glassf6290892019-08-24 07:22:53 -0600176 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
177 elf_test.BuildElfTestFiles(cls._elf_testdir)
178
Simon Glass72232452016-11-25 20:15:53 -0700179 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glass4affd4b2019-08-24 07:22:54 -0600180 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -0700181 tools.read_file(cls.ElfTestFile('u_boot_ucode_ptr')))
Simon Glass72232452016-11-25 20:15:53 -0700182
183 # Intel flash descriptor file
Simon Glasse88cef92020-07-09 18:39:41 -0600184 cls._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -0700185
Simon Glass862f8e22019-08-24 07:22:43 -0600186 shutil.copytree(cls.TestFile('files'),
187 os.path.join(cls._indir, 'files'))
Simon Glassac6328c2018-09-14 04:57:28 -0600188
Simon Glass7ba33592018-09-14 04:57:26 -0600189 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
Simon Glassd92c8362020-10-26 17:40:25 -0600190 TestFunctional._MakeInputFile('compress_big', COMPRESS_DATA_BIG)
Simon Glass559c4de2020-09-01 05:13:58 -0600191 TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
Roger Quadros5cdcea02022-02-19 20:50:04 +0200192 TestFunctional._MakeInputFile('tee-pager.bin', TEE_OS_DATA)
Simon Glass3efb2972021-11-23 21:08:59 -0700193 TestFunctional._MakeInputFile('bl2u.bin', ATF_BL2U_DATA)
Bin Mengc0b15742021-05-10 20:23:33 +0800194 TestFunctional._MakeInputFile('fw_dynamic.bin', OPENSBI_DATA)
Samuel Holland9d8cc632020-10-21 21:12:15 -0500195 TestFunctional._MakeInputFile('scp.bin', SCP_DATA)
Simon Glass7ba33592018-09-14 04:57:26 -0600196
Simon Glassa435cd12020-09-01 05:13:59 -0600197 # Add a few .dtb files for testing
198 TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR,
199 TEST_FDT1_DATA)
200 TestFunctional._MakeInputFile('%s/test-fdt2.dtb' % TEST_FDT_SUBDIR,
201 TEST_FDT2_DATA)
202
Simon Glassa0729502020-09-06 10:35:33 -0600203 TestFunctional._MakeInputFile('env.txt', ENV_DATA)
204
Simon Glass5f423422022-03-05 20:19:12 -0700205 # ELF file with two sections in different parts of memory, used for both
206 # ATF and OP_TEE
207 TestFunctional._MakeInputFile('bl31.elf',
208 tools.read_file(cls.ElfTestFile('elf_sections')))
209 TestFunctional._MakeInputFile('tee.elf',
210 tools.read_file(cls.ElfTestFile('elf_sections')))
211
Simon Glass9203c162022-01-09 20:14:06 -0700212 cls.have_lz4 = comp_util.HAVE_LZ4
Simon Glass1de34482019-07-08 13:18:53 -0600213
Simon Glass57454f42016-11-25 20:15:52 -0700214 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600215 def tearDownClass(cls):
Simon Glass57454f42016-11-25 20:15:52 -0700216 """Remove the temporary input directory and its contents"""
Simon Glass862f8e22019-08-24 07:22:43 -0600217 if cls.preserve_indir:
218 print('Preserving input dir: %s' % cls._indir)
Simon Glass1c420c92019-07-08 13:18:49 -0600219 else:
Simon Glass862f8e22019-08-24 07:22:43 -0600220 if cls._indir:
221 shutil.rmtree(cls._indir)
222 cls._indir = None
Simon Glass57454f42016-11-25 20:15:52 -0700223
Simon Glass1c420c92019-07-08 13:18:49 -0600224 @classmethod
Simon Glasscebfab22019-07-08 13:18:50 -0600225 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
Simon Glassf46732a2019-07-08 14:25:29 -0600226 toolpath=None, verbosity=None):
Simon Glass1c420c92019-07-08 13:18:49 -0600227 """Accept arguments controlling test execution
228
229 Args:
230 preserve_indir: Preserve the shared input directory used by all
231 tests in this class.
232 preserve_outdir: Preserve the output directories used by tests. Each
233 test has its own, so this is normally only useful when running a
234 single test.
Simon Glasscebfab22019-07-08 13:18:50 -0600235 toolpath: ist of paths to use for tools
Simon Glass1c420c92019-07-08 13:18:49 -0600236 """
237 cls.preserve_indir = preserve_indir
238 cls.preserve_outdirs = preserve_outdirs
Simon Glasscebfab22019-07-08 13:18:50 -0600239 cls.toolpath = toolpath
Simon Glassf46732a2019-07-08 14:25:29 -0600240 cls.verbosity = verbosity
Simon Glass1c420c92019-07-08 13:18:49 -0600241
Simon Glass1de34482019-07-08 13:18:53 -0600242 def _CheckLz4(self):
243 if not self.have_lz4:
244 self.skipTest('lz4 --no-frame-crc not available')
245
Simon Glassee9d10d2019-07-20 12:24:09 -0600246 def _CleanupOutputDir(self):
247 """Remove the temporary output directory"""
248 if self.preserve_outdirs:
249 print('Preserving output dir: %s' % tools.outdir)
250 else:
Simon Glass80025522022-01-29 14:14:04 -0700251 tools._finalise_for_test()
Simon Glassee9d10d2019-07-20 12:24:09 -0600252
Simon Glass57454f42016-11-25 20:15:52 -0700253 def setUp(self):
254 # Enable this to turn on debugging output
Simon Glass011f1b32022-01-29 14:14:15 -0700255 # tout.init(tout.DEBUG)
Simon Glass57454f42016-11-25 20:15:52 -0700256 command.test_result = None
257
258 def tearDown(self):
259 """Remove the temporary output directory"""
Simon Glassee9d10d2019-07-20 12:24:09 -0600260 self._CleanupOutputDir()
Simon Glass57454f42016-11-25 20:15:52 -0700261
Simon Glassb3d6fc72019-07-20 12:24:10 -0600262 def _SetupImageInTmpdir(self):
263 """Set up the output image in a new temporary directory
264
265 This is used when an image has been generated in the output directory,
266 but we want to run binman again. This will create a new output
267 directory and fail to delete the original one.
268
269 This creates a new temporary directory, copies the image to it (with a
270 new name) and removes the old output directory.
271
272 Returns:
273 Tuple:
274 Temporary directory to use
275 New image filename
276 """
Simon Glass80025522022-01-29 14:14:04 -0700277 image_fname = tools.get_output_filename('image.bin')
Simon Glassb3d6fc72019-07-20 12:24:10 -0600278 tmpdir = tempfile.mkdtemp(prefix='binman.')
279 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
Simon Glass80025522022-01-29 14:14:04 -0700280 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassb3d6fc72019-07-20 12:24:10 -0600281 self._CleanupOutputDir()
282 return tmpdir, updated_fname
283
Simon Glass8425a1f2018-07-17 13:25:48 -0600284 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600285 def _ResetDtbs(cls):
Simon Glass8425a1f2018-07-17 13:25:48 -0600286 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
287 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
288 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
289
Simon Glass57454f42016-11-25 20:15:52 -0700290 def _RunBinman(self, *args, **kwargs):
291 """Run binman using the command line
292
293 Args:
294 Arguments to pass, as a list of strings
295 kwargs: Arguments to pass to Command.RunPipe()
296 """
Simon Glass840be732022-01-29 14:14:05 -0700297 result = command.run_pipe([[self._binman_pathname] + list(args)],
Simon Glass57454f42016-11-25 20:15:52 -0700298 capture=True, capture_stderr=True, raise_on_error=False)
299 if result.return_code and kwargs.get('raise_on_error', True):
300 raise Exception("Error running '%s': %s" % (' '.join(args),
301 result.stdout + result.stderr))
302 return result
303
Simon Glassf46732a2019-07-08 14:25:29 -0600304 def _DoBinman(self, *argv):
Simon Glass57454f42016-11-25 20:15:52 -0700305 """Run binman using directly (in the same process)
306
307 Args:
308 Arguments to pass, as a list of strings
309 Returns:
310 Return value (0 for success)
311 """
Simon Glassf46732a2019-07-08 14:25:29 -0600312 argv = list(argv)
313 args = cmdline.ParseArgs(argv)
314 args.pager = 'binman-invalid-pager'
315 args.build_dir = self._indir
Simon Glass57454f42016-11-25 20:15:52 -0700316
317 # For testing, you can force an increase in verbosity here
Simon Glassf46732a2019-07-08 14:25:29 -0600318 # args.verbosity = tout.DEBUG
319 return control.Binman(args)
Simon Glass57454f42016-11-25 20:15:52 -0700320
Simon Glass91710b32018-07-17 13:25:32 -0600321 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glassb4595d82019-04-25 21:58:34 -0600322 entry_args=None, images=None, use_real_dtb=False,
Simon Glassed930672021-03-18 20:25:05 +1300323 use_expanded=False, verbosity=None, allow_missing=False,
Heiko Thiery6d451362022-01-06 11:49:41 +0100324 allow_fake_blobs=False, extra_indirs=None, threads=None,
Simon Glass66152ce2022-01-09 20:14:09 -0700325 test_section_timeout=False, update_fdt_in_elf=None,
326 force_missing_bintools=''):
Simon Glass57454f42016-11-25 20:15:52 -0700327 """Run binman with a given test file
328
329 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600330 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600331 debug: True to enable debugging output
Simon Glass30732662018-06-01 09:38:20 -0600332 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600333 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600334 tree before packing it into the image
Simon Glass3b376c32018-09-14 04:57:12 -0600335 entry_args: Dict of entry args to supply to binman
336 key: arg name
337 value: value of that arg
338 images: List of image names to build
Simon Glass31ee50f2020-09-01 05:13:55 -0600339 use_real_dtb: True to use the test file as the contents of
340 the u-boot-dtb entry. Normally this is not needed and the
341 test contents (the U_BOOT_DTB_DATA string) can be used.
342 But in some test we need the real contents.
Simon Glassed930672021-03-18 20:25:05 +1300343 use_expanded: True to use expanded entries where available, e.g.
344 'u-boot-expanded' instead of 'u-boot'
Simon Glass31ee50f2020-09-01 05:13:55 -0600345 verbosity: Verbosity level to use (0-3, None=don't set it)
346 allow_missing: Set the '--allow-missing' flag so that missing
347 external binaries just produce a warning instead of an error
Heiko Thiery6d451362022-01-06 11:49:41 +0100348 allow_fake_blobs: Set the '--fake-ext-blobs' flag
Simon Glassa435cd12020-09-01 05:13:59 -0600349 extra_indirs: Extra input directories to add using -I
Simon Glass76f496d2021-07-06 10:36:37 -0600350 threads: Number of threads to use (None for default, 0 for
351 single-threaded)
Simon Glass9a798402021-11-03 21:09:17 -0600352 test_section_timeout: True to force the first time to timeout, as
353 used in testThreadTimeout()
Simon Glassadfb8492021-11-03 21:09:18 -0600354 update_fdt_in_elf: Value to pass with --update-fdt-in-elf=xxx
Simon Glass66152ce2022-01-09 20:14:09 -0700355 force_missing_tools (str): comma-separated list of bintools to
356 regard as missing
Simon Glass9a798402021-11-03 21:09:17 -0600357
358 Returns:
359 int return code, 0 on success
Simon Glass57454f42016-11-25 20:15:52 -0700360 """
Simon Glassf46732a2019-07-08 14:25:29 -0600361 args = []
Simon Glass075a45c2017-11-13 18:55:00 -0700362 if debug:
363 args.append('-D')
Simon Glassf46732a2019-07-08 14:25:29 -0600364 if verbosity is not None:
365 args.append('-v%d' % verbosity)
366 elif self.verbosity:
367 args.append('-v%d' % self.verbosity)
368 if self.toolpath:
369 for path in self.toolpath:
370 args += ['--toolpath', path]
Simon Glass76f496d2021-07-06 10:36:37 -0600371 if threads is not None:
372 args.append('-T%d' % threads)
373 if test_section_timeout:
374 args.append('--test-section-timeout')
Simon Glassf46732a2019-07-08 14:25:29 -0600375 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass30732662018-06-01 09:38:20 -0600376 if map:
377 args.append('-m')
Simon Glassa87014e2018-07-06 10:27:42 -0600378 if update_dtb:
Simon Glass38a411c2019-07-08 13:18:47 -0600379 args.append('-u')
Simon Glass31402012018-09-14 04:57:23 -0600380 if not use_real_dtb:
381 args.append('--fake-dtb')
Simon Glassed930672021-03-18 20:25:05 +1300382 if not use_expanded:
383 args.append('--no-expanded')
Simon Glass91710b32018-07-17 13:25:32 -0600384 if entry_args:
Simon Glass5f3645b2019-05-14 15:53:41 -0600385 for arg, value in entry_args.items():
Simon Glass91710b32018-07-17 13:25:32 -0600386 args.append('-a%s=%s' % (arg, value))
Simon Glass5d94cc62020-07-09 18:39:38 -0600387 if allow_missing:
388 args.append('-M')
Heiko Thiery6d451362022-01-06 11:49:41 +0100389 if allow_fake_blobs:
390 args.append('--fake-ext-blobs')
Simon Glass66152ce2022-01-09 20:14:09 -0700391 if force_missing_bintools:
392 args += ['--force-missing-bintools', force_missing_bintools]
Simon Glassadfb8492021-11-03 21:09:18 -0600393 if update_fdt_in_elf:
394 args += ['--update-fdt-in-elf', update_fdt_in_elf]
Simon Glass3b376c32018-09-14 04:57:12 -0600395 if images:
396 for image in images:
397 args += ['-i', image]
Simon Glassa435cd12020-09-01 05:13:59 -0600398 if extra_indirs:
399 for indir in extra_indirs:
400 args += ['-I', indir]
Simon Glass075a45c2017-11-13 18:55:00 -0700401 return self._DoBinman(*args)
Simon Glass57454f42016-11-25 20:15:52 -0700402
403 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glass72232452016-11-25 20:15:53 -0700404 """Set up a new test device-tree file
405
406 The given file is compiled and set up as the device tree to be used
407 for ths test.
408
409 Args:
410 fname: Filename of .dts file to read
Simon Glass1e324002018-06-01 09:38:19 -0600411 outfile: Output filename for compiled device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700412
413 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600414 Contents of device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700415 """
Simon Glassb8d2daa2019-07-20 12:23:49 -0600416 tmpdir = tempfile.mkdtemp(prefix='binmant.')
417 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
Simon Glass33486662019-05-14 15:53:42 -0600418 with open(dtb, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700419 data = fd.read()
420 TestFunctional._MakeInputFile(outfile, data)
Simon Glassb8d2daa2019-07-20 12:23:49 -0600421 shutil.rmtree(tmpdir)
Simon Glass752e7552018-10-01 21:12:41 -0600422 return data
Simon Glass57454f42016-11-25 20:15:52 -0700423
Simon Glasse219aa42018-09-14 04:57:24 -0600424 def _GetDtbContentsForSplTpl(self, dtb_data, name):
425 """Create a version of the main DTB for SPL or SPL
426
427 For testing we don't actually have different versions of the DTB. With
428 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
429 we don't normally have any unwanted nodes.
430
431 We still want the DTBs for SPL and TPL to be different though, since
432 otherwise it is confusing to know which one we are looking at. So add
433 an 'spl' or 'tpl' property to the top-level node.
Simon Glass31ee50f2020-09-01 05:13:55 -0600434
435 Args:
436 dtb_data: dtb data to modify (this should be a value devicetree)
437 name: Name of a new property to add
438
439 Returns:
440 New dtb data with the property added
Simon Glasse219aa42018-09-14 04:57:24 -0600441 """
442 dtb = fdt.Fdt.FromData(dtb_data)
443 dtb.Scan()
444 dtb.GetNode('/binman').AddZeroProp(name)
445 dtb.Sync(auto_resize=True)
446 dtb.Pack()
447 return dtb.GetContents()
448
Simon Glassed930672021-03-18 20:25:05 +1300449 def _DoReadFileDtb(self, fname, use_real_dtb=False, use_expanded=False,
450 map=False, update_dtb=False, entry_args=None,
Simon Glass76f496d2021-07-06 10:36:37 -0600451 reset_dtbs=True, extra_indirs=None, threads=None):
Simon Glass57454f42016-11-25 20:15:52 -0700452 """Run binman and return the resulting image
453
454 This runs binman with a given test file and then reads the resulting
455 output file. It is a shortcut function since most tests need to do
456 these steps.
457
458 Raises an assertion failure if binman returns a non-zero exit code.
459
460 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600461 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass57454f42016-11-25 20:15:52 -0700462 use_real_dtb: True to use the test file as the contents of
463 the u-boot-dtb entry. Normally this is not needed and the
464 test contents (the U_BOOT_DTB_DATA string) can be used.
465 But in some test we need the real contents.
Simon Glassed930672021-03-18 20:25:05 +1300466 use_expanded: True to use expanded entries where available, e.g.
467 'u-boot-expanded' instead of 'u-boot'
Simon Glass30732662018-06-01 09:38:20 -0600468 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600469 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600470 tree before packing it into the image
Simon Glass31ee50f2020-09-01 05:13:55 -0600471 entry_args: Dict of entry args to supply to binman
472 key: arg name
473 value: value of that arg
474 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
475 function. If reset_dtbs is True, then the original test dtb
476 is written back before this function finishes
Simon Glassa435cd12020-09-01 05:13:59 -0600477 extra_indirs: Extra input directories to add using -I
Simon Glass76f496d2021-07-06 10:36:37 -0600478 threads: Number of threads to use (None for default, 0 for
479 single-threaded)
Simon Glass72232452016-11-25 20:15:53 -0700480
481 Returns:
482 Tuple:
483 Resulting image contents
484 Device tree contents
Simon Glass30732662018-06-01 09:38:20 -0600485 Map data showing contents of image (or None if none)
Simon Glassdef77b52018-07-17 13:25:27 -0600486 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass57454f42016-11-25 20:15:52 -0700487 """
Simon Glass72232452016-11-25 20:15:53 -0700488 dtb_data = None
Simon Glass57454f42016-11-25 20:15:52 -0700489 # Use the compiled test file as the u-boot-dtb input
490 if use_real_dtb:
Simon Glass72232452016-11-25 20:15:53 -0700491 dtb_data = self._SetupDtb(fname)
Simon Glasse219aa42018-09-14 04:57:24 -0600492
493 # For testing purposes, make a copy of the DT for SPL and TPL. Add
494 # a node indicating which it is, so aid verification.
495 for name in ['spl', 'tpl']:
496 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
497 outfile = os.path.join(self._indir, dtb_fname)
498 TestFunctional._MakeInputFile(dtb_fname,
499 self._GetDtbContentsForSplTpl(dtb_data, name))
Simon Glass57454f42016-11-25 20:15:52 -0700500
501 try:
Simon Glass91710b32018-07-17 13:25:32 -0600502 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glassa435cd12020-09-01 05:13:59 -0600503 entry_args=entry_args, use_real_dtb=use_real_dtb,
Simon Glass76f496d2021-07-06 10:36:37 -0600504 use_expanded=use_expanded, extra_indirs=extra_indirs,
505 threads=threads)
Simon Glass57454f42016-11-25 20:15:52 -0700506 self.assertEqual(0, retcode)
Simon Glass80025522022-01-29 14:14:04 -0700507 out_dtb_fname = tools.get_output_filename('u-boot.dtb.out')
Simon Glass57454f42016-11-25 20:15:52 -0700508
509 # Find the (only) image, read it and return its contents
510 image = control.images['image']
Simon Glass80025522022-01-29 14:14:04 -0700511 image_fname = tools.get_output_filename('image.bin')
Simon Glassa87014e2018-07-06 10:27:42 -0600512 self.assertTrue(os.path.exists(image_fname))
Simon Glass30732662018-06-01 09:38:20 -0600513 if map:
Simon Glass80025522022-01-29 14:14:04 -0700514 map_fname = tools.get_output_filename('image.map')
Simon Glass30732662018-06-01 09:38:20 -0600515 with open(map_fname) as fd:
516 map_data = fd.read()
517 else:
518 map_data = None
Simon Glass33486662019-05-14 15:53:42 -0600519 with open(image_fname, 'rb') as fd:
Simon Glassa87014e2018-07-06 10:27:42 -0600520 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass57454f42016-11-25 20:15:52 -0700521 finally:
522 # Put the test file back
Simon Glasse219aa42018-09-14 04:57:24 -0600523 if reset_dtbs and use_real_dtb:
Simon Glass8425a1f2018-07-17 13:25:48 -0600524 self._ResetDtbs()
Simon Glass57454f42016-11-25 20:15:52 -0700525
Simon Glass5b4bce32019-07-08 14:25:26 -0600526 def _DoReadFileRealDtb(self, fname):
527 """Run binman with a real .dtb file and return the resulting data
528
529 Args:
530 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
531
532 Returns:
533 Resulting image contents
534 """
535 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
536
Simon Glass72232452016-11-25 20:15:53 -0700537 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass1e324002018-06-01 09:38:19 -0600538 """Helper function which discards the device-tree binary
539
540 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600541 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600542 use_real_dtb: True to use the test file as the contents of
543 the u-boot-dtb entry. Normally this is not needed and the
544 test contents (the U_BOOT_DTB_DATA string) can be used.
545 But in some test we need the real contents.
Simon Glassdef77b52018-07-17 13:25:27 -0600546
547 Returns:
548 Resulting image contents
Simon Glass1e324002018-06-01 09:38:19 -0600549 """
Simon Glass72232452016-11-25 20:15:53 -0700550 return self._DoReadFileDtb(fname, use_real_dtb)[0]
551
Simon Glass57454f42016-11-25 20:15:52 -0700552 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600553 def _MakeInputFile(cls, fname, contents):
Simon Glass57454f42016-11-25 20:15:52 -0700554 """Create a new test input file, creating directories as needed
555
556 Args:
Simon Glasse8561af2018-08-01 15:22:37 -0600557 fname: Filename to create
Simon Glass57454f42016-11-25 20:15:52 -0700558 contents: File contents to write in to the file
559 Returns:
560 Full pathname of file created
561 """
Simon Glass862f8e22019-08-24 07:22:43 -0600562 pathname = os.path.join(cls._indir, fname)
Simon Glass57454f42016-11-25 20:15:52 -0700563 dirname = os.path.dirname(pathname)
564 if dirname and not os.path.exists(dirname):
565 os.makedirs(dirname)
566 with open(pathname, 'wb') as fd:
567 fd.write(contents)
568 return pathname
569
570 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600571 def _MakeInputDir(cls, dirname):
Simon Glassc1ae83c2018-07-17 13:25:44 -0600572 """Create a new test input directory, creating directories as needed
573
574 Args:
575 dirname: Directory name to create
576
577 Returns:
578 Full pathname of directory created
579 """
Simon Glass862f8e22019-08-24 07:22:43 -0600580 pathname = os.path.join(cls._indir, dirname)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600581 if not os.path.exists(pathname):
582 os.makedirs(pathname)
583 return pathname
584
585 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600586 def _SetupSplElf(cls, src_fname='bss_data'):
Simon Glass7057d022018-10-01 21:12:47 -0600587 """Set up an ELF file with a '_dt_ucode_base_size' symbol
588
589 Args:
590 Filename of ELF file to use as SPL
591 """
Simon Glass93a806f2019-08-24 07:22:59 -0600592 TestFunctional._MakeInputFile('spl/u-boot-spl',
Simon Glass80025522022-01-29 14:14:04 -0700593 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass7057d022018-10-01 21:12:47 -0600594
595 @classmethod
Simon Glass3eb5b202019-08-24 07:23:00 -0600596 def _SetupTplElf(cls, src_fname='bss_data'):
597 """Set up an ELF file with a '_dt_ucode_base_size' symbol
598
599 Args:
600 Filename of ELF file to use as TPL
601 """
602 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
Simon Glass80025522022-01-29 14:14:04 -0700603 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass3eb5b202019-08-24 07:23:00 -0600604
605 @classmethod
Simon Glasse88cef92020-07-09 18:39:41 -0600606 def _SetupDescriptor(cls):
607 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
608 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
609
610 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600611 def TestFile(cls, fname):
612 return os.path.join(cls._binman_dir, 'test', fname)
Simon Glass57454f42016-11-25 20:15:52 -0700613
Simon Glassf6290892019-08-24 07:22:53 -0600614 @classmethod
615 def ElfTestFile(cls, fname):
616 return os.path.join(cls._elf_testdir, fname)
617
Simon Glass57454f42016-11-25 20:15:52 -0700618 def AssertInList(self, grep_list, target):
619 """Assert that at least one of a list of things is in a target
620
621 Args:
622 grep_list: List of strings to check
623 target: Target string
624 """
625 for grep in grep_list:
626 if grep in target:
627 return
Simon Glass848cdb52019-05-17 22:00:50 -0600628 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass57454f42016-11-25 20:15:52 -0700629
630 def CheckNoGaps(self, entries):
631 """Check that all entries fit together without gaps
632
633 Args:
634 entries: List of entries to check
635 """
Simon Glasse8561af2018-08-01 15:22:37 -0600636 offset = 0
Simon Glass57454f42016-11-25 20:15:52 -0700637 for entry in entries.values():
Simon Glasse8561af2018-08-01 15:22:37 -0600638 self.assertEqual(offset, entry.offset)
639 offset += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700640
Simon Glass72232452016-11-25 20:15:53 -0700641 def GetFdtLen(self, dtb):
Simon Glass1e324002018-06-01 09:38:19 -0600642 """Get the totalsize field from a device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700643
644 Args:
Simon Glass1e324002018-06-01 09:38:19 -0600645 dtb: Device-tree binary contents
Simon Glass72232452016-11-25 20:15:53 -0700646
647 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600648 Total size of device-tree binary, from the header
Simon Glass72232452016-11-25 20:15:53 -0700649 """
650 return struct.unpack('>L', dtb[4:8])[0]
651
Simon Glass0f621332019-07-08 14:25:27 -0600652 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glassa87014e2018-07-06 10:27:42 -0600653 def AddNode(node, path):
654 if node.name != '/':
655 path += '/' + node.name
Simon Glass0f621332019-07-08 14:25:27 -0600656 for prop in node.props.values():
657 if prop.name in prop_names:
658 prop_path = path + ':' + prop.name
659 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
660 prop.value)
Simon Glassa87014e2018-07-06 10:27:42 -0600661 for subnode in node.subnodes:
Simon Glassa87014e2018-07-06 10:27:42 -0600662 AddNode(subnode, path)
663
664 tree = {}
Simon Glassa87014e2018-07-06 10:27:42 -0600665 AddNode(dtb.GetRoot(), '')
666 return tree
667
Simon Glass57454f42016-11-25 20:15:52 -0700668 def testRun(self):
669 """Test a basic run with valid args"""
670 result = self._RunBinman('-h')
671
672 def testFullHelp(self):
673 """Test that the full help is displayed with -H"""
674 result = self._RunBinman('-H')
Simon Glass75ead662021-03-18 20:25:13 +1300675 help_file = os.path.join(self._binman_dir, 'README.rst')
Tom Rinic3c0b6d2018-01-16 15:29:50 -0500676 # Remove possible extraneous strings
677 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
678 gothelp = result.stdout.replace(extra, '')
679 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass57454f42016-11-25 20:15:52 -0700680 self.assertEqual(0, len(result.stderr))
681 self.assertEqual(0, result.return_code)
682
683 def testFullHelpInternal(self):
684 """Test that the full help is displayed with -H"""
685 try:
686 command.test_result = command.CommandResult()
687 result = self._DoBinman('-H')
Simon Glass75ead662021-03-18 20:25:13 +1300688 help_file = os.path.join(self._binman_dir, 'README.rst')
Simon Glass57454f42016-11-25 20:15:52 -0700689 finally:
690 command.test_result = None
691
692 def testHelp(self):
693 """Test that the basic help is displayed with -h"""
694 result = self._RunBinman('-h')
695 self.assertTrue(len(result.stdout) > 200)
696 self.assertEqual(0, len(result.stderr))
697 self.assertEqual(0, result.return_code)
698
Simon Glass57454f42016-11-25 20:15:52 -0700699 def testBoard(self):
700 """Test that we can run it with a specific board"""
Simon Glass511f6582018-10-01 12:22:30 -0600701 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass57454f42016-11-25 20:15:52 -0700702 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glassed930672021-03-18 20:25:05 +1300703 result = self._DoBinman('build', '-n', '-b', 'sandbox')
Simon Glass57454f42016-11-25 20:15:52 -0700704 self.assertEqual(0, result)
705
706 def testNeedBoard(self):
707 """Test that we get an error when no board ius supplied"""
708 with self.assertRaises(ValueError) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600709 result = self._DoBinman('build')
Simon Glass57454f42016-11-25 20:15:52 -0700710 self.assertIn("Must provide a board to process (use -b <board>)",
711 str(e.exception))
712
713 def testMissingDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600714 """Test that an invalid device-tree file generates an error"""
Simon Glass57454f42016-11-25 20:15:52 -0700715 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600716 self._RunBinman('build', '-d', 'missing_file')
Simon Glass57454f42016-11-25 20:15:52 -0700717 # We get one error from libfdt, and a different one from fdtget.
718 self.AssertInList(["Couldn't open blob from 'missing_file'",
719 'No such file or directory'], str(e.exception))
720
721 def testBrokenDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600722 """Test that an invalid device-tree source file generates an error
Simon Glass57454f42016-11-25 20:15:52 -0700723
724 Since this is a source file it should be compiled and the error
725 will come from the device-tree compiler (dtc).
726 """
727 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600728 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700729 self.assertIn("FATAL ERROR: Unable to parse input tree",
730 str(e.exception))
731
732 def testMissingNode(self):
733 """Test that a device tree without a 'binman' node generates an error"""
734 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600735 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700736 self.assertIn("does not have a 'binman' node", str(e.exception))
737
738 def testEmpty(self):
739 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glassf46732a2019-07-08 14:25:29 -0600740 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700741 self.assertEqual(0, len(result.stderr))
742 self.assertEqual(0, result.return_code)
743
744 def testInvalidEntry(self):
745 """Test that an invalid entry is flagged"""
746 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600747 result = self._RunBinman('build', '-d',
Simon Glass511f6582018-10-01 12:22:30 -0600748 self.TestFile('004_invalid_entry.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700749 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
750 "'/binman/not-a-valid-type'", str(e.exception))
751
752 def testSimple(self):
753 """Test a simple binman with a single file"""
Simon Glass511f6582018-10-01 12:22:30 -0600754 data = self._DoReadFile('005_simple.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700755 self.assertEqual(U_BOOT_DATA, data)
756
Simon Glass075a45c2017-11-13 18:55:00 -0700757 def testSimpleDebug(self):
758 """Test a simple binman run with debugging enabled"""
Simon Glass52d06212019-07-08 14:25:53 -0600759 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass075a45c2017-11-13 18:55:00 -0700760
Simon Glass57454f42016-11-25 20:15:52 -0700761 def testDual(self):
762 """Test that we can handle creating two images
763
764 This also tests image padding.
765 """
Simon Glass511f6582018-10-01 12:22:30 -0600766 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700767 self.assertEqual(0, retcode)
768
769 image = control.images['image1']
Simon Glass39dd2152019-07-08 14:25:47 -0600770 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glass80025522022-01-29 14:14:04 -0700771 fname = tools.get_output_filename('image1.bin')
Simon Glass57454f42016-11-25 20:15:52 -0700772 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600773 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700774 data = fd.read()
775 self.assertEqual(U_BOOT_DATA, data)
776
777 image = control.images['image2']
Simon Glass39dd2152019-07-08 14:25:47 -0600778 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glass80025522022-01-29 14:14:04 -0700779 fname = tools.get_output_filename('image2.bin')
Simon Glass57454f42016-11-25 20:15:52 -0700780 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600781 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700782 data = fd.read()
783 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glass80025522022-01-29 14:14:04 -0700784 self.assertEqual(tools.get_bytes(0, 3), data[:3])
785 self.assertEqual(tools.get_bytes(0, 5), data[7:])
Simon Glass57454f42016-11-25 20:15:52 -0700786
787 def testBadAlign(self):
788 """Test that an invalid alignment value is detected"""
789 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600790 self._DoTestFile('007_bad_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700791 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
792 "of two", str(e.exception))
793
794 def testPackSimple(self):
795 """Test that packing works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -0600796 retcode = self._DoTestFile('008_pack.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700797 self.assertEqual(0, retcode)
798 self.assertIn('image', control.images)
799 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600800 entries = image.GetEntries()
Simon Glass57454f42016-11-25 20:15:52 -0700801 self.assertEqual(5, len(entries))
802
803 # First u-boot
804 self.assertIn('u-boot', entries)
805 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600806 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700807 self.assertEqual(len(U_BOOT_DATA), entry.size)
808
809 # Second u-boot, aligned to 16-byte boundary
810 self.assertIn('u-boot-align', entries)
811 entry = entries['u-boot-align']
Simon Glasse8561af2018-08-01 15:22:37 -0600812 self.assertEqual(16, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700813 self.assertEqual(len(U_BOOT_DATA), entry.size)
814
815 # Third u-boot, size 23 bytes
816 self.assertIn('u-boot-size', entries)
817 entry = entries['u-boot-size']
Simon Glasse8561af2018-08-01 15:22:37 -0600818 self.assertEqual(20, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700819 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
820 self.assertEqual(23, entry.size)
821
822 # Fourth u-boot, placed immediate after the above
823 self.assertIn('u-boot-next', entries)
824 entry = entries['u-boot-next']
Simon Glasse8561af2018-08-01 15:22:37 -0600825 self.assertEqual(43, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700826 self.assertEqual(len(U_BOOT_DATA), entry.size)
827
Simon Glasse8561af2018-08-01 15:22:37 -0600828 # Fifth u-boot, placed at a fixed offset
Simon Glass57454f42016-11-25 20:15:52 -0700829 self.assertIn('u-boot-fixed', entries)
830 entry = entries['u-boot-fixed']
Simon Glasse8561af2018-08-01 15:22:37 -0600831 self.assertEqual(61, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700832 self.assertEqual(len(U_BOOT_DATA), entry.size)
833
Simon Glass39dd2152019-07-08 14:25:47 -0600834 self.assertEqual(65, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700835
836 def testPackExtra(self):
837 """Test that extra packing feature works as expected"""
Simon Glassafb9caa2020-10-26 17:40:10 -0600838 data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
839 update_dtb=True)
Simon Glass57454f42016-11-25 20:15:52 -0700840
Simon Glass57454f42016-11-25 20:15:52 -0700841 self.assertIn('image', control.images)
842 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600843 entries = image.GetEntries()
Simon Glass57454f42016-11-25 20:15:52 -0700844 self.assertEqual(5, len(entries))
845
846 # First u-boot with padding before and after
847 self.assertIn('u-boot', entries)
848 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600849 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700850 self.assertEqual(3, entry.pad_before)
851 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600852 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glass80025522022-01-29 14:14:04 -0700853 self.assertEqual(tools.get_bytes(0, 3) + U_BOOT_DATA +
854 tools.get_bytes(0, 5), data[:entry.size])
Simon Glass187202f2020-10-26 17:40:08 -0600855 pos = entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700856
857 # Second u-boot has an aligned size, but it has no effect
858 self.assertIn('u-boot-align-size-nop', entries)
859 entry = entries['u-boot-align-size-nop']
Simon Glass187202f2020-10-26 17:40:08 -0600860 self.assertEqual(pos, entry.offset)
861 self.assertEqual(len(U_BOOT_DATA), entry.size)
862 self.assertEqual(U_BOOT_DATA, entry.data)
863 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
864 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700865
866 # Third u-boot has an aligned size too
867 self.assertIn('u-boot-align-size', entries)
868 entry = entries['u-boot-align-size']
Simon Glass187202f2020-10-26 17:40:08 -0600869 self.assertEqual(pos, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700870 self.assertEqual(32, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600871 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glass80025522022-01-29 14:14:04 -0700872 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600873 data[pos:pos + entry.size])
874 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700875
876 # Fourth u-boot has an aligned end
877 self.assertIn('u-boot-align-end', entries)
878 entry = entries['u-boot-align-end']
Simon Glasse8561af2018-08-01 15:22:37 -0600879 self.assertEqual(48, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700880 self.assertEqual(16, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600881 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glass80025522022-01-29 14:14:04 -0700882 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 16 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600883 data[pos:pos + entry.size])
884 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700885
886 # Fifth u-boot immediately afterwards
887 self.assertIn('u-boot-align-both', entries)
888 entry = entries['u-boot-align-both']
Simon Glasse8561af2018-08-01 15:22:37 -0600889 self.assertEqual(64, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700890 self.assertEqual(64, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600891 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glass80025522022-01-29 14:14:04 -0700892 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 64 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600893 data[pos:pos + entry.size])
Simon Glass57454f42016-11-25 20:15:52 -0700894
895 self.CheckNoGaps(entries)
Simon Glass39dd2152019-07-08 14:25:47 -0600896 self.assertEqual(128, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700897
Simon Glassafb9caa2020-10-26 17:40:10 -0600898 dtb = fdt.Fdt(out_dtb_fname)
899 dtb.Scan()
900 props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
901 expected = {
902 'image-pos': 0,
903 'offset': 0,
904 'size': 128,
905
906 'u-boot:image-pos': 0,
907 'u-boot:offset': 0,
908 'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
909
910 'u-boot-align-size-nop:image-pos': 12,
911 'u-boot-align-size-nop:offset': 12,
912 'u-boot-align-size-nop:size': 4,
913
914 'u-boot-align-size:image-pos': 16,
915 'u-boot-align-size:offset': 16,
916 'u-boot-align-size:size': 32,
917
918 'u-boot-align-end:image-pos': 48,
919 'u-boot-align-end:offset': 48,
920 'u-boot-align-end:size': 16,
921
922 'u-boot-align-both:image-pos': 64,
923 'u-boot-align-both:offset': 64,
924 'u-boot-align-both:size': 64,
925 }
926 self.assertEqual(expected, props)
927
Simon Glass57454f42016-11-25 20:15:52 -0700928 def testPackAlignPowerOf2(self):
929 """Test that invalid entry alignment is detected"""
930 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600931 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700932 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
933 "of two", str(e.exception))
934
935 def testPackAlignSizePowerOf2(self):
936 """Test that invalid entry size alignment is detected"""
937 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600938 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700939 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
940 "power of two", str(e.exception))
941
942 def testPackInvalidAlign(self):
Simon Glasse8561af2018-08-01 15:22:37 -0600943 """Test detection of an offset that does not match its alignment"""
Simon Glass57454f42016-11-25 20:15:52 -0700944 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600945 self._DoTestFile('012_pack_inv_align.dts')
Simon Glasse8561af2018-08-01 15:22:37 -0600946 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass57454f42016-11-25 20:15:52 -0700947 "align 0x4 (4)", str(e.exception))
948
949 def testPackInvalidSizeAlign(self):
950 """Test that invalid entry size alignment is detected"""
951 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600952 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700953 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
954 "align-size 0x4 (4)", str(e.exception))
955
956 def testPackOverlap(self):
957 """Test that overlapping regions are detected"""
958 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600959 self._DoTestFile('014_pack_overlap.dts')
Simon Glasse8561af2018-08-01 15:22:37 -0600960 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -0700961 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
962 str(e.exception))
963
964 def testPackEntryOverflow(self):
965 """Test that entries that overflow their size are detected"""
966 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600967 self._DoTestFile('015_pack_overflow.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700968 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
969 "but entry size is 0x3 (3)", str(e.exception))
970
971 def testPackImageOverflow(self):
972 """Test that entries which overflow the image size are detected"""
973 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600974 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glasseca32212018-06-01 09:38:12 -0600975 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass57454f42016-11-25 20:15:52 -0700976 "size 0x3 (3)", str(e.exception))
977
978 def testPackImageSize(self):
979 """Test that the image size can be set"""
Simon Glass511f6582018-10-01 12:22:30 -0600980 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700981 self.assertEqual(0, retcode)
982 self.assertIn('image', control.images)
983 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -0600984 self.assertEqual(7, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700985
986 def testPackImageSizeAlign(self):
987 """Test that image size alignemnt works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -0600988 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700989 self.assertEqual(0, retcode)
990 self.assertIn('image', control.images)
991 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -0600992 self.assertEqual(16, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700993
994 def testPackInvalidImageAlign(self):
995 """Test that invalid image alignment is detected"""
996 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600997 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glasseca32212018-06-01 09:38:12 -0600998 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass57454f42016-11-25 20:15:52 -0700999 "align-size 0x8 (8)", str(e.exception))
1000
Simon Glass2a0fa982022-02-11 13:23:21 -07001001 def testPackAlignPowerOf2Inv(self):
Simon Glass57454f42016-11-25 20:15:52 -07001002 """Test that invalid image alignment is detected"""
1003 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001004 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001005 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass57454f42016-11-25 20:15:52 -07001006 "two", str(e.exception))
1007
1008 def testImagePadByte(self):
1009 """Test that the image pad byte can be specified"""
Simon Glass7057d022018-10-01 21:12:47 -06001010 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001011 data = self._DoReadFile('021_image_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07001012 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0xff, 1) +
Simon Glassac0d4952019-05-14 15:53:47 -06001013 U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -07001014
1015 def testImageName(self):
1016 """Test that image files can be named"""
Simon Glass511f6582018-10-01 12:22:30 -06001017 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001018 self.assertEqual(0, retcode)
1019 image = control.images['image1']
Simon Glass80025522022-01-29 14:14:04 -07001020 fname = tools.get_output_filename('test-name')
Simon Glass57454f42016-11-25 20:15:52 -07001021 self.assertTrue(os.path.exists(fname))
1022
1023 image = control.images['image2']
Simon Glass80025522022-01-29 14:14:04 -07001024 fname = tools.get_output_filename('test-name.xx')
Simon Glass57454f42016-11-25 20:15:52 -07001025 self.assertTrue(os.path.exists(fname))
1026
1027 def testBlobFilename(self):
1028 """Test that generic blobs can be provided by filename"""
Simon Glass511f6582018-10-01 12:22:30 -06001029 data = self._DoReadFile('023_blob.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001030 self.assertEqual(BLOB_DATA, data)
1031
1032 def testPackSorted(self):
1033 """Test that entries can be sorted"""
Simon Glass7057d022018-10-01 21:12:47 -06001034 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001035 data = self._DoReadFile('024_sorted.dts')
Simon Glass80025522022-01-29 14:14:04 -07001036 self.assertEqual(tools.get_bytes(0, 1) + U_BOOT_SPL_DATA +
1037 tools.get_bytes(0, 2) + U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -07001038
Simon Glasse8561af2018-08-01 15:22:37 -06001039 def testPackZeroOffset(self):
1040 """Test that an entry at offset 0 is not given a new offset"""
Simon Glass57454f42016-11-25 20:15:52 -07001041 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001042 self._DoTestFile('025_pack_zero_size.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001043 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -07001044 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1045 str(e.exception))
1046
1047 def testPackUbootDtb(self):
1048 """Test that a device tree can be added to U-Boot"""
Simon Glass511f6582018-10-01 12:22:30 -06001049 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001050 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glass72232452016-11-25 20:15:53 -07001051
1052 def testPackX86RomNoSize(self):
1053 """Test that the end-at-4gb property requires a size property"""
1054 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001055 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001056 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glass72232452016-11-25 20:15:53 -07001057 "using end-at-4gb", str(e.exception))
1058
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301059 def test4gbAndSkipAtStartTogether(self):
1060 """Test that the end-at-4gb and skip-at-size property can't be used
1061 together"""
1062 with self.assertRaises(ValueError) as e:
Simon Glass11f2bd02019-08-24 07:23:02 -06001063 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001064 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301065 "'skip-at-start'", str(e.exception))
1066
Simon Glass72232452016-11-25 20:15:53 -07001067 def testPackX86RomOutside(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001068 """Test that the end-at-4gb property checks for offset boundaries"""
Simon Glass72232452016-11-25 20:15:53 -07001069 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001070 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glassd6179862020-10-26 17:40:05 -06001071 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
1072 "is outside the section '/binman' starting at "
1073 '0xffffffe0 (4294967264) of size 0x20 (32)',
Simon Glass72232452016-11-25 20:15:53 -07001074 str(e.exception))
1075
1076 def testPackX86Rom(self):
1077 """Test that a basic x86 ROM can be created"""
Simon Glass7057d022018-10-01 21:12:47 -06001078 self._SetupSplElf()
Simon Glass1d167762019-08-24 07:23:01 -06001079 data = self._DoReadFile('029_x86_rom.dts')
Simon Glass80025522022-01-29 14:14:04 -07001080 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 3) + U_BOOT_SPL_DATA +
1081 tools.get_bytes(0, 2), data)
Simon Glass72232452016-11-25 20:15:53 -07001082
1083 def testPackX86RomMeNoDesc(self):
1084 """Test that an invalid Intel descriptor entry is detected"""
Simon Glasse88cef92020-07-09 18:39:41 -06001085 try:
Simon Glass14c596c2020-07-25 15:11:19 -06001086 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
Simon Glasse88cef92020-07-09 18:39:41 -06001087 with self.assertRaises(ValueError) as e:
Simon Glass14c596c2020-07-25 15:11:19 -06001088 self._DoTestFile('163_x86_rom_me_empty.dts')
Simon Glasse88cef92020-07-09 18:39:41 -06001089 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1090 str(e.exception))
1091 finally:
1092 self._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -07001093
1094 def testPackX86RomBadDesc(self):
1095 """Test that the Intel requires a descriptor entry"""
1096 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06001097 self._DoTestFile('030_x86_rom_me_no_desc.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001098 self.assertIn("Node '/binman/intel-me': No offset set with "
1099 "offset-unset: should another entry provide this correct "
1100 "offset?", str(e.exception))
Simon Glass72232452016-11-25 20:15:53 -07001101
1102 def testPackX86RomMe(self):
1103 """Test that an x86 ROM with an ME region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001104 data = self._DoReadFile('031_x86_rom_me.dts')
Simon Glass80025522022-01-29 14:14:04 -07001105 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glass759af872019-07-08 13:18:54 -06001106 if data[:0x1000] != expected_desc:
1107 self.fail('Expected descriptor binary at start of image')
Simon Glass72232452016-11-25 20:15:53 -07001108 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1109
1110 def testPackVga(self):
1111 """Test that an image with a VGA binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001112 data = self._DoReadFile('032_intel_vga.dts')
Simon Glass72232452016-11-25 20:15:53 -07001113 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1114
1115 def testPackStart16(self):
1116 """Test that an image with an x86 start16 region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001117 data = self._DoReadFile('033_x86_start16.dts')
Simon Glass72232452016-11-25 20:15:53 -07001118 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1119
Jagdish Gediya311d4842018-09-03 21:35:08 +05301120 def testPackPowerpcMpc85xxBootpgResetvec(self):
1121 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1122 created"""
Simon Glass11f2bd02019-08-24 07:23:02 -06001123 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
Jagdish Gediya311d4842018-09-03 21:35:08 +05301124 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1125
Simon Glass6ba679c2018-07-06 10:27:17 -06001126 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glass820af1d2018-07-06 10:27:16 -06001127 """Handle running a test for insertion of microcode
1128
1129 Args:
1130 dts_fname: Name of test .dts file
1131 nodtb_data: Data that we expect in the first section
Simon Glass6ba679c2018-07-06 10:27:17 -06001132 ucode_second: True if the microsecond entry is second instead of
1133 third
Simon Glass820af1d2018-07-06 10:27:16 -06001134
1135 Returns:
1136 Tuple:
1137 Contents of first region (U-Boot or SPL)
Simon Glasse8561af2018-08-01 15:22:37 -06001138 Offset and size components of microcode pointer, as inserted
Simon Glass820af1d2018-07-06 10:27:16 -06001139 in the above (two 4-byte words)
1140 """
Simon Glass3d274232017-11-12 21:52:27 -07001141 data = self._DoReadFile(dts_fname, True)
Simon Glass72232452016-11-25 20:15:53 -07001142
1143 # Now check the device tree has no microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001144 if ucode_second:
1145 ucode_content = data[len(nodtb_data):]
1146 ucode_pos = len(nodtb_data)
1147 dtb_with_ucode = ucode_content[16:]
1148 fdt_len = self.GetFdtLen(dtb_with_ucode)
1149 else:
1150 dtb_with_ucode = data[len(nodtb_data):]
1151 fdt_len = self.GetFdtLen(dtb_with_ucode)
1152 ucode_content = dtb_with_ucode[fdt_len:]
1153 ucode_pos = len(nodtb_data) + fdt_len
Simon Glass80025522022-01-29 14:14:04 -07001154 fname = tools.get_output_filename('test.dtb')
Simon Glass72232452016-11-25 20:15:53 -07001155 with open(fname, 'wb') as fd:
Simon Glass820af1d2018-07-06 10:27:16 -06001156 fd.write(dtb_with_ucode)
Simon Glass22c92ca2017-05-27 07:38:29 -06001157 dtb = fdt.FdtScan(fname)
1158 ucode = dtb.GetNode('/microcode')
Simon Glass72232452016-11-25 20:15:53 -07001159 self.assertTrue(ucode)
1160 for node in ucode.subnodes:
1161 self.assertFalse(node.props.get('data'))
1162
Simon Glass72232452016-11-25 20:15:53 -07001163 # Check that the microcode appears immediately after the Fdt
1164 # This matches the concatenation of the data properties in
Simon Glasse83679d2017-11-12 21:52:26 -07001165 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glass72232452016-11-25 20:15:53 -07001166 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1167 0x78235609)
Simon Glass820af1d2018-07-06 10:27:16 -06001168 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glass72232452016-11-25 20:15:53 -07001169
1170 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001171 # expected offset and size
Simon Glass72232452016-11-25 20:15:53 -07001172 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1173 len(ucode_data))
Simon Glass6ba679c2018-07-06 10:27:17 -06001174 u_boot = data[:len(nodtb_data)]
1175 return u_boot, pos_and_size
Simon Glass3d274232017-11-12 21:52:27 -07001176
1177 def testPackUbootMicrocode(self):
1178 """Test that x86 microcode can be handled correctly
1179
1180 We expect to see the following in the image, in order:
1181 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1182 place
1183 u-boot.dtb with the microcode removed
1184 the microcode
1185 """
Simon Glass511f6582018-10-01 12:22:30 -06001186 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass3d274232017-11-12 21:52:27 -07001187 U_BOOT_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06001188 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1189 b' somewhere in here', first)
Simon Glass72232452016-11-25 20:15:53 -07001190
Simon Glassbac25c82017-05-27 07:38:26 -06001191 def _RunPackUbootSingleMicrocode(self):
Simon Glass72232452016-11-25 20:15:53 -07001192 """Test that x86 microcode can be handled correctly
1193
1194 We expect to see the following in the image, in order:
1195 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1196 place
1197 u-boot.dtb with the microcode
1198 an empty microcode region
1199 """
1200 # We need the libfdt library to run this test since only that allows
1201 # finding the offset of a property. This is required by
1202 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass511f6582018-10-01 12:22:30 -06001203 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glass72232452016-11-25 20:15:53 -07001204
1205 second = data[len(U_BOOT_NODTB_DATA):]
1206
1207 fdt_len = self.GetFdtLen(second)
1208 third = second[fdt_len:]
1209 second = second[:fdt_len]
1210
Simon Glassbac25c82017-05-27 07:38:26 -06001211 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1212 self.assertIn(ucode_data, second)
1213 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glass72232452016-11-25 20:15:53 -07001214
Simon Glassbac25c82017-05-27 07:38:26 -06001215 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001216 # expected offset and size
Simon Glassbac25c82017-05-27 07:38:26 -06001217 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1218 len(ucode_data))
1219 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glass303f62f2019-05-17 22:00:46 -06001220 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1221 b' somewhere in here', first)
Simon Glass996021e2016-11-25 20:15:54 -07001222
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001223 def testPackUbootSingleMicrocode(self):
1224 """Test that x86 microcode can be handled correctly with fdt_normal.
1225 """
Simon Glassbac25c82017-05-27 07:38:26 -06001226 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001227
Simon Glass996021e2016-11-25 20:15:54 -07001228 def testUBootImg(self):
1229 """Test that u-boot.img can be put in a file"""
Simon Glass511f6582018-10-01 12:22:30 -06001230 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glass996021e2016-11-25 20:15:54 -07001231 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001232
1233 def testNoMicrocode(self):
1234 """Test that a missing microcode region is detected"""
1235 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001236 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001237 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1238 "node found in ", str(e.exception))
1239
1240 def testMicrocodeWithoutNode(self):
1241 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1242 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001243 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001244 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1245 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1246
1247 def testMicrocodeWithoutNode2(self):
1248 """Test that a missing u-boot-ucode node is detected"""
1249 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001250 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001251 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1252 "microcode region u-boot-ucode", str(e.exception))
1253
1254 def testMicrocodeWithoutPtrInElf(self):
1255 """Test that a U-Boot binary without the microcode symbol is detected"""
1256 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001257 try:
Simon Glassfaaaa162019-08-24 07:22:55 -06001258 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001259 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001260
1261 with self.assertRaises(ValueError) as e:
Simon Glassbac25c82017-05-27 07:38:26 -06001262 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001263 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1264 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1265
1266 finally:
1267 # Put the original file back
Simon Glass4affd4b2019-08-24 07:22:54 -06001268 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001269 tools.read_file(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001270
1271 def testMicrocodeNotInImage(self):
1272 """Test that microcode must be placed within the image"""
1273 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001274 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001275 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1276 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glassad5a7712018-06-01 09:38:14 -06001277 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001278
1279 def testWithoutMicrocode(self):
1280 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glassfaaaa162019-08-24 07:22:55 -06001281 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001282 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass511f6582018-10-01 12:22:30 -06001283 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001284
1285 # Now check the device tree has no microcode
1286 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1287 second = data[len(U_BOOT_NODTB_DATA):]
1288
1289 fdt_len = self.GetFdtLen(second)
1290 self.assertEqual(dtb, second[:fdt_len])
1291
1292 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1293 third = data[used_len:]
Simon Glass80025522022-01-29 14:14:04 -07001294 self.assertEqual(tools.get_bytes(0, 0x200 - used_len), third)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001295
1296 def testUnknownPosSize(self):
1297 """Test that microcode must be placed within the image"""
1298 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001299 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glasse8561af2018-08-01 15:22:37 -06001300 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001301 "entry 'invalid-entry'", str(e.exception))
Simon Glassb4176d42016-11-25 20:15:56 -07001302
1303 def testPackFsp(self):
1304 """Test that an image with a FSP binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001305 data = self._DoReadFile('042_intel_fsp.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001306 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1307
1308 def testPackCmc(self):
Bin Mengd7bcdf52017-08-15 22:41:54 -07001309 """Test that an image with a CMC binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001310 data = self._DoReadFile('043_intel_cmc.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001311 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Mengd7bcdf52017-08-15 22:41:54 -07001312
1313 def testPackVbt(self):
1314 """Test that an image with a VBT binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001315 data = self._DoReadFile('046_intel_vbt.dts')
Bin Mengd7bcdf52017-08-15 22:41:54 -07001316 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glassac599912017-11-12 21:52:22 -07001317
Simon Glass7f94e832017-11-12 21:52:25 -07001318 def testSplBssPad(self):
1319 """Test that we can pad SPL's BSS with zeros"""
Simon Glass3d274232017-11-12 21:52:27 -07001320 # ELF file with a '__bss_size' symbol
Simon Glass7057d022018-10-01 21:12:47 -06001321 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001322 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07001323 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glassac0d4952019-05-14 15:53:47 -06001324 data)
Simon Glass7f94e832017-11-12 21:52:25 -07001325
Simon Glass04cda032018-10-01 21:12:42 -06001326 def testSplBssPadMissing(self):
1327 """Test that a missing symbol is detected"""
Simon Glass7057d022018-10-01 21:12:47 -06001328 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass24ad3652017-11-13 18:54:54 -07001329 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001330 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass24ad3652017-11-13 18:54:54 -07001331 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1332 str(e.exception))
1333
Simon Glasse83679d2017-11-12 21:52:26 -07001334 def testPackStart16Spl(self):
Simon Glassed40e962018-09-14 04:57:10 -06001335 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001336 data = self._DoReadFile('048_x86_start16_spl.dts')
Simon Glasse83679d2017-11-12 21:52:26 -07001337 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1338
Simon Glass6ba679c2018-07-06 10:27:17 -06001339 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1340 """Helper function for microcode tests
Simon Glass3d274232017-11-12 21:52:27 -07001341
1342 We expect to see the following in the image, in order:
1343 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1344 correct place
1345 u-boot.dtb with the microcode removed
1346 the microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001347
1348 Args:
1349 dts: Device tree file to use for test
1350 ucode_second: True if the microsecond entry is second instead of
1351 third
Simon Glass3d274232017-11-12 21:52:27 -07001352 """
Simon Glass7057d022018-10-01 21:12:47 -06001353 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass6ba679c2018-07-06 10:27:17 -06001354 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1355 ucode_second=ucode_second)
Simon Glass303f62f2019-05-17 22:00:46 -06001356 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1357 b'ter somewhere in here', first)
Simon Glass3d274232017-11-12 21:52:27 -07001358
Simon Glass6ba679c2018-07-06 10:27:17 -06001359 def testPackUbootSplMicrocode(self):
1360 """Test that x86 microcode can be handled correctly in SPL"""
Simon Glass511f6582018-10-01 12:22:30 -06001361 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass6ba679c2018-07-06 10:27:17 -06001362
1363 def testPackUbootSplMicrocodeReorder(self):
1364 """Test that order doesn't matter for microcode entries
1365
1366 This is the same as testPackUbootSplMicrocode but when we process the
1367 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1368 entry, so we reply on binman to try later.
1369 """
Simon Glass511f6582018-10-01 12:22:30 -06001370 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass6ba679c2018-07-06 10:27:17 -06001371 ucode_second=True)
1372
Simon Glassa409c932017-11-12 21:52:28 -07001373 def testPackMrc(self):
1374 """Test that an image with an MRC binary can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001375 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassa409c932017-11-12 21:52:28 -07001376 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1377
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001378 def testSplDtb(self):
1379 """Test that an image with spl/u-boot-spl.dtb can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001380 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001381 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1382
Simon Glass0a6da312017-11-13 18:54:56 -07001383 def testSplNoDtb(self):
1384 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12001385 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001386 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass0a6da312017-11-13 18:54:56 -07001387 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1388
Simon Glass7098b7f2021-03-21 18:24:30 +13001389 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
1390 use_expanded=False):
Simon Glass31e04cb2021-03-18 20:24:56 +13001391 """Check the image contains the expected symbol values
1392
1393 Args:
1394 dts: Device tree file to use for test
1395 base_data: Data before and after 'u-boot' section
1396 u_boot_offset: Offset of 'u-boot' section in image
Simon Glass7098b7f2021-03-21 18:24:30 +13001397 entry_args: Dict of entry args to supply to binman
1398 key: arg name
1399 value: value of that arg
1400 use_expanded: True to use expanded entries where available, e.g.
1401 'u-boot-expanded' instead of 'u-boot'
Simon Glass31e04cb2021-03-18 20:24:56 +13001402 """
Simon Glass5d0c0262019-08-24 07:22:56 -06001403 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass4ca8e042017-11-13 18:55:01 -07001404 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1405 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Simon Glass31e04cb2021-03-18 20:24:56 +13001406 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
1407 addr)
Simon Glass4ca8e042017-11-13 18:55:01 -07001408
Simon Glass7057d022018-10-01 21:12:47 -06001409 self._SetupSplElf('u_boot_binman_syms')
Simon Glass7098b7f2021-03-21 18:24:30 +13001410 data = self._DoReadFileDtb(dts, entry_args=entry_args,
1411 use_expanded=use_expanded)[0]
Simon Glass31e04cb2021-03-18 20:24:56 +13001412 # The image should contain the symbols from u_boot_binman_syms.c
1413 # Note that image_pos is adjusted by the base address of the image,
1414 # which is 0x10 in our test image
1415 sym_values = struct.pack('<LQLL', 0x00,
1416 u_boot_offset + len(U_BOOT_DATA),
1417 0x10 + u_boot_offset, 0x04)
1418 expected = (sym_values + base_data[20:] +
Simon Glass80025522022-01-29 14:14:04 -07001419 tools.get_bytes(0xff, 1) + U_BOOT_DATA + sym_values +
Simon Glass31e04cb2021-03-18 20:24:56 +13001420 base_data[20:])
Simon Glass4ca8e042017-11-13 18:55:01 -07001421 self.assertEqual(expected, data)
1422
Simon Glass31e04cb2021-03-18 20:24:56 +13001423 def testSymbols(self):
1424 """Test binman can assign symbols embedded in U-Boot"""
1425 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x18)
1426
1427 def testSymbolsNoDtb(self):
1428 """Test binman can assign symbols embedded in U-Boot SPL"""
Simon Glass3bbc9932021-03-21 18:24:29 +13001429 self.checkSymbols('196_symbols_nodtb.dts',
Simon Glass31e04cb2021-03-18 20:24:56 +13001430 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1431 0x38)
1432
Simon Glasse76a3e62018-06-01 09:38:11 -06001433 def testPackUnitAddress(self):
1434 """Test that we support multiple binaries with the same name"""
Simon Glass511f6582018-10-01 12:22:30 -06001435 data = self._DoReadFile('054_unit_address.dts')
Simon Glasse76a3e62018-06-01 09:38:11 -06001436 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1437
Simon Glassa91e1152018-06-01 09:38:16 -06001438 def testSections(self):
1439 """Basic test of sections"""
Simon Glass511f6582018-10-01 12:22:30 -06001440 data = self._DoReadFile('055_sections.dts')
Simon Glass80025522022-01-29 14:14:04 -07001441 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1442 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
1443 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glassa91e1152018-06-01 09:38:16 -06001444 self.assertEqual(expected, data)
Simon Glassac599912017-11-12 21:52:22 -07001445
Simon Glass30732662018-06-01 09:38:20 -06001446 def testMap(self):
1447 """Tests outputting a map of the images"""
Simon Glass511f6582018-10-01 12:22:30 -06001448 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001449 self.assertEqual('''ImagePos Offset Size Name
145000000000 00000000 00000028 main-section
145100000000 00000000 00000010 section@0
145200000000 00000000 00000004 u-boot
145300000010 00000010 00000010 section@1
145400000010 00000000 00000004 u-boot
145500000020 00000020 00000004 section@2
145600000020 00000000 00000004 u-boot
Simon Glass30732662018-06-01 09:38:20 -06001457''', map_data)
1458
Simon Glass3b78d532018-06-01 09:38:21 -06001459 def testNamePrefix(self):
1460 """Tests that name prefixes are used"""
Simon Glass511f6582018-10-01 12:22:30 -06001461 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001462 self.assertEqual('''ImagePos Offset Size Name
146300000000 00000000 00000028 main-section
146400000000 00000000 00000010 section@0
146500000000 00000000 00000004 ro-u-boot
146600000010 00000010 00000010 section@1
146700000010 00000000 00000004 rw-u-boot
Simon Glass3b78d532018-06-01 09:38:21 -06001468''', map_data)
1469
Simon Glass6ba679c2018-07-06 10:27:17 -06001470 def testUnknownContents(self):
1471 """Test that obtaining the contents works as expected"""
1472 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001473 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass39dd2152019-07-08 14:25:47 -06001474 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glassc585dd42020-04-17 18:09:03 -06001475 "processing of contents: remaining ["
1476 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass6ba679c2018-07-06 10:27:17 -06001477
Simon Glass2e1169f2018-07-06 10:27:19 -06001478 def testBadChangeSize(self):
1479 """Test that trying to change the size of an entry fails"""
Simon Glasse61b6f62019-07-08 14:25:37 -06001480 try:
1481 state.SetAllowEntryExpansion(False)
1482 with self.assertRaises(ValueError) as e:
1483 self._DoReadFile('059_change_size.dts', True)
Simon Glass8c702fb2019-07-20 12:23:57 -06001484 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glasse61b6f62019-07-08 14:25:37 -06001485 str(e.exception))
1486 finally:
1487 state.SetAllowEntryExpansion(True)
Simon Glass2e1169f2018-07-06 10:27:19 -06001488
Simon Glassa87014e2018-07-06 10:27:42 -06001489 def testUpdateFdt(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001490 """Test that we can update the device tree with offset/size info"""
Simon Glass511f6582018-10-01 12:22:30 -06001491 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glassa87014e2018-07-06 10:27:42 -06001492 update_dtb=True)
Simon Glass5463a6a2018-07-17 13:25:52 -06001493 dtb = fdt.Fdt(out_dtb_fname)
1494 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06001495 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glassa87014e2018-07-06 10:27:42 -06001496 self.assertEqual({
Simon Glass9dcc8612018-08-01 15:22:42 -06001497 'image-pos': 0,
Simon Glass3a9a2b82018-07-17 13:25:28 -06001498 'offset': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001499 '_testing:offset': 32,
Simon Glass8c702fb2019-07-20 12:23:57 -06001500 '_testing:size': 2,
Simon Glass9dcc8612018-08-01 15:22:42 -06001501 '_testing:image-pos': 32,
Simon Glasse8561af2018-08-01 15:22:37 -06001502 'section@0/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001503 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001504 'section@0/u-boot:image-pos': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001505 'section@0:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001506 'section@0:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001507 'section@0:image-pos': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001508
Simon Glasse8561af2018-08-01 15:22:37 -06001509 'section@1/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001510 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001511 'section@1/u-boot:image-pos': 16,
Simon Glasse8561af2018-08-01 15:22:37 -06001512 'section@1:offset': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001513 'section@1:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001514 'section@1:image-pos': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001515 'size': 40
1516 }, props)
1517
1518 def testUpdateFdtBad(self):
1519 """Test that we detect when ProcessFdt never completes"""
1520 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001521 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glassa87014e2018-07-06 10:27:42 -06001522 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glassc585dd42020-04-17 18:09:03 -06001523 '[<binman.etype._testing.Entry__testing',
1524 str(e.exception))
Simon Glass2e1169f2018-07-06 10:27:19 -06001525
Simon Glass91710b32018-07-17 13:25:32 -06001526 def testEntryArgs(self):
1527 """Test passing arguments to entries from the command line"""
1528 entry_args = {
1529 'test-str-arg': 'test1',
1530 'test-int-arg': '456',
1531 }
Simon Glass511f6582018-10-01 12:22:30 -06001532 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001533 self.assertIn('image', control.images)
1534 entry = control.images['image'].GetEntries()['_testing']
1535 self.assertEqual('test0', entry.test_str_fdt)
1536 self.assertEqual('test1', entry.test_str_arg)
1537 self.assertEqual(123, entry.test_int_fdt)
1538 self.assertEqual(456, entry.test_int_arg)
1539
1540 def testEntryArgsMissing(self):
1541 """Test missing arguments and properties"""
1542 entry_args = {
1543 'test-int-arg': '456',
1544 }
Simon Glass511f6582018-10-01 12:22:30 -06001545 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001546 entry = control.images['image'].GetEntries()['_testing']
1547 self.assertEqual('test0', entry.test_str_fdt)
1548 self.assertEqual(None, entry.test_str_arg)
1549 self.assertEqual(None, entry.test_int_fdt)
1550 self.assertEqual(456, entry.test_int_arg)
1551
1552 def testEntryArgsRequired(self):
1553 """Test missing arguments and properties"""
1554 entry_args = {
1555 'test-int-arg': '456',
1556 }
1557 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001558 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass21db0ff2020-09-01 05:13:54 -06001559 self.assertIn("Node '/binman/_testing': "
1560 'Missing required properties/entry args: test-str-arg, '
1561 'test-int-fdt, test-int-arg',
Simon Glass91710b32018-07-17 13:25:32 -06001562 str(e.exception))
1563
1564 def testEntryArgsInvalidFormat(self):
1565 """Test that an invalid entry-argument format is detected"""
Simon Glassf46732a2019-07-08 14:25:29 -06001566 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1567 '-ano-value']
Simon Glass91710b32018-07-17 13:25:32 -06001568 with self.assertRaises(ValueError) as e:
1569 self._DoBinman(*args)
1570 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1571
1572 def testEntryArgsInvalidInteger(self):
1573 """Test that an invalid entry-argument integer is detected"""
1574 entry_args = {
1575 'test-int-arg': 'abc',
1576 }
1577 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001578 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001579 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1580 "'test-int-arg' (value 'abc') to integer",
1581 str(e.exception))
1582
1583 def testEntryArgsInvalidDatatype(self):
1584 """Test that an invalid entry-argument datatype is detected
1585
1586 This test could be written in entry_test.py except that it needs
1587 access to control.entry_args, which seems more than that module should
1588 be able to see.
1589 """
1590 entry_args = {
1591 'test-bad-datatype-arg': '12',
1592 }
1593 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001594 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass91710b32018-07-17 13:25:32 -06001595 entry_args=entry_args)
1596 self.assertIn('GetArg() internal error: Unknown data type ',
1597 str(e.exception))
1598
Simon Glass2ca52032018-07-17 13:25:33 -06001599 def testText(self):
1600 """Test for a text entry type"""
1601 entry_args = {
1602 'test-id': TEXT_DATA,
1603 'test-id2': TEXT_DATA2,
1604 'test-id3': TEXT_DATA3,
1605 }
Simon Glass511f6582018-10-01 12:22:30 -06001606 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glass2ca52032018-07-17 13:25:33 -06001607 entry_args=entry_args)
Simon Glass80025522022-01-29 14:14:04 -07001608 expected = (tools.to_bytes(TEXT_DATA) +
1609 tools.get_bytes(0, 8 - len(TEXT_DATA)) +
1610 tools.to_bytes(TEXT_DATA2) + tools.to_bytes(TEXT_DATA3) +
Simon Glass47f6a622019-07-08 13:18:40 -06001611 b'some text' + b'more text')
Simon Glass2ca52032018-07-17 13:25:33 -06001612 self.assertEqual(expected, data)
1613
Simon Glass969616c2018-07-17 13:25:36 -06001614 def testEntryDocs(self):
1615 """Test for creation of entry documentation"""
1616 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001617 control.WriteEntryDocs(control.GetEntryModules())
Simon Glass969616c2018-07-17 13:25:36 -06001618 self.assertTrue(len(stdout.getvalue()) > 0)
1619
1620 def testEntryDocsMissing(self):
1621 """Test handling of missing entry documentation"""
1622 with self.assertRaises(ValueError) as e:
1623 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001624 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glass969616c2018-07-17 13:25:36 -06001625 self.assertIn('Documentation is missing for modules: u_boot',
1626 str(e.exception))
1627
Simon Glass704784b2018-07-17 13:25:38 -06001628 def testFmap(self):
1629 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06001630 data = self._DoReadFile('067_fmap.dts')
Simon Glass704784b2018-07-17 13:25:38 -06001631 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass80025522022-01-29 14:14:04 -07001632 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1633 U_BOOT_DATA + tools.get_bytes(ord('a'), 12))
Simon Glass704784b2018-07-17 13:25:38 -06001634 self.assertEqual(expected, data[:32])
Simon Glass303f62f2019-05-17 22:00:46 -06001635 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass704784b2018-07-17 13:25:38 -06001636 self.assertEqual(1, fhdr.ver_major)
1637 self.assertEqual(0, fhdr.ver_minor)
1638 self.assertEqual(0, fhdr.base)
Simon Glassb1d414c2021-04-03 11:05:10 +13001639 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 5
Simon Glass82059c22021-04-03 11:05:09 +13001640 self.assertEqual(16 + 16 + expect_size, fhdr.image_size)
Simon Glass303f62f2019-05-17 22:00:46 -06001641 self.assertEqual(b'FMAP', fhdr.name)
Simon Glassb1d414c2021-04-03 11:05:10 +13001642 self.assertEqual(5, fhdr.nareas)
Simon Glass82059c22021-04-03 11:05:09 +13001643 fiter = iter(fentries)
Simon Glass704784b2018-07-17 13:25:38 -06001644
Simon Glass82059c22021-04-03 11:05:09 +13001645 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001646 self.assertEqual(b'SECTION0', fentry.name)
1647 self.assertEqual(0, fentry.offset)
1648 self.assertEqual(16, fentry.size)
1649 self.assertEqual(0, fentry.flags)
1650
1651 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001652 self.assertEqual(b'RO_U_BOOT', fentry.name)
1653 self.assertEqual(0, fentry.offset)
1654 self.assertEqual(4, fentry.size)
1655 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001656
Simon Glass82059c22021-04-03 11:05:09 +13001657 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001658 self.assertEqual(b'SECTION1', fentry.name)
1659 self.assertEqual(16, fentry.offset)
1660 self.assertEqual(16, fentry.size)
1661 self.assertEqual(0, fentry.flags)
1662
1663 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001664 self.assertEqual(b'RW_U_BOOT', fentry.name)
1665 self.assertEqual(16, fentry.offset)
1666 self.assertEqual(4, fentry.size)
1667 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001668
Simon Glass82059c22021-04-03 11:05:09 +13001669 fentry = next(fiter)
1670 self.assertEqual(b'FMAP', fentry.name)
1671 self.assertEqual(32, fentry.offset)
1672 self.assertEqual(expect_size, fentry.size)
1673 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001674
Simon Glassdb168d42018-07-17 13:25:39 -06001675 def testBlobNamedByArg(self):
1676 """Test we can add a blob with the filename coming from an entry arg"""
1677 entry_args = {
1678 'cros-ec-rw-path': 'ecrw.bin',
1679 }
Simon Glass21db0ff2020-09-01 05:13:54 -06001680 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassdb168d42018-07-17 13:25:39 -06001681
Simon Glass53f53992018-07-17 13:25:40 -06001682 def testFill(self):
1683 """Test for an fill entry type"""
Simon Glass511f6582018-10-01 12:22:30 -06001684 data = self._DoReadFile('069_fill.dts')
Simon Glass80025522022-01-29 14:14:04 -07001685 expected = tools.get_bytes(0xff, 8) + tools.get_bytes(0, 8)
Simon Glass53f53992018-07-17 13:25:40 -06001686 self.assertEqual(expected, data)
1687
1688 def testFillNoSize(self):
1689 """Test for an fill entry type with no size"""
1690 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001691 self._DoReadFile('070_fill_no_size.dts')
Simon Glass53f53992018-07-17 13:25:40 -06001692 self.assertIn("'fill' entry must have a size property",
1693 str(e.exception))
1694
Simon Glassc1ae83c2018-07-17 13:25:44 -06001695 def _HandleGbbCommand(self, pipe_list):
1696 """Fake calls to the futility utility"""
1697 if pipe_list[0][0] == 'futility':
1698 fname = pipe_list[0][-1]
1699 # Append our GBB data to the file, which will happen every time the
1700 # futility command is called.
Simon Glass33486662019-05-14 15:53:42 -06001701 with open(fname, 'ab') as fd:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001702 fd.write(GBB_DATA)
1703 return command.CommandResult()
1704
1705 def testGbb(self):
1706 """Test for the Chromium OS Google Binary Block"""
1707 command.test_result = self._HandleGbbCommand
1708 entry_args = {
1709 'keydir': 'devkeys',
1710 'bmpblk': 'bmpblk.bin',
1711 }
Simon Glass511f6582018-10-01 12:22:30 -06001712 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glassc1ae83c2018-07-17 13:25:44 -06001713
1714 # Since futility
Simon Glass80025522022-01-29 14:14:04 -07001715 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
1716 tools.get_bytes(0, 0x2180 - 16))
Simon Glassc1ae83c2018-07-17 13:25:44 -06001717 self.assertEqual(expected, data)
1718
1719 def testGbbTooSmall(self):
1720 """Test for the Chromium OS Google Binary Block being large enough"""
1721 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001722 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001723 self.assertIn("Node '/binman/gbb': GBB is too small",
1724 str(e.exception))
1725
1726 def testGbbNoSize(self):
1727 """Test for the Chromium OS Google Binary Block having a size"""
1728 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001729 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001730 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1731 str(e.exception))
1732
Simon Glass66152ce2022-01-09 20:14:09 -07001733 def testGbbMissing(self):
1734 """Test that binman still produces an image if futility is missing"""
1735 entry_args = {
1736 'keydir': 'devkeys',
1737 }
1738 with test_util.capture_sys_output() as (_, stderr):
1739 self._DoTestFile('071_gbb.dts', force_missing_bintools='futility',
1740 entry_args=entry_args)
1741 err = stderr.getvalue()
1742 self.assertRegex(err,
1743 "Image 'main-section'.*missing bintools.*: futility")
1744
Simon Glass5c350162018-07-17 13:25:47 -06001745 def _HandleVblockCommand(self, pipe_list):
Simon Glass220c6222021-01-06 21:35:17 -07001746 """Fake calls to the futility utility
1747
1748 The expected pipe is:
1749
1750 [('futility', 'vbutil_firmware', '--vblock',
1751 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1752 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1753 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1754 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1755
1756 This writes to the output file (here, 'vblock.vblock'). If
1757 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1758 of the input data (here, 'input.vblock').
1759 """
Simon Glass5c350162018-07-17 13:25:47 -06001760 if pipe_list[0][0] == 'futility':
1761 fname = pipe_list[0][3]
Simon Glass639505b2018-09-14 04:57:11 -06001762 with open(fname, 'wb') as fd:
Simon Glass220c6222021-01-06 21:35:17 -07001763 if self._hash_data:
1764 infile = pipe_list[0][11]
1765 m = hashlib.sha256()
Simon Glass80025522022-01-29 14:14:04 -07001766 data = tools.read_file(infile)
Simon Glass220c6222021-01-06 21:35:17 -07001767 m.update(data)
1768 fd.write(m.digest())
1769 else:
1770 fd.write(VBLOCK_DATA)
1771
Simon Glass5c350162018-07-17 13:25:47 -06001772 return command.CommandResult()
1773
1774 def testVblock(self):
1775 """Test for the Chromium OS Verified Boot Block"""
Simon Glass220c6222021-01-06 21:35:17 -07001776 self._hash_data = False
Simon Glass5c350162018-07-17 13:25:47 -06001777 command.test_result = self._HandleVblockCommand
1778 entry_args = {
1779 'keydir': 'devkeys',
1780 }
Simon Glass511f6582018-10-01 12:22:30 -06001781 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass5c350162018-07-17 13:25:47 -06001782 entry_args=entry_args)
1783 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1784 self.assertEqual(expected, data)
1785
1786 def testVblockNoContent(self):
1787 """Test we detect a vblock which has no content to sign"""
1788 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001789 self._DoReadFile('075_vblock_no_content.dts')
Simon Glasse1915782021-03-21 18:24:31 +13001790 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
Simon Glass5c350162018-07-17 13:25:47 -06001791 'property', str(e.exception))
1792
1793 def testVblockBadPhandle(self):
1794 """Test that we detect a vblock with an invalid phandle in contents"""
1795 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001796 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001797 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1798 '1000', str(e.exception))
1799
1800 def testVblockBadEntry(self):
1801 """Test that we detect an entry that points to a non-entry"""
1802 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001803 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001804 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1805 "'other'", str(e.exception))
1806
Simon Glass220c6222021-01-06 21:35:17 -07001807 def testVblockContent(self):
1808 """Test that the vblock signs the right data"""
1809 self._hash_data = True
1810 command.test_result = self._HandleVblockCommand
1811 entry_args = {
1812 'keydir': 'devkeys',
1813 }
1814 data = self._DoReadFileDtb(
1815 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1816 entry_args=entry_args)[0]
1817 hashlen = 32 # SHA256 hash is 32 bytes
1818 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1819 hashval = data[-hashlen:]
1820 dtb = data[len(U_BOOT_DATA):-hashlen]
1821
1822 expected_data = U_BOOT_DATA + dtb
1823
1824 # The hashval should be a hash of the dtb
1825 m = hashlib.sha256()
1826 m.update(expected_data)
1827 expected_hashval = m.digest()
1828 self.assertEqual(expected_hashval, hashval)
1829
Simon Glass66152ce2022-01-09 20:14:09 -07001830 def testVblockMissing(self):
1831 """Test that binman still produces an image if futility is missing"""
1832 entry_args = {
1833 'keydir': 'devkeys',
1834 }
1835 with test_util.capture_sys_output() as (_, stderr):
1836 self._DoTestFile('074_vblock.dts',
1837 force_missing_bintools='futility',
1838 entry_args=entry_args)
1839 err = stderr.getvalue()
1840 self.assertRegex(err,
1841 "Image 'main-section'.*missing bintools.*: futility")
1842
Simon Glass8425a1f2018-07-17 13:25:48 -06001843 def testTpl(self):
Simon Glass3eb5b202019-08-24 07:23:00 -06001844 """Test that an image with TPL and its device tree can be created"""
Simon Glass8425a1f2018-07-17 13:25:48 -06001845 # ELF file with a '__bss_size' symbol
Simon Glass3eb5b202019-08-24 07:23:00 -06001846 self._SetupTplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001847 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glass8425a1f2018-07-17 13:25:48 -06001848 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1849
Simon Glass24b97442018-07-17 13:25:51 -06001850 def testUsesPos(self):
1851 """Test that the 'pos' property cannot be used anymore"""
1852 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001853 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass24b97442018-07-17 13:25:51 -06001854 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1855 "'pos'", str(e.exception))
1856
Simon Glass274bf092018-09-14 04:57:08 -06001857 def testFillZero(self):
1858 """Test for an fill entry type with a size of 0"""
Simon Glass511f6582018-10-01 12:22:30 -06001859 data = self._DoReadFile('080_fill_empty.dts')
Simon Glass80025522022-01-29 14:14:04 -07001860 self.assertEqual(tools.get_bytes(0, 16), data)
Simon Glass274bf092018-09-14 04:57:08 -06001861
Simon Glass267de432018-09-14 04:57:09 -06001862 def testTextMissing(self):
1863 """Test for a text entry type where there is no text"""
1864 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001865 self._DoReadFileDtb('066_text.dts',)
Simon Glass267de432018-09-14 04:57:09 -06001866 self.assertIn("Node '/binman/text': No value provided for text label "
1867 "'test-id'", str(e.exception))
1868
Simon Glassed40e962018-09-14 04:57:10 -06001869 def testPackStart16Tpl(self):
1870 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001871 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glassed40e962018-09-14 04:57:10 -06001872 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1873
Simon Glass3b376c32018-09-14 04:57:12 -06001874 def testSelectImage(self):
1875 """Test that we can select which images to build"""
Simon Glassb4595d82019-04-25 21:58:34 -06001876 expected = 'Skipping images: image1'
1877
1878 # We should only get the expected message in verbose mode
Simon Glass8a50b4a2019-07-08 13:18:48 -06001879 for verbosity in (0, 2):
Simon Glassb4595d82019-04-25 21:58:34 -06001880 with test_util.capture_sys_output() as (stdout, stderr):
1881 retcode = self._DoTestFile('006_dual_image.dts',
1882 verbosity=verbosity,
1883 images=['image2'])
1884 self.assertEqual(0, retcode)
1885 if verbosity:
1886 self.assertIn(expected, stdout.getvalue())
1887 else:
1888 self.assertNotIn(expected, stdout.getvalue())
Simon Glass3b376c32018-09-14 04:57:12 -06001889
Simon Glass80025522022-01-29 14:14:04 -07001890 self.assertFalse(os.path.exists(tools.get_output_filename('image1.bin')))
1891 self.assertTrue(os.path.exists(tools.get_output_filename('image2.bin')))
Simon Glassb3d6fc72019-07-20 12:24:10 -06001892 self._CleanupOutputDir()
Simon Glass3b376c32018-09-14 04:57:12 -06001893
Simon Glasse219aa42018-09-14 04:57:24 -06001894 def testUpdateFdtAll(self):
1895 """Test that all device trees are updated with offset/size info"""
Simon Glass5b4bce32019-07-08 14:25:26 -06001896 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glasse219aa42018-09-14 04:57:24 -06001897
1898 base_expected = {
1899 'section:image-pos': 0,
1900 'u-boot-tpl-dtb:size': 513,
1901 'u-boot-spl-dtb:size': 513,
1902 'u-boot-spl-dtb:offset': 493,
1903 'image-pos': 0,
1904 'section/u-boot-dtb:image-pos': 0,
1905 'u-boot-spl-dtb:image-pos': 493,
1906 'section/u-boot-dtb:size': 493,
1907 'u-boot-tpl-dtb:image-pos': 1006,
1908 'section/u-boot-dtb:offset': 0,
1909 'section:size': 493,
1910 'offset': 0,
1911 'section:offset': 0,
1912 'u-boot-tpl-dtb:offset': 1006,
1913 'size': 1519
1914 }
1915
1916 # We expect three device-tree files in the output, one after the other.
1917 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1918 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1919 # main U-Boot tree. All three should have the same postions and offset.
1920 start = 0
1921 for item in ['', 'spl', 'tpl']:
1922 dtb = fdt.Fdt.FromData(data[start:])
1923 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06001924 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
1925 ['spl', 'tpl'])
Simon Glasse219aa42018-09-14 04:57:24 -06001926 expected = dict(base_expected)
1927 if item:
1928 expected[item] = 0
1929 self.assertEqual(expected, props)
1930 start += dtb._fdt_obj.totalsize()
1931
1932 def testUpdateFdtOutput(self):
1933 """Test that output DTB files are updated"""
1934 try:
Simon Glass511f6582018-10-01 12:22:30 -06001935 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glasse219aa42018-09-14 04:57:24 -06001936 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1937
1938 # Unfortunately, compiling a source file always results in a file
1939 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass511f6582018-10-01 12:22:30 -06001940 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glasse219aa42018-09-14 04:57:24 -06001941 # binman as a file called u-boot.dtb. To fix this, copy the file
1942 # over to the expected place.
Simon Glasse219aa42018-09-14 04:57:24 -06001943 start = 0
1944 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1945 'tpl/u-boot-tpl.dtb.out']:
1946 dtb = fdt.Fdt.FromData(data[start:])
1947 size = dtb._fdt_obj.totalsize()
Simon Glass80025522022-01-29 14:14:04 -07001948 pathname = tools.get_output_filename(os.path.split(fname)[1])
1949 outdata = tools.read_file(pathname)
Simon Glasse219aa42018-09-14 04:57:24 -06001950 name = os.path.split(fname)[0]
1951
1952 if name:
1953 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1954 else:
1955 orig_indata = dtb_data
1956 self.assertNotEqual(outdata, orig_indata,
1957 "Expected output file '%s' be updated" % pathname)
1958 self.assertEqual(outdata, data[start:start + size],
1959 "Expected output file '%s' to match output image" %
1960 pathname)
1961 start += size
1962 finally:
1963 self._ResetDtbs()
1964
Simon Glass7ba33592018-09-14 04:57:26 -06001965 def _decompress(self, data):
Simon Glassdd5c14ec2022-01-09 20:14:04 -07001966 return comp_util.decompress(data, 'lz4')
Simon Glass7ba33592018-09-14 04:57:26 -06001967
1968 def testCompress(self):
1969 """Test compression of blobs"""
Simon Glass1de34482019-07-08 13:18:53 -06001970 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06001971 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass7ba33592018-09-14 04:57:26 -06001972 use_real_dtb=True, update_dtb=True)
1973 dtb = fdt.Fdt(out_dtb_fname)
1974 dtb.Scan()
1975 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1976 orig = self._decompress(data)
1977 self.assertEquals(COMPRESS_DATA, orig)
Simon Glass789b34402020-10-26 17:40:15 -06001978
1979 # Do a sanity check on various fields
1980 image = control.images['image']
1981 entries = image.GetEntries()
1982 self.assertEqual(1, len(entries))
1983
1984 entry = entries['blob']
1985 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
1986 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
1987 orig = self._decompress(entry.data)
1988 self.assertEqual(orig, entry.uncomp_data)
1989
Simon Glass72eeff12020-10-26 17:40:16 -06001990 self.assertEqual(image.data, entry.data)
1991
Simon Glass7ba33592018-09-14 04:57:26 -06001992 expected = {
1993 'blob:uncomp-size': len(COMPRESS_DATA),
1994 'blob:size': len(data),
1995 'size': len(data),
1996 }
1997 self.assertEqual(expected, props)
1998
Simon Glassac6328c2018-09-14 04:57:28 -06001999 def testFiles(self):
2000 """Test bringing in multiple files"""
Simon Glass511f6582018-10-01 12:22:30 -06002001 data = self._DoReadFile('084_files.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002002 self.assertEqual(FILES_DATA, data)
2003
2004 def testFilesCompress(self):
2005 """Test bringing in multiple files and compressing them"""
Simon Glass1de34482019-07-08 13:18:53 -06002006 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06002007 data = self._DoReadFile('085_files_compress.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002008
2009 image = control.images['image']
2010 entries = image.GetEntries()
2011 files = entries['files']
Simon Glass39dd2152019-07-08 14:25:47 -06002012 entries = files._entries
Simon Glassac6328c2018-09-14 04:57:28 -06002013
Simon Glass303f62f2019-05-17 22:00:46 -06002014 orig = b''
Simon Glassac6328c2018-09-14 04:57:28 -06002015 for i in range(1, 3):
2016 key = '%d.dat' % i
2017 start = entries[key].image_pos
2018 len = entries[key].size
2019 chunk = data[start:start + len]
2020 orig += self._decompress(chunk)
2021
2022 self.assertEqual(FILES_DATA, orig)
2023
2024 def testFilesMissing(self):
2025 """Test missing files"""
2026 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002027 data = self._DoReadFile('086_files_none.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002028 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
2029 'no files', str(e.exception))
2030
2031 def testFilesNoPattern(self):
2032 """Test missing files"""
2033 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002034 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002035 self.assertIn("Node '/binman/files': Missing 'pattern' property",
2036 str(e.exception))
2037
Simon Glassdd156a42022-03-05 20:18:59 -07002038 def testExtendSize(self):
2039 """Test an extending entry"""
2040 data, _, map_data, _ = self._DoReadFileDtb('088_extend_size.dts',
Simon Glassfa79a812018-09-14 04:57:29 -06002041 map=True)
Simon Glass80025522022-01-29 14:14:04 -07002042 expect = (tools.get_bytes(ord('a'), 8) + U_BOOT_DATA +
2043 MRC_DATA + tools.get_bytes(ord('b'), 1) + U_BOOT_DATA +
2044 tools.get_bytes(ord('c'), 8) + U_BOOT_DATA +
2045 tools.get_bytes(ord('d'), 8))
Simon Glassfa79a812018-09-14 04:57:29 -06002046 self.assertEqual(expect, data)
2047 self.assertEqual('''ImagePos Offset Size Name
204800000000 00000000 00000028 main-section
204900000000 00000000 00000008 fill
205000000008 00000008 00000004 u-boot
20510000000c 0000000c 00000004 section
20520000000c 00000000 00000003 intel-mrc
205300000010 00000010 00000004 u-boot2
205400000014 00000014 0000000c section2
205500000014 00000000 00000008 fill
20560000001c 00000008 00000004 u-boot
205700000020 00000020 00000008 fill2
2058''', map_data)
2059
Simon Glassdd156a42022-03-05 20:18:59 -07002060 def testExtendSizeBad(self):
2061 """Test an extending entry which fails to provide contents"""
Simon Glasscd817d52018-09-14 04:57:36 -06002062 with test_util.capture_sys_output() as (stdout, stderr):
2063 with self.assertRaises(ValueError) as e:
Simon Glassdd156a42022-03-05 20:18:59 -07002064 self._DoReadFileDtb('089_extend_size_bad.dts', map=True)
Simon Glassfa79a812018-09-14 04:57:29 -06002065 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
2066 'expanding entry', str(e.exception))
2067
Simon Glassae7cf032018-09-14 04:57:31 -06002068 def testHash(self):
2069 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002070 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002071 use_real_dtb=True, update_dtb=True)
2072 dtb = fdt.Fdt(out_dtb_fname)
2073 dtb.Scan()
2074 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
2075 m = hashlib.sha256()
2076 m.update(U_BOOT_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002077 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002078
2079 def testHashNoAlgo(self):
2080 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002081 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glassae7cf032018-09-14 04:57:31 -06002082 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2083 'hash node', str(e.exception))
2084
2085 def testHashBadAlgo(self):
2086 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002087 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glass64af7c22022-02-08 10:59:44 -07002088 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm 'invalid'",
Simon Glassae7cf032018-09-14 04:57:31 -06002089 str(e.exception))
2090
2091 def testHashSection(self):
2092 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002093 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002094 use_real_dtb=True, update_dtb=True)
2095 dtb = fdt.Fdt(out_dtb_fname)
2096 dtb.Scan()
2097 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2098 m = hashlib.sha256()
2099 m.update(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07002100 m.update(tools.get_bytes(ord('a'), 16))
Simon Glass303f62f2019-05-17 22:00:46 -06002101 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002102
Simon Glass3fb4f422018-09-14 04:57:32 -06002103 def testPackUBootTplMicrocode(self):
2104 """Test that x86 microcode can be handled correctly in TPL
2105
2106 We expect to see the following in the image, in order:
2107 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2108 place
2109 u-boot-tpl.dtb with the microcode removed
2110 the microcode
2111 """
Simon Glass3eb5b202019-08-24 07:23:00 -06002112 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass511f6582018-10-01 12:22:30 -06002113 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glass3fb4f422018-09-14 04:57:32 -06002114 U_BOOT_TPL_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002115 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2116 b'ter somewhere in here', first)
Simon Glass3fb4f422018-09-14 04:57:32 -06002117
Simon Glassc64aea52018-09-14 04:57:34 -06002118 def testFmapX86(self):
2119 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002120 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassc64aea52018-09-14 04:57:34 -06002121 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass80025522022-01-29 14:14:04 -07002122 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('a'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002123 self.assertEqual(expected, data[:32])
2124 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2125
2126 self.assertEqual(0x100, fhdr.image_size)
2127
2128 self.assertEqual(0, fentries[0].offset)
2129 self.assertEqual(4, fentries[0].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002130 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002131
2132 self.assertEqual(4, fentries[1].offset)
2133 self.assertEqual(3, fentries[1].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002134 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002135
2136 self.assertEqual(32, fentries[2].offset)
2137 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2138 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002139 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002140
2141 def testFmapX86Section(self):
2142 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002143 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glass80025522022-01-29 14:14:04 -07002144 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('b'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002145 self.assertEqual(expected, data[:32])
2146 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2147
Simon Glassb1d414c2021-04-03 11:05:10 +13002148 self.assertEqual(0x180, fhdr.image_size)
2149 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
Simon Glass82059c22021-04-03 11:05:09 +13002150 fiter = iter(fentries)
Simon Glassc64aea52018-09-14 04:57:34 -06002151
Simon Glass82059c22021-04-03 11:05:09 +13002152 fentry = next(fiter)
2153 self.assertEqual(b'U_BOOT', fentry.name)
2154 self.assertEqual(0, fentry.offset)
2155 self.assertEqual(4, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002156
Simon Glass82059c22021-04-03 11:05:09 +13002157 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13002158 self.assertEqual(b'SECTION', fentry.name)
2159 self.assertEqual(4, fentry.offset)
2160 self.assertEqual(0x20 + expect_size, fentry.size)
2161
2162 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13002163 self.assertEqual(b'INTEL_MRC', fentry.name)
2164 self.assertEqual(4, fentry.offset)
2165 self.assertEqual(3, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002166
Simon Glass82059c22021-04-03 11:05:09 +13002167 fentry = next(fiter)
2168 self.assertEqual(b'FMAP', fentry.name)
2169 self.assertEqual(36, fentry.offset)
2170 self.assertEqual(expect_size, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002171
Simon Glassb1714232018-09-14 04:57:35 -06002172 def testElf(self):
2173 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002174 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002175 self._SetupTplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002176 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002177 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002178 data = self._DoReadFile('096_elf.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002179
Simon Glass0d673792019-07-08 13:18:25 -06002180 def testElfStrip(self):
Simon Glassb1714232018-09-14 04:57:35 -06002181 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002182 self._SetupSplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002183 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002184 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002185 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002186
Simon Glasscd817d52018-09-14 04:57:36 -06002187 def testPackOverlapMap(self):
2188 """Test that overlapping regions are detected"""
2189 with test_util.capture_sys_output() as (stdout, stderr):
2190 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002191 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glass80025522022-01-29 14:14:04 -07002192 map_fname = tools.get_output_filename('image.map')
Simon Glasscd817d52018-09-14 04:57:36 -06002193 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2194 stdout.getvalue())
2195
2196 # We should not get an inmage, but there should be a map file
Simon Glass80025522022-01-29 14:14:04 -07002197 self.assertFalse(os.path.exists(tools.get_output_filename('image.bin')))
Simon Glasscd817d52018-09-14 04:57:36 -06002198 self.assertTrue(os.path.exists(map_fname))
Simon Glass80025522022-01-29 14:14:04 -07002199 map_data = tools.read_file(map_fname, binary=False)
Simon Glasscd817d52018-09-14 04:57:36 -06002200 self.assertEqual('''ImagePos Offset Size Name
Simon Glassd99850b2020-10-26 17:40:24 -06002201<none> 00000000 00000008 main-section
Simon Glasscd817d52018-09-14 04:57:36 -06002202<none> 00000000 00000004 u-boot
2203<none> 00000003 00000004 u-boot-align
2204''', map_data)
2205
Simon Glass0d673792019-07-08 13:18:25 -06002206 def testPackRefCode(self):
Simon Glass41902e42018-10-01 12:22:31 -06002207 """Test that an image with an Intel Reference code binary works"""
2208 data = self._DoReadFile('100_intel_refcode.dts')
2209 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2210
Simon Glasseb023b32019-04-25 21:58:39 -06002211 def testSectionOffset(self):
2212 """Tests use of a section with an offset"""
2213 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2214 map=True)
2215 self.assertEqual('''ImagePos Offset Size Name
221600000000 00000000 00000038 main-section
221700000004 00000004 00000010 section@0
221800000004 00000000 00000004 u-boot
221900000018 00000018 00000010 section@1
222000000018 00000000 00000004 u-boot
22210000002c 0000002c 00000004 section@2
22220000002c 00000000 00000004 u-boot
2223''', map_data)
2224 self.assertEqual(data,
Simon Glass80025522022-01-29 14:14:04 -07002225 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2226 tools.get_bytes(0x21, 12) +
2227 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2228 tools.get_bytes(0x61, 12) +
2229 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2230 tools.get_bytes(0x26, 8))
Simon Glasseb023b32019-04-25 21:58:39 -06002231
Simon Glass1de34482019-07-08 13:18:53 -06002232 def testCbfsRaw(self):
2233 """Test base handling of a Coreboot Filesystem (CBFS)
2234
2235 The exact contents of the CBFS is verified by similar tests in
2236 cbfs_util_test.py. The tests here merely check that the files added to
2237 the CBFS can be found in the final image.
2238 """
2239 data = self._DoReadFile('102_cbfs_raw.dts')
2240 size = 0xb0
2241
2242 cbfs = cbfs_util.CbfsReader(data)
2243 self.assertEqual(size, cbfs.rom_size)
2244
2245 self.assertIn('u-boot-dtb', cbfs.files)
2246 cfile = cbfs.files['u-boot-dtb']
2247 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2248
2249 def testCbfsArch(self):
2250 """Test on non-x86 architecture"""
2251 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2252 size = 0x100
2253
2254 cbfs = cbfs_util.CbfsReader(data)
2255 self.assertEqual(size, cbfs.rom_size)
2256
2257 self.assertIn('u-boot-dtb', cbfs.files)
2258 cfile = cbfs.files['u-boot-dtb']
2259 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2260
2261 def testCbfsStage(self):
2262 """Tests handling of a Coreboot Filesystem (CBFS)"""
2263 if not elf.ELF_TOOLS:
2264 self.skipTest('Python elftools not available')
2265 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2266 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2267 size = 0xb0
2268
2269 data = self._DoReadFile('104_cbfs_stage.dts')
2270 cbfs = cbfs_util.CbfsReader(data)
2271 self.assertEqual(size, cbfs.rom_size)
2272
2273 self.assertIn('u-boot', cbfs.files)
2274 cfile = cbfs.files['u-boot']
2275 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2276
2277 def testCbfsRawCompress(self):
2278 """Test handling of compressing raw files"""
2279 self._CheckLz4()
2280 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2281 size = 0x140
2282
2283 cbfs = cbfs_util.CbfsReader(data)
2284 self.assertIn('u-boot', cbfs.files)
2285 cfile = cbfs.files['u-boot']
2286 self.assertEqual(COMPRESS_DATA, cfile.data)
2287
2288 def testCbfsBadArch(self):
2289 """Test handling of a bad architecture"""
2290 with self.assertRaises(ValueError) as e:
2291 self._DoReadFile('106_cbfs_bad_arch.dts')
2292 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2293
2294 def testCbfsNoSize(self):
2295 """Test handling of a missing size property"""
2296 with self.assertRaises(ValueError) as e:
2297 self._DoReadFile('107_cbfs_no_size.dts')
2298 self.assertIn('entry must have a size property', str(e.exception))
2299
Simon Glass3e28f4f2021-11-23 11:03:54 -07002300 def testCbfsNoContents(self):
Simon Glass1de34482019-07-08 13:18:53 -06002301 """Test handling of a CBFS entry which does not provide contentsy"""
2302 with self.assertRaises(ValueError) as e:
2303 self._DoReadFile('108_cbfs_no_contents.dts')
2304 self.assertIn('Could not complete processing of contents',
2305 str(e.exception))
2306
2307 def testCbfsBadCompress(self):
2308 """Test handling of a bad architecture"""
2309 with self.assertRaises(ValueError) as e:
2310 self._DoReadFile('109_cbfs_bad_compress.dts')
2311 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2312 str(e.exception))
2313
2314 def testCbfsNamedEntries(self):
2315 """Test handling of named entries"""
2316 data = self._DoReadFile('110_cbfs_name.dts')
2317
2318 cbfs = cbfs_util.CbfsReader(data)
2319 self.assertIn('FRED', cbfs.files)
2320 cfile1 = cbfs.files['FRED']
2321 self.assertEqual(U_BOOT_DATA, cfile1.data)
2322
2323 self.assertIn('hello', cbfs.files)
2324 cfile2 = cbfs.files['hello']
2325 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2326
Simon Glass759af872019-07-08 13:18:54 -06002327 def _SetupIfwi(self, fname):
2328 """Set up to run an IFWI test
2329
2330 Args:
2331 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2332 """
2333 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002334 self._SetupTplElf()
Simon Glass759af872019-07-08 13:18:54 -06002335
2336 # Intel Integrated Firmware Image (IFWI) file
2337 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2338 data = fd.read()
2339 TestFunctional._MakeInputFile(fname,data)
2340
2341 def _CheckIfwi(self, data):
2342 """Check that an image with an IFWI contains the correct output
2343
2344 Args:
2345 data: Conents of output file
2346 """
Simon Glass80025522022-01-29 14:14:04 -07002347 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glass759af872019-07-08 13:18:54 -06002348 if data[:0x1000] != expected_desc:
2349 self.fail('Expected descriptor binary at start of image')
2350
2351 # We expect to find the TPL wil in subpart IBBP entry IBBL
Simon Glass80025522022-01-29 14:14:04 -07002352 image_fname = tools.get_output_filename('image.bin')
2353 tpl_fname = tools.get_output_filename('tpl.out')
Simon Glass57c7a482022-01-09 20:14:01 -07002354 ifwitool = bintool.Bintool.create('ifwitool')
2355 ifwitool.extract(image_fname, 'IBBP', 'IBBL', tpl_fname)
Simon Glass759af872019-07-08 13:18:54 -06002356
Simon Glass80025522022-01-29 14:14:04 -07002357 tpl_data = tools.read_file(tpl_fname)
Simon Glassf55bd692019-08-24 07:22:51 -06002358 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glass759af872019-07-08 13:18:54 -06002359
2360 def testPackX86RomIfwi(self):
2361 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2362 self._SetupIfwi('fitimage.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002363 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glass759af872019-07-08 13:18:54 -06002364 self._CheckIfwi(data)
2365
2366 def testPackX86RomIfwiNoDesc(self):
2367 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2368 self._SetupIfwi('ifwi.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002369 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glass759af872019-07-08 13:18:54 -06002370 self._CheckIfwi(data)
2371
2372 def testPackX86RomIfwiNoData(self):
2373 """Test that an x86 ROM with IFWI handles missing data"""
2374 self._SetupIfwi('ifwi.bin')
2375 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06002376 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glass759af872019-07-08 13:18:54 -06002377 self.assertIn('Could not complete processing of contents',
2378 str(e.exception))
Simon Glass91710b32018-07-17 13:25:32 -06002379
Simon Glass66152ce2022-01-09 20:14:09 -07002380 def testIfwiMissing(self):
2381 """Test that binman still produces an image if ifwitool is missing"""
2382 self._SetupIfwi('fitimage.bin')
2383 with test_util.capture_sys_output() as (_, stderr):
2384 self._DoTestFile('111_x86_rom_ifwi.dts',
2385 force_missing_bintools='ifwitool')
2386 err = stderr.getvalue()
2387 self.assertRegex(err,
2388 "Image 'main-section'.*missing bintools.*: ifwitool")
2389
Simon Glassc2f1aed2019-07-08 13:18:56 -06002390 def testCbfsOffset(self):
2391 """Test a CBFS with files at particular offsets
2392
2393 Like all CFBS tests, this is just checking the logic that calls
2394 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2395 """
2396 data = self._DoReadFile('114_cbfs_offset.dts')
2397 size = 0x200
2398
2399 cbfs = cbfs_util.CbfsReader(data)
2400 self.assertEqual(size, cbfs.rom_size)
2401
2402 self.assertIn('u-boot', cbfs.files)
2403 cfile = cbfs.files['u-boot']
2404 self.assertEqual(U_BOOT_DATA, cfile.data)
2405 self.assertEqual(0x40, cfile.cbfs_offset)
2406
2407 self.assertIn('u-boot-dtb', cbfs.files)
2408 cfile2 = cbfs.files['u-boot-dtb']
2409 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2410 self.assertEqual(0x140, cfile2.cbfs_offset)
2411
Simon Glass0f621332019-07-08 14:25:27 -06002412 def testFdtmap(self):
2413 """Test an FDT map can be inserted in the image"""
2414 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2415 fdtmap_data = data[len(U_BOOT_DATA):]
2416 magic = fdtmap_data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002417 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07002418 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass0f621332019-07-08 14:25:27 -06002419
2420 fdt_data = fdtmap_data[16:]
2421 dtb = fdt.Fdt.FromData(fdt_data)
2422 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002423 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass0f621332019-07-08 14:25:27 -06002424 self.assertEqual({
2425 'image-pos': 0,
2426 'offset': 0,
2427 'u-boot:offset': 0,
2428 'u-boot:size': len(U_BOOT_DATA),
2429 'u-boot:image-pos': 0,
2430 'fdtmap:image-pos': 4,
2431 'fdtmap:offset': 4,
2432 'fdtmap:size': len(fdtmap_data),
2433 'size': len(data),
2434 }, props)
2435
2436 def testFdtmapNoMatch(self):
2437 """Check handling of an FDT map when the section cannot be found"""
2438 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2439
2440 # Mangle the section name, which should cause a mismatch between the
2441 # correct FDT path and the one expected by the section
2442 image = control.images['image']
Simon Glasscec34ba2019-07-08 14:25:28 -06002443 image._node.path += '-suffix'
Simon Glass0f621332019-07-08 14:25:27 -06002444 entries = image.GetEntries()
2445 fdtmap = entries['fdtmap']
2446 with self.assertRaises(ValueError) as e:
2447 fdtmap._GetFdtmap()
2448 self.assertIn("Cannot locate node for path '/binman-suffix'",
2449 str(e.exception))
2450
Simon Glasscec34ba2019-07-08 14:25:28 -06002451 def testFdtmapHeader(self):
2452 """Test an FDT map and image header can be inserted in the image"""
2453 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2454 fdtmap_pos = len(U_BOOT_DATA)
2455 fdtmap_data = data[fdtmap_pos:]
2456 fdt_data = fdtmap_data[16:]
2457 dtb = fdt.Fdt.FromData(fdt_data)
2458 fdt_size = dtb.GetFdtObj().totalsize()
2459 hdr_data = data[-8:]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002460 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002461 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2462 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2463
2464 def testFdtmapHeaderStart(self):
2465 """Test an image header can be inserted at the image start"""
2466 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2467 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2468 hdr_data = data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002469 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002470 offset = struct.unpack('<I', hdr_data[4:])[0]
2471 self.assertEqual(fdtmap_pos, offset)
2472
2473 def testFdtmapHeaderPos(self):
2474 """Test an image header can be inserted at a chosen position"""
2475 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2476 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2477 hdr_data = data[0x80:0x88]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002478 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002479 offset = struct.unpack('<I', hdr_data[4:])[0]
2480 self.assertEqual(fdtmap_pos, offset)
2481
2482 def testHeaderMissingFdtmap(self):
2483 """Test an image header requires an fdtmap"""
2484 with self.assertRaises(ValueError) as e:
2485 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2486 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2487 str(e.exception))
2488
2489 def testHeaderNoLocation(self):
2490 """Test an image header with a no specified location is detected"""
2491 with self.assertRaises(ValueError) as e:
2492 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2493 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2494 str(e.exception))
2495
Simon Glasse61b6f62019-07-08 14:25:37 -06002496 def testEntryExpand(self):
Simon Glassdd156a42022-03-05 20:18:59 -07002497 """Test extending an entry after it is packed"""
2498 data = self._DoReadFile('121_entry_extend.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002499 self.assertEqual(b'aaa', data[:3])
2500 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2501 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002502
Simon Glassdd156a42022-03-05 20:18:59 -07002503 def testEntryExtendBad(self):
2504 """Test extending an entry after it is packed, twice"""
Simon Glasse61b6f62019-07-08 14:25:37 -06002505 with self.assertRaises(ValueError) as e:
Simon Glassdd156a42022-03-05 20:18:59 -07002506 self._DoReadFile('122_entry_extend_twice.dts')
Simon Glass9d8ee322019-07-20 12:23:58 -06002507 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glasse61b6f62019-07-08 14:25:37 -06002508 str(e.exception))
2509
Simon Glassdd156a42022-03-05 20:18:59 -07002510 def testEntryExtendSection(self):
2511 """Test extending an entry within a section after it is packed"""
2512 data = self._DoReadFile('123_entry_extend_section.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002513 self.assertEqual(b'aaa', data[:3])
2514 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2515 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002516
Simon Glass90d29682019-07-08 14:25:38 -06002517 def testCompressDtb(self):
2518 """Test that compress of device-tree files is supported"""
2519 self._CheckLz4()
2520 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2521 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2522 comp_data = data[len(U_BOOT_DATA):]
2523 orig = self._decompress(comp_data)
2524 dtb = fdt.Fdt.FromData(orig)
2525 dtb.Scan()
2526 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2527 expected = {
2528 'u-boot:size': len(U_BOOT_DATA),
2529 'u-boot-dtb:uncomp-size': len(orig),
2530 'u-boot-dtb:size': len(comp_data),
2531 'size': len(data),
2532 }
2533 self.assertEqual(expected, props)
2534
Simon Glass151bbbf2019-07-08 14:25:41 -06002535 def testCbfsUpdateFdt(self):
2536 """Test that we can update the device tree with CBFS offset/size info"""
2537 self._CheckLz4()
2538 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2539 update_dtb=True)
2540 dtb = fdt.Fdt(out_dtb_fname)
2541 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002542 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass151bbbf2019-07-08 14:25:41 -06002543 del props['cbfs/u-boot:size']
2544 self.assertEqual({
2545 'offset': 0,
2546 'size': len(data),
2547 'image-pos': 0,
2548 'cbfs:offset': 0,
2549 'cbfs:size': len(data),
2550 'cbfs:image-pos': 0,
2551 'cbfs/u-boot:offset': 0x38,
2552 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2553 'cbfs/u-boot:image-pos': 0x38,
2554 'cbfs/u-boot-dtb:offset': 0xb8,
2555 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2556 'cbfs/u-boot-dtb:image-pos': 0xb8,
2557 }, props)
2558
Simon Glass3c9b4f22019-07-08 14:25:42 -06002559 def testCbfsBadType(self):
2560 """Test an image header with a no specified location is detected"""
2561 with self.assertRaises(ValueError) as e:
2562 self._DoReadFile('126_cbfs_bad_type.dts')
2563 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2564
Simon Glass6b156f82019-07-08 14:25:43 -06002565 def testList(self):
2566 """Test listing the files in an image"""
2567 self._CheckLz4()
2568 data = self._DoReadFile('127_list.dts')
2569 image = control.images['image']
2570 entries = image.BuildEntryList()
2571 self.assertEqual(7, len(entries))
2572
2573 ent = entries[0]
2574 self.assertEqual(0, ent.indent)
2575 self.assertEqual('main-section', ent.name)
2576 self.assertEqual('section', ent.etype)
2577 self.assertEqual(len(data), ent.size)
2578 self.assertEqual(0, ent.image_pos)
2579 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002580 self.assertEqual(0, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002581
2582 ent = entries[1]
2583 self.assertEqual(1, ent.indent)
2584 self.assertEqual('u-boot', ent.name)
2585 self.assertEqual('u-boot', ent.etype)
2586 self.assertEqual(len(U_BOOT_DATA), ent.size)
2587 self.assertEqual(0, ent.image_pos)
2588 self.assertEqual(None, ent.uncomp_size)
2589 self.assertEqual(0, ent.offset)
2590
2591 ent = entries[2]
2592 self.assertEqual(1, ent.indent)
2593 self.assertEqual('section', ent.name)
2594 self.assertEqual('section', ent.etype)
2595 section_size = ent.size
2596 self.assertEqual(0x100, ent.image_pos)
2597 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002598 self.assertEqual(0x100, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002599
2600 ent = entries[3]
2601 self.assertEqual(2, ent.indent)
2602 self.assertEqual('cbfs', ent.name)
2603 self.assertEqual('cbfs', ent.etype)
2604 self.assertEqual(0x400, ent.size)
2605 self.assertEqual(0x100, ent.image_pos)
2606 self.assertEqual(None, ent.uncomp_size)
2607 self.assertEqual(0, ent.offset)
2608
2609 ent = entries[4]
2610 self.assertEqual(3, ent.indent)
2611 self.assertEqual('u-boot', ent.name)
2612 self.assertEqual('u-boot', ent.etype)
2613 self.assertEqual(len(U_BOOT_DATA), ent.size)
2614 self.assertEqual(0x138, ent.image_pos)
2615 self.assertEqual(None, ent.uncomp_size)
2616 self.assertEqual(0x38, ent.offset)
2617
2618 ent = entries[5]
2619 self.assertEqual(3, ent.indent)
2620 self.assertEqual('u-boot-dtb', ent.name)
2621 self.assertEqual('text', ent.etype)
2622 self.assertGreater(len(COMPRESS_DATA), ent.size)
2623 self.assertEqual(0x178, ent.image_pos)
2624 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2625 self.assertEqual(0x78, ent.offset)
2626
2627 ent = entries[6]
2628 self.assertEqual(2, ent.indent)
2629 self.assertEqual('u-boot-dtb', ent.name)
2630 self.assertEqual('u-boot-dtb', ent.etype)
2631 self.assertEqual(0x500, ent.image_pos)
2632 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2633 dtb_size = ent.size
2634 # Compressing this data expands it since headers are added
2635 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2636 self.assertEqual(0x400, ent.offset)
2637
2638 self.assertEqual(len(data), 0x100 + section_size)
2639 self.assertEqual(section_size, 0x400 + dtb_size)
2640
Simon Glass8d8bf4e2019-07-08 14:25:44 -06002641 def testFindFdtmap(self):
2642 """Test locating an FDT map in an image"""
2643 self._CheckLz4()
2644 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2645 image = control.images['image']
2646 entries = image.GetEntries()
2647 entry = entries['fdtmap']
2648 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2649
2650 def testFindFdtmapMissing(self):
2651 """Test failing to locate an FDP map"""
2652 data = self._DoReadFile('005_simple.dts')
2653 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2654
Simon Glassed39a3c2019-07-08 14:25:45 -06002655 def testFindImageHeader(self):
2656 """Test locating a image header"""
2657 self._CheckLz4()
Simon Glassb8424fa2019-07-08 14:25:46 -06002658 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002659 image = control.images['image']
2660 entries = image.GetEntries()
2661 entry = entries['fdtmap']
2662 # The header should point to the FDT map
2663 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2664
2665 def testFindImageHeaderStart(self):
2666 """Test locating a image header located at the start of an image"""
Simon Glassb8424fa2019-07-08 14:25:46 -06002667 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002668 image = control.images['image']
2669 entries = image.GetEntries()
2670 entry = entries['fdtmap']
2671 # The header should point to the FDT map
2672 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2673
2674 def testFindImageHeaderMissing(self):
2675 """Test failing to locate an image header"""
2676 data = self._DoReadFile('005_simple.dts')
2677 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2678
Simon Glassb8424fa2019-07-08 14:25:46 -06002679 def testReadImage(self):
2680 """Test reading an image and accessing its FDT map"""
2681 self._CheckLz4()
2682 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass80025522022-01-29 14:14:04 -07002683 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002684 orig_image = control.images['image']
2685 image = Image.FromFile(image_fname)
2686 self.assertEqual(orig_image.GetEntries().keys(),
2687 image.GetEntries().keys())
2688
2689 orig_entry = orig_image.GetEntries()['fdtmap']
2690 entry = image.GetEntries()['fdtmap']
2691 self.assertEquals(orig_entry.offset, entry.offset)
2692 self.assertEquals(orig_entry.size, entry.size)
2693 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2694
2695 def testReadImageNoHeader(self):
2696 """Test accessing an image's FDT map without an image header"""
2697 self._CheckLz4()
2698 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
Simon Glass80025522022-01-29 14:14:04 -07002699 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002700 image = Image.FromFile(image_fname)
2701 self.assertTrue(isinstance(image, Image))
Simon Glass072959a2019-07-20 12:23:50 -06002702 self.assertEqual('image', image.image_name[-5:])
Simon Glassb8424fa2019-07-08 14:25:46 -06002703
2704 def testReadImageFail(self):
2705 """Test failing to read an image image's FDT map"""
2706 self._DoReadFile('005_simple.dts')
Simon Glass80025522022-01-29 14:14:04 -07002707 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002708 with self.assertRaises(ValueError) as e:
2709 image = Image.FromFile(image_fname)
2710 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glassc2f1aed2019-07-08 13:18:56 -06002711
Simon Glassb2fd11d2019-07-08 14:25:48 -06002712 def testListCmd(self):
2713 """Test listing the files in an image using an Fdtmap"""
2714 self._CheckLz4()
2715 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2716
2717 # lz4 compression size differs depending on the version
2718 image = control.images['image']
2719 entries = image.GetEntries()
2720 section_size = entries['section'].size
2721 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2722 fdtmap_offset = entries['fdtmap'].offset
2723
Simon Glassb3d6fc72019-07-20 12:24:10 -06002724 try:
2725 tmpdir, updated_fname = self._SetupImageInTmpdir()
2726 with test_util.capture_sys_output() as (stdout, stderr):
2727 self._DoBinman('ls', '-i', updated_fname)
2728 finally:
2729 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002730 lines = stdout.getvalue().splitlines()
2731 expected = [
2732'Name Image-pos Size Entry-type Offset Uncomp-size',
2733'----------------------------------------------------------------------',
2734'main-section 0 c00 section 0',
2735' u-boot 0 4 u-boot 0',
2736' section 100 %x section 100' % section_size,
2737' cbfs 100 400 cbfs 0',
2738' u-boot 138 4 u-boot 38',
Simon Glassc5fd10a2019-10-31 07:43:03 -06002739' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002740' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassc5fd10a2019-10-31 07:43:03 -06002741' fdtmap %x 3bd fdtmap %x' %
Simon Glassb2fd11d2019-07-08 14:25:48 -06002742 (fdtmap_offset, fdtmap_offset),
2743' image-header bf8 8 image-header bf8',
2744 ]
2745 self.assertEqual(expected, lines)
2746
2747 def testListCmdFail(self):
2748 """Test failing to list an image"""
2749 self._DoReadFile('005_simple.dts')
Simon Glassb3d6fc72019-07-20 12:24:10 -06002750 try:
2751 tmpdir, updated_fname = self._SetupImageInTmpdir()
2752 with self.assertRaises(ValueError) as e:
2753 self._DoBinman('ls', '-i', updated_fname)
2754 finally:
2755 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002756 self.assertIn("Cannot find FDT map in image", str(e.exception))
2757
2758 def _RunListCmd(self, paths, expected):
2759 """List out entries and check the result
2760
2761 Args:
2762 paths: List of paths to pass to the list command
2763 expected: Expected list of filenames to be returned, in order
2764 """
2765 self._CheckLz4()
2766 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002767 image_fname = tools.get_output_filename('image.bin')
Simon Glassb2fd11d2019-07-08 14:25:48 -06002768 image = Image.FromFile(image_fname)
2769 lines = image.GetListEntries(paths)[1]
2770 files = [line[0].strip() for line in lines[1:]]
2771 self.assertEqual(expected, files)
2772
2773 def testListCmdSection(self):
2774 """Test listing the files in a section"""
2775 self._RunListCmd(['section'],
2776 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2777
2778 def testListCmdFile(self):
2779 """Test listing a particular file"""
2780 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2781
2782 def testListCmdWildcard(self):
2783 """Test listing a wildcarded file"""
2784 self._RunListCmd(['*boot*'],
2785 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2786
2787 def testListCmdWildcardMulti(self):
2788 """Test listing a wildcarded file"""
2789 self._RunListCmd(['*cb*', '*head*'],
2790 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2791
2792 def testListCmdEmpty(self):
2793 """Test listing a wildcarded file"""
2794 self._RunListCmd(['nothing'], [])
2795
2796 def testListCmdPath(self):
2797 """Test listing the files in a sub-entry of a section"""
2798 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2799
Simon Glass4c613bf2019-07-08 14:25:50 -06002800 def _RunExtractCmd(self, entry_name, decomp=True):
2801 """Extract an entry from an image
2802
2803 Args:
2804 entry_name: Entry name to extract
2805 decomp: True to decompress the data if compressed, False to leave
2806 it in its raw uncompressed format
2807
2808 Returns:
2809 data from entry
2810 """
2811 self._CheckLz4()
2812 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002813 image_fname = tools.get_output_filename('image.bin')
Simon Glass4c613bf2019-07-08 14:25:50 -06002814 return control.ReadEntry(image_fname, entry_name, decomp)
2815
2816 def testExtractSimple(self):
2817 """Test extracting a single file"""
2818 data = self._RunExtractCmd('u-boot')
2819 self.assertEqual(U_BOOT_DATA, data)
2820
Simon Glass980a2842019-07-08 14:25:52 -06002821 def testExtractSection(self):
2822 """Test extracting the files in a section"""
2823 data = self._RunExtractCmd('section')
2824 cbfs_data = data[:0x400]
2825 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassc5fd10a2019-10-31 07:43:03 -06002826 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass980a2842019-07-08 14:25:52 -06002827 dtb_data = data[0x400:]
2828 dtb = self._decompress(dtb_data)
2829 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2830
2831 def testExtractCompressed(self):
2832 """Test extracting compressed data"""
2833 data = self._RunExtractCmd('section/u-boot-dtb')
2834 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2835
2836 def testExtractRaw(self):
2837 """Test extracting compressed data without decompressing it"""
2838 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2839 dtb = self._decompress(data)
2840 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2841
2842 def testExtractCbfs(self):
2843 """Test extracting CBFS data"""
2844 data = self._RunExtractCmd('section/cbfs/u-boot')
2845 self.assertEqual(U_BOOT_DATA, data)
2846
2847 def testExtractCbfsCompressed(self):
2848 """Test extracting CBFS compressed data"""
2849 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2850 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2851
2852 def testExtractCbfsRaw(self):
2853 """Test extracting CBFS compressed data without decompressing it"""
2854 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Simon Glassdd5c14ec2022-01-09 20:14:04 -07002855 dtb = comp_util.decompress(data, 'lzma', with_header=False)
Simon Glass980a2842019-07-08 14:25:52 -06002856 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2857
Simon Glass4c613bf2019-07-08 14:25:50 -06002858 def testExtractBadEntry(self):
2859 """Test extracting a bad section path"""
2860 with self.assertRaises(ValueError) as e:
2861 self._RunExtractCmd('section/does-not-exist')
2862 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2863 str(e.exception))
2864
2865 def testExtractMissingFile(self):
2866 """Test extracting file that does not exist"""
2867 with self.assertRaises(IOError) as e:
2868 control.ReadEntry('missing-file', 'name')
2869
2870 def testExtractBadFile(self):
2871 """Test extracting an invalid file"""
2872 fname = os.path.join(self._indir, 'badfile')
Simon Glass80025522022-01-29 14:14:04 -07002873 tools.write_file(fname, b'')
Simon Glass4c613bf2019-07-08 14:25:50 -06002874 with self.assertRaises(ValueError) as e:
2875 control.ReadEntry(fname, 'name')
2876
Simon Glass980a2842019-07-08 14:25:52 -06002877 def testExtractCmd(self):
2878 """Test extracting a file fron an image on the command line"""
2879 self._CheckLz4()
2880 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass980a2842019-07-08 14:25:52 -06002881 fname = os.path.join(self._indir, 'output.extact')
Simon Glassb3d6fc72019-07-20 12:24:10 -06002882 try:
2883 tmpdir, updated_fname = self._SetupImageInTmpdir()
2884 with test_util.capture_sys_output() as (stdout, stderr):
2885 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2886 '-f', fname)
2887 finally:
2888 shutil.rmtree(tmpdir)
Simon Glass80025522022-01-29 14:14:04 -07002889 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06002890 self.assertEqual(U_BOOT_DATA, data)
2891
2892 def testExtractOneEntry(self):
2893 """Test extracting a single entry fron an image """
2894 self._CheckLz4()
2895 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002896 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06002897 fname = os.path.join(self._indir, 'output.extact')
2898 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07002899 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06002900 self.assertEqual(U_BOOT_DATA, data)
2901
2902 def _CheckExtractOutput(self, decomp):
2903 """Helper to test file output with and without decompression
2904
2905 Args:
2906 decomp: True to decompress entry data, False to output it raw
2907 """
2908 def _CheckPresent(entry_path, expect_data, expect_size=None):
2909 """Check and remove expected file
2910
2911 This checks the data/size of a file and removes the file both from
2912 the outfiles set and from the output directory. Once all files are
2913 processed, both the set and directory should be empty.
2914
2915 Args:
2916 entry_path: Entry path
2917 expect_data: Data to expect in file, or None to skip check
2918 expect_size: Size of data to expect in file, or None to skip
2919 """
2920 path = os.path.join(outdir, entry_path)
Simon Glass80025522022-01-29 14:14:04 -07002921 data = tools.read_file(path)
Simon Glass980a2842019-07-08 14:25:52 -06002922 os.remove(path)
2923 if expect_data:
2924 self.assertEqual(expect_data, data)
2925 elif expect_size:
2926 self.assertEqual(expect_size, len(data))
2927 outfiles.remove(path)
2928
2929 def _CheckDirPresent(name):
2930 """Remove expected directory
2931
2932 This gives an error if the directory does not exist as expected
2933
2934 Args:
2935 name: Name of directory to remove
2936 """
2937 path = os.path.join(outdir, name)
2938 os.rmdir(path)
2939
2940 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002941 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06002942 outdir = os.path.join(self._indir, 'extract')
2943 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2944
2945 # Create a set of all file that were output (should be 9)
2946 outfiles = set()
2947 for root, dirs, files in os.walk(outdir):
2948 outfiles |= set([os.path.join(root, fname) for fname in files])
2949 self.assertEqual(9, len(outfiles))
2950 self.assertEqual(9, len(einfos))
2951
2952 image = control.images['image']
2953 entries = image.GetEntries()
2954
2955 # Check the 9 files in various ways
2956 section = entries['section']
2957 section_entries = section.GetEntries()
2958 cbfs_entries = section_entries['cbfs'].GetEntries()
2959 _CheckPresent('u-boot', U_BOOT_DATA)
2960 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
2961 dtb_len = EXTRACT_DTB_SIZE
2962 if not decomp:
2963 dtb_len = cbfs_entries['u-boot-dtb'].size
2964 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
2965 if not decomp:
2966 dtb_len = section_entries['u-boot-dtb'].size
2967 _CheckPresent('section/u-boot-dtb', None, dtb_len)
2968
2969 fdtmap = entries['fdtmap']
2970 _CheckPresent('fdtmap', fdtmap.data)
2971 hdr = entries['image-header']
2972 _CheckPresent('image-header', hdr.data)
2973
2974 _CheckPresent('section/root', section.data)
2975 cbfs = section_entries['cbfs']
2976 _CheckPresent('section/cbfs/root', cbfs.data)
Simon Glass80025522022-01-29 14:14:04 -07002977 data = tools.read_file(image_fname)
Simon Glass980a2842019-07-08 14:25:52 -06002978 _CheckPresent('root', data)
2979
2980 # There should be no files left. Remove all the directories to check.
2981 # If there are any files/dirs remaining, one of these checks will fail.
2982 self.assertEqual(0, len(outfiles))
2983 _CheckDirPresent('section/cbfs')
2984 _CheckDirPresent('section')
2985 _CheckDirPresent('')
2986 self.assertFalse(os.path.exists(outdir))
2987
2988 def testExtractAllEntries(self):
2989 """Test extracting all entries"""
2990 self._CheckLz4()
2991 self._CheckExtractOutput(decomp=True)
2992
2993 def testExtractAllEntriesRaw(self):
2994 """Test extracting all entries without decompressing them"""
2995 self._CheckLz4()
2996 self._CheckExtractOutput(decomp=False)
2997
2998 def testExtractSelectedEntries(self):
2999 """Test extracting some entries"""
3000 self._CheckLz4()
3001 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003002 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003003 outdir = os.path.join(self._indir, 'extract')
3004 einfos = control.ExtractEntries(image_fname, None, outdir,
3005 ['*cb*', '*head*'])
3006
3007 # File output is tested by testExtractAllEntries(), so just check that
3008 # the expected entries are selected
3009 names = [einfo.name for einfo in einfos]
3010 self.assertEqual(names,
3011 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
3012
3013 def testExtractNoEntryPaths(self):
3014 """Test extracting some entries"""
3015 self._CheckLz4()
3016 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003017 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003018 with self.assertRaises(ValueError) as e:
3019 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassa772d3f2019-07-20 12:24:14 -06003020 self.assertIn('Must specify an entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003021 str(e.exception))
3022
3023 def testExtractTooManyEntryPaths(self):
3024 """Test extracting some entries"""
3025 self._CheckLz4()
3026 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003027 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003028 with self.assertRaises(ValueError) as e:
3029 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassa772d3f2019-07-20 12:24:14 -06003030 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003031 str(e.exception))
3032
Simon Glass52d06212019-07-08 14:25:53 -06003033 def testPackAlignSection(self):
3034 """Test that sections can have alignment"""
3035 self._DoReadFile('131_pack_align_section.dts')
3036
3037 self.assertIn('image', control.images)
3038 image = control.images['image']
3039 entries = image.GetEntries()
3040 self.assertEqual(3, len(entries))
3041
3042 # First u-boot
3043 self.assertIn('u-boot', entries)
3044 entry = entries['u-boot']
3045 self.assertEqual(0, entry.offset)
3046 self.assertEqual(0, entry.image_pos)
3047 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3048 self.assertEqual(len(U_BOOT_DATA), entry.size)
3049
3050 # Section0
3051 self.assertIn('section0', entries)
3052 section0 = entries['section0']
3053 self.assertEqual(0x10, section0.offset)
3054 self.assertEqual(0x10, section0.image_pos)
3055 self.assertEqual(len(U_BOOT_DATA), section0.size)
3056
3057 # Second u-boot
3058 section_entries = section0.GetEntries()
3059 self.assertIn('u-boot', section_entries)
3060 entry = section_entries['u-boot']
3061 self.assertEqual(0, entry.offset)
3062 self.assertEqual(0x10, entry.image_pos)
3063 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3064 self.assertEqual(len(U_BOOT_DATA), entry.size)
3065
3066 # Section1
3067 self.assertIn('section1', entries)
3068 section1 = entries['section1']
3069 self.assertEqual(0x14, section1.offset)
3070 self.assertEqual(0x14, section1.image_pos)
3071 self.assertEqual(0x20, section1.size)
3072
3073 # Second u-boot
3074 section_entries = section1.GetEntries()
3075 self.assertIn('u-boot', section_entries)
3076 entry = section_entries['u-boot']
3077 self.assertEqual(0, entry.offset)
3078 self.assertEqual(0x14, entry.image_pos)
3079 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3080 self.assertEqual(len(U_BOOT_DATA), entry.size)
3081
3082 # Section2
3083 self.assertIn('section2', section_entries)
3084 section2 = section_entries['section2']
3085 self.assertEqual(0x4, section2.offset)
3086 self.assertEqual(0x18, section2.image_pos)
3087 self.assertEqual(4, section2.size)
3088
3089 # Third u-boot
3090 section_entries = section2.GetEntries()
3091 self.assertIn('u-boot', section_entries)
3092 entry = section_entries['u-boot']
3093 self.assertEqual(0, entry.offset)
3094 self.assertEqual(0x18, entry.image_pos)
3095 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3096 self.assertEqual(len(U_BOOT_DATA), entry.size)
3097
Simon Glassf8a54bc2019-07-20 12:23:56 -06003098 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3099 dts='132_replace.dts'):
Simon Glass072959a2019-07-20 12:23:50 -06003100 """Replace an entry in an image
3101
3102 This writes the entry data to update it, then opens the updated file and
3103 returns the value that it now finds there.
3104
3105 Args:
3106 entry_name: Entry name to replace
3107 data: Data to replace it with
3108 decomp: True to compress the data if needed, False if data is
3109 already compressed so should be used as is
Simon Glassf8a54bc2019-07-20 12:23:56 -06003110 allow_resize: True to allow entries to change size, False to raise
3111 an exception
Simon Glass072959a2019-07-20 12:23:50 -06003112
3113 Returns:
3114 Tuple:
3115 data from entry
3116 data from fdtmap (excluding header)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003117 Image object that was modified
Simon Glass072959a2019-07-20 12:23:50 -06003118 """
Simon Glassf8a54bc2019-07-20 12:23:56 -06003119 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass072959a2019-07-20 12:23:50 -06003120 update_dtb=True)[1]
3121
3122 self.assertIn('image', control.images)
3123 image = control.images['image']
3124 entries = image.GetEntries()
3125 orig_dtb_data = entries['u-boot-dtb'].data
3126 orig_fdtmap_data = entries['fdtmap'].data
3127
Simon Glass80025522022-01-29 14:14:04 -07003128 image_fname = tools.get_output_filename('image.bin')
3129 updated_fname = tools.get_output_filename('image-updated.bin')
3130 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassf8a54bc2019-07-20 12:23:56 -06003131 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3132 allow_resize)
Simon Glass072959a2019-07-20 12:23:50 -06003133 data = control.ReadEntry(updated_fname, entry_name, decomp)
3134
Simon Glassf8a54bc2019-07-20 12:23:56 -06003135 # The DT data should not change unless resized:
3136 if not allow_resize:
3137 new_dtb_data = entries['u-boot-dtb'].data
3138 self.assertEqual(new_dtb_data, orig_dtb_data)
3139 new_fdtmap_data = entries['fdtmap'].data
3140 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass072959a2019-07-20 12:23:50 -06003141
Simon Glassf8a54bc2019-07-20 12:23:56 -06003142 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass072959a2019-07-20 12:23:50 -06003143
3144 def testReplaceSimple(self):
3145 """Test replacing a single file"""
3146 expected = b'x' * len(U_BOOT_DATA)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003147 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3148 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003149 self.assertEqual(expected, data)
3150
3151 # Test that the state looks right. There should be an FDT for the fdtmap
3152 # that we jsut read back in, and it should match what we find in the
3153 # 'control' tables. Checking for an FDT that does not exist should
3154 # return None.
3155 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glassf8a54bc2019-07-20 12:23:56 -06003156 self.assertIsNotNone(path)
Simon Glass072959a2019-07-20 12:23:50 -06003157 self.assertEqual(expected_fdtmap, fdtmap)
3158
3159 dtb = state.GetFdtForEtype('fdtmap')
3160 self.assertEqual(dtb.GetContents(), fdtmap)
3161
3162 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3163 self.assertIsNone(missing_path)
3164 self.assertIsNone(missing_fdtmap)
3165
3166 missing_dtb = state.GetFdtForEtype('missing')
3167 self.assertIsNone(missing_dtb)
3168
3169 self.assertEqual('/binman', state.fdt_path_prefix)
3170
3171 def testReplaceResizeFail(self):
3172 """Test replacing a file by something larger"""
3173 expected = U_BOOT_DATA + b'x'
3174 with self.assertRaises(ValueError) as e:
Simon Glassf8a54bc2019-07-20 12:23:56 -06003175 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3176 dts='139_replace_repack.dts')
Simon Glass072959a2019-07-20 12:23:50 -06003177 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3178 str(e.exception))
3179
3180 def testReplaceMulti(self):
3181 """Test replacing entry data where multiple images are generated"""
3182 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3183 update_dtb=True)[0]
3184 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003185 updated_fname = tools.get_output_filename('image-updated.bin')
3186 tools.write_file(updated_fname, data)
Simon Glass072959a2019-07-20 12:23:50 -06003187 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003188 control.WriteEntry(updated_fname, entry_name, expected,
3189 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003190 data = control.ReadEntry(updated_fname, entry_name)
3191 self.assertEqual(expected, data)
3192
3193 # Check the state looks right.
3194 self.assertEqual('/binman/image', state.fdt_path_prefix)
3195
3196 # Now check we can write the first image
Simon Glass80025522022-01-29 14:14:04 -07003197 image_fname = tools.get_output_filename('first-image.bin')
3198 updated_fname = tools.get_output_filename('first-updated.bin')
3199 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glass072959a2019-07-20 12:23:50 -06003200 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003201 control.WriteEntry(updated_fname, entry_name, expected,
3202 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003203 data = control.ReadEntry(updated_fname, entry_name)
3204 self.assertEqual(expected, data)
3205
3206 # Check the state looks right.
3207 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass39dd2152019-07-08 14:25:47 -06003208
Simon Glassfb30e292019-07-20 12:23:51 -06003209 def testUpdateFdtAllRepack(self):
3210 """Test that all device trees are updated with offset/size info"""
3211 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3212 SECTION_SIZE = 0x300
3213 DTB_SIZE = 602
3214 FDTMAP_SIZE = 608
3215 base_expected = {
3216 'offset': 0,
3217 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3218 'image-pos': 0,
3219 'section:offset': 0,
3220 'section:size': SECTION_SIZE,
3221 'section:image-pos': 0,
3222 'section/u-boot-dtb:offset': 4,
3223 'section/u-boot-dtb:size': 636,
3224 'section/u-boot-dtb:image-pos': 4,
3225 'u-boot-spl-dtb:offset': SECTION_SIZE,
3226 'u-boot-spl-dtb:size': DTB_SIZE,
3227 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3228 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3229 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3230 'u-boot-tpl-dtb:size': DTB_SIZE,
3231 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3232 'fdtmap:size': FDTMAP_SIZE,
3233 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3234 }
3235 main_expected = {
3236 'section:orig-size': SECTION_SIZE,
3237 'section/u-boot-dtb:orig-offset': 4,
3238 }
3239
3240 # We expect three device-tree files in the output, with the first one
3241 # within a fixed-size section.
3242 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3243 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3244 # main U-Boot tree. All three should have the same positions and offset
3245 # except that the main tree should include the main_expected properties
3246 start = 4
3247 for item in ['', 'spl', 'tpl', None]:
3248 if item is None:
3249 start += 16 # Move past fdtmap header
3250 dtb = fdt.Fdt.FromData(data[start:])
3251 dtb.Scan()
3252 props = self._GetPropTree(dtb,
3253 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3254 prefix='/' if item is None else '/binman/')
3255 expected = dict(base_expected)
3256 if item:
3257 expected[item] = 0
3258 else:
3259 # Main DTB and fdtdec should include the 'orig-' properties
3260 expected.update(main_expected)
3261 # Helpful for debugging:
3262 #for prop in sorted(props):
3263 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3264 self.assertEqual(expected, props)
3265 if item == '':
3266 start = SECTION_SIZE
3267 else:
3268 start += dtb._fdt_obj.totalsize()
3269
Simon Glass11453762019-07-20 12:23:55 -06003270 def testFdtmapHeaderMiddle(self):
3271 """Test an FDT map in the middle of an image when it should be at end"""
3272 with self.assertRaises(ValueError) as e:
3273 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3274 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3275 str(e.exception))
3276
3277 def testFdtmapHeaderStartBad(self):
3278 """Test an FDT map in middle of an image when it should be at start"""
3279 with self.assertRaises(ValueError) as e:
3280 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3281 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3282 str(e.exception))
3283
3284 def testFdtmapHeaderEndBad(self):
3285 """Test an FDT map at the start of an image when it should be at end"""
3286 with self.assertRaises(ValueError) as e:
3287 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3288 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3289 str(e.exception))
3290
3291 def testFdtmapHeaderNoSize(self):
3292 """Test an image header at the end of an image with undefined size"""
3293 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3294
Simon Glassf8a54bc2019-07-20 12:23:56 -06003295 def testReplaceResize(self):
3296 """Test replacing a single file in an entry with a larger file"""
3297 expected = U_BOOT_DATA + b'x'
3298 data, _, image = self._RunReplaceCmd('u-boot', expected,
3299 dts='139_replace_repack.dts')
3300 self.assertEqual(expected, data)
3301
3302 entries = image.GetEntries()
3303 dtb_data = entries['u-boot-dtb'].data
3304 dtb = fdt.Fdt.FromData(dtb_data)
3305 dtb.Scan()
3306
3307 # The u-boot section should now be larger in the dtb
3308 node = dtb.GetNode('/binman/u-boot')
3309 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3310
3311 # Same for the fdtmap
3312 fdata = entries['fdtmap'].data
3313 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3314 fdtb.Scan()
3315 fnode = fdtb.GetNode('/u-boot')
3316 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3317
3318 def testReplaceResizeNoRepack(self):
3319 """Test replacing an entry with a larger file when not allowed"""
3320 expected = U_BOOT_DATA + b'x'
3321 with self.assertRaises(ValueError) as e:
3322 self._RunReplaceCmd('u-boot', expected)
3323 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3324 str(e.exception))
3325
Simon Glass9d8ee322019-07-20 12:23:58 -06003326 def testEntryShrink(self):
3327 """Test contracting an entry after it is packed"""
3328 try:
3329 state.SetAllowEntryContraction(True)
3330 data = self._DoReadFileDtb('140_entry_shrink.dts',
3331 update_dtb=True)[0]
3332 finally:
3333 state.SetAllowEntryContraction(False)
3334 self.assertEqual(b'a', data[:1])
3335 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3336 self.assertEqual(b'a', data[-1:])
3337
3338 def testEntryShrinkFail(self):
3339 """Test not being allowed to contract an entry after it is packed"""
3340 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3341
3342 # In this case there is a spare byte at the end of the data. The size of
3343 # the contents is only 1 byte but we still have the size before it
3344 # shrunk.
3345 self.assertEqual(b'a\0', data[:2])
3346 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3347 self.assertEqual(b'a\0', data[-2:])
3348
Simon Glass70e32982019-07-20 12:24:01 -06003349 def testDescriptorOffset(self):
3350 """Test that the Intel descriptor is always placed at at the start"""
3351 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3352 image = control.images['image']
3353 entries = image.GetEntries()
3354 desc = entries['intel-descriptor']
3355 self.assertEqual(0xff800000, desc.offset);
3356 self.assertEqual(0xff800000, desc.image_pos);
3357
Simon Glass37fdd142019-07-20 12:24:06 -06003358 def testReplaceCbfs(self):
3359 """Test replacing a single file in CBFS without changing the size"""
3360 self._CheckLz4()
3361 expected = b'x' * len(U_BOOT_DATA)
3362 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003363 updated_fname = tools.get_output_filename('image-updated.bin')
3364 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003365 entry_name = 'section/cbfs/u-boot'
3366 control.WriteEntry(updated_fname, entry_name, expected,
3367 allow_resize=True)
3368 data = control.ReadEntry(updated_fname, entry_name)
3369 self.assertEqual(expected, data)
3370
3371 def testReplaceResizeCbfs(self):
3372 """Test replacing a single file in CBFS with one of a different size"""
3373 self._CheckLz4()
3374 expected = U_BOOT_DATA + b'x'
3375 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003376 updated_fname = tools.get_output_filename('image-updated.bin')
3377 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003378 entry_name = 'section/cbfs/u-boot'
3379 control.WriteEntry(updated_fname, entry_name, expected,
3380 allow_resize=True)
3381 data = control.ReadEntry(updated_fname, entry_name)
3382 self.assertEqual(expected, data)
3383
Simon Glass30033c22019-07-20 12:24:15 -06003384 def _SetupForReplace(self):
3385 """Set up some files to use to replace entries
3386
3387 This generates an image, copies it to a new file, extracts all the files
3388 in it and updates some of them
3389
3390 Returns:
3391 List
3392 Image filename
3393 Output directory
3394 Expected values for updated entries, each a string
3395 """
3396 data = self._DoReadFileRealDtb('143_replace_all.dts')
3397
Simon Glass80025522022-01-29 14:14:04 -07003398 updated_fname = tools.get_output_filename('image-updated.bin')
3399 tools.write_file(updated_fname, data)
Simon Glass30033c22019-07-20 12:24:15 -06003400
3401 outdir = os.path.join(self._indir, 'extract')
3402 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3403
3404 expected1 = b'x' + U_BOOT_DATA + b'y'
3405 u_boot_fname1 = os.path.join(outdir, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07003406 tools.write_file(u_boot_fname1, expected1)
Simon Glass30033c22019-07-20 12:24:15 -06003407
3408 expected2 = b'a' + U_BOOT_DATA + b'b'
3409 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
Simon Glass80025522022-01-29 14:14:04 -07003410 tools.write_file(u_boot_fname2, expected2)
Simon Glass30033c22019-07-20 12:24:15 -06003411
3412 expected_text = b'not the same text'
3413 text_fname = os.path.join(outdir, 'text')
Simon Glass80025522022-01-29 14:14:04 -07003414 tools.write_file(text_fname, expected_text)
Simon Glass30033c22019-07-20 12:24:15 -06003415
3416 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3417 dtb = fdt.FdtScan(dtb_fname)
3418 node = dtb.GetNode('/binman/text')
3419 node.AddString('my-property', 'the value')
3420 dtb.Sync(auto_resize=True)
3421 dtb.Flush()
3422
3423 return updated_fname, outdir, expected1, expected2, expected_text
3424
3425 def _CheckReplaceMultiple(self, entry_paths):
3426 """Handle replacing the contents of multiple entries
3427
3428 Args:
3429 entry_paths: List of entry paths to replace
3430
3431 Returns:
3432 List
3433 Dict of entries in the image:
3434 key: Entry name
3435 Value: Entry object
3436 Expected values for updated entries, each a string
3437 """
3438 updated_fname, outdir, expected1, expected2, expected_text = (
3439 self._SetupForReplace())
3440 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3441
3442 image = Image.FromFile(updated_fname)
3443 image.LoadData()
3444 return image.GetEntries(), expected1, expected2, expected_text
3445
3446 def testReplaceAll(self):
3447 """Test replacing the contents of all entries"""
3448 entries, expected1, expected2, expected_text = (
3449 self._CheckReplaceMultiple([]))
3450 data = entries['u-boot'].data
3451 self.assertEqual(expected1, data)
3452
3453 data = entries['u-boot2'].data
3454 self.assertEqual(expected2, data)
3455
3456 data = entries['text'].data
3457 self.assertEqual(expected_text, data)
3458
3459 # Check that the device tree is updated
3460 data = entries['u-boot-dtb'].data
3461 dtb = fdt.Fdt.FromData(data)
3462 dtb.Scan()
3463 node = dtb.GetNode('/binman/text')
3464 self.assertEqual('the value', node.props['my-property'].value)
3465
3466 def testReplaceSome(self):
3467 """Test replacing the contents of a few entries"""
3468 entries, expected1, expected2, expected_text = (
3469 self._CheckReplaceMultiple(['u-boot2', 'text']))
3470
3471 # This one should not change
3472 data = entries['u-boot'].data
3473 self.assertEqual(U_BOOT_DATA, data)
3474
3475 data = entries['u-boot2'].data
3476 self.assertEqual(expected2, data)
3477
3478 data = entries['text'].data
3479 self.assertEqual(expected_text, data)
3480
3481 def testReplaceCmd(self):
3482 """Test replacing a file fron an image on the command line"""
3483 self._DoReadFileRealDtb('143_replace_all.dts')
3484
3485 try:
3486 tmpdir, updated_fname = self._SetupImageInTmpdir()
3487
3488 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3489 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003490 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003491
3492 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
Simon Glass80025522022-01-29 14:14:04 -07003493 data = tools.read_file(updated_fname)
Simon Glass30033c22019-07-20 12:24:15 -06003494 self.assertEqual(expected, data[:len(expected)])
3495 map_fname = os.path.join(tmpdir, 'image-updated.map')
3496 self.assertFalse(os.path.exists(map_fname))
3497 finally:
3498 shutil.rmtree(tmpdir)
3499
3500 def testReplaceCmdSome(self):
3501 """Test replacing some files fron an image on the command line"""
3502 updated_fname, outdir, expected1, expected2, expected_text = (
3503 self._SetupForReplace())
3504
3505 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3506 'u-boot2', 'text')
3507
Simon Glass80025522022-01-29 14:14:04 -07003508 tools.prepare_output_dir(None)
Simon Glass30033c22019-07-20 12:24:15 -06003509 image = Image.FromFile(updated_fname)
3510 image.LoadData()
3511 entries = image.GetEntries()
3512
3513 # This one should not change
3514 data = entries['u-boot'].data
3515 self.assertEqual(U_BOOT_DATA, data)
3516
3517 data = entries['u-boot2'].data
3518 self.assertEqual(expected2, data)
3519
3520 data = entries['text'].data
3521 self.assertEqual(expected_text, data)
3522
3523 def testReplaceMissing(self):
3524 """Test replacing entries where the file is missing"""
3525 updated_fname, outdir, expected1, expected2, expected_text = (
3526 self._SetupForReplace())
3527
3528 # Remove one of the files, to generate a warning
3529 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3530 os.remove(u_boot_fname1)
3531
3532 with test_util.capture_sys_output() as (stdout, stderr):
3533 control.ReplaceEntries(updated_fname, None, outdir, [])
3534 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass6e02f7c2020-07-09 18:39:39 -06003535 stderr.getvalue())
Simon Glass30033c22019-07-20 12:24:15 -06003536
3537 def testReplaceCmdMap(self):
3538 """Test replacing a file fron an image on the command line"""
3539 self._DoReadFileRealDtb('143_replace_all.dts')
3540
3541 try:
3542 tmpdir, updated_fname = self._SetupImageInTmpdir()
3543
3544 fname = os.path.join(self._indir, 'update-u-boot.bin')
3545 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003546 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003547
3548 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3549 '-f', fname, '-m')
3550 map_fname = os.path.join(tmpdir, 'image-updated.map')
3551 self.assertTrue(os.path.exists(map_fname))
3552 finally:
3553 shutil.rmtree(tmpdir)
3554
3555 def testReplaceNoEntryPaths(self):
3556 """Test replacing an entry without an entry path"""
3557 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003558 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003559 with self.assertRaises(ValueError) as e:
3560 control.ReplaceEntries(image_fname, 'fname', None, [])
3561 self.assertIn('Must specify an entry path to read with -f',
3562 str(e.exception))
3563
3564 def testReplaceTooManyEntryPaths(self):
3565 """Test extracting some entries"""
3566 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003567 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003568 with self.assertRaises(ValueError) as e:
3569 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3570 self.assertIn('Must specify exactly one entry path to write with -f',
3571 str(e.exception))
3572
Simon Glass0b074d62019-08-24 07:22:48 -06003573 def testPackReset16(self):
3574 """Test that an image with an x86 reset16 region can be created"""
3575 data = self._DoReadFile('144_x86_reset16.dts')
3576 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3577
3578 def testPackReset16Spl(self):
3579 """Test that an image with an x86 reset16-spl region can be created"""
3580 data = self._DoReadFile('145_x86_reset16_spl.dts')
3581 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3582
3583 def testPackReset16Tpl(self):
3584 """Test that an image with an x86 reset16-tpl region can be created"""
3585 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3586 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3587
Simon Glass232f90c2019-08-24 07:22:50 -06003588 def testPackIntelFit(self):
3589 """Test that an image with an Intel FIT and pointer can be created"""
3590 data = self._DoReadFile('147_intel_fit.dts')
3591 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3592 fit = data[16:32];
3593 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3594 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3595
3596 image = control.images['image']
3597 entries = image.GetEntries()
3598 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3599 self.assertEqual(expected_ptr, ptr)
3600
3601 def testPackIntelFitMissing(self):
3602 """Test detection of a FIT pointer with not FIT region"""
3603 with self.assertRaises(ValueError) as e:
3604 self._DoReadFile('148_intel_fit_missing.dts')
3605 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3606 str(e.exception))
3607
Simon Glass72555fa2019-11-06 17:22:44 -07003608 def _CheckSymbolsTplSection(self, dts, expected_vals):
3609 data = self._DoReadFile(dts)
3610 sym_values = struct.pack('<LQLL', *expected_vals)
Simon Glass3eb5b202019-08-24 07:23:00 -06003611 upto1 = 4 + len(U_BOOT_SPL_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003612 expected1 = tools.get_bytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[20:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003613 self.assertEqual(expected1, data[:upto1])
3614
3615 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003616 expected2 = tools.get_bytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[20:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003617 self.assertEqual(expected2, data[upto1:upto2])
3618
Simon Glass4e353e22019-08-24 07:23:04 -06003619 upto3 = 0x34 + len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003620 expected3 = tools.get_bytes(0xff, 1) + U_BOOT_DATA
Simon Glass3eb5b202019-08-24 07:23:00 -06003621 self.assertEqual(expected3, data[upto2:upto3])
3622
Simon Glass3f8ff012019-08-24 07:23:05 -06003623 expected4 = sym_values + U_BOOT_TPL_DATA[20:]
Simon Glass72555fa2019-11-06 17:22:44 -07003624 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3625
3626 def testSymbolsTplSection(self):
3627 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3628 self._SetupSplElf('u_boot_binman_syms')
3629 self._SetupTplElf('u_boot_binman_syms')
3630 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
3631 [0x04, 0x1c, 0x10 + 0x34, 0x04])
3632
3633 def testSymbolsTplSectionX86(self):
3634 """Test binman can assign symbols in a section with end-at-4gb"""
3635 self._SetupSplElf('u_boot_binman_syms_x86')
3636 self._SetupTplElf('u_boot_binman_syms_x86')
3637 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
3638 [0xffffff04, 0xffffff1c, 0xffffff34,
3639 0x04])
Simon Glass3eb5b202019-08-24 07:23:00 -06003640
Simon Glass98c59572019-08-24 07:23:03 -06003641 def testPackX86RomIfwiSectiom(self):
3642 """Test that a section can be placed in an IFWI region"""
3643 self._SetupIfwi('fitimage.bin')
3644 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3645 self._CheckIfwi(data)
3646
Simon Glassba7985d2019-08-24 07:23:07 -06003647 def testPackFspM(self):
3648 """Test that an image with a FSP memory-init binary can be created"""
3649 data = self._DoReadFile('152_intel_fsp_m.dts')
3650 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3651
Simon Glass4d9086d2019-10-20 21:31:35 -06003652 def testPackFspS(self):
3653 """Test that an image with a FSP silicon-init binary can be created"""
3654 data = self._DoReadFile('153_intel_fsp_s.dts')
3655 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassba7985d2019-08-24 07:23:07 -06003656
Simon Glass9ea87b22019-10-20 21:31:36 -06003657 def testPackFspT(self):
3658 """Test that an image with a FSP temp-ram-init binary can be created"""
3659 data = self._DoReadFile('154_intel_fsp_t.dts')
3660 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3661
Simon Glass48f3aad2020-07-09 18:39:31 -06003662 def testMkimage(self):
3663 """Test using mkimage to build an image"""
3664 data = self._DoReadFile('156_mkimage.dts')
3665
3666 # Just check that the data appears in the file somewhere
3667 self.assertIn(U_BOOT_SPL_DATA, data)
3668
Simon Glass66152ce2022-01-09 20:14:09 -07003669 def testMkimageMissing(self):
3670 """Test that binman still produces an image if mkimage is missing"""
3671 with test_util.capture_sys_output() as (_, stderr):
3672 self._DoTestFile('156_mkimage.dts',
3673 force_missing_bintools='mkimage')
3674 err = stderr.getvalue()
3675 self.assertRegex(err,
3676 "Image 'main-section'.*missing bintools.*: mkimage")
3677
Simon Glass5e560182020-07-09 18:39:36 -06003678 def testExtblob(self):
3679 """Test an image with an external blob"""
3680 data = self._DoReadFile('157_blob_ext.dts')
3681 self.assertEqual(REFCODE_DATA, data)
3682
3683 def testExtblobMissing(self):
3684 """Test an image with a missing external blob"""
3685 with self.assertRaises(ValueError) as e:
3686 self._DoReadFile('158_blob_ext_missing.dts')
3687 self.assertIn("Filename 'missing-file' not found in input path",
3688 str(e.exception))
3689
Simon Glass5d94cc62020-07-09 18:39:38 -06003690 def testExtblobMissingOk(self):
3691 """Test an image with an missing external blob that is allowed"""
Simon Glassa003cd32020-07-09 18:39:40 -06003692 with test_util.capture_sys_output() as (stdout, stderr):
3693 self._DoTestFile('158_blob_ext_missing.dts', allow_missing=True)
3694 err = stderr.getvalue()
3695 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
3696
3697 def testExtblobMissingOkSect(self):
3698 """Test an image with an missing external blob that is allowed"""
3699 with test_util.capture_sys_output() as (stdout, stderr):
3700 self._DoTestFile('159_blob_ext_missing_sect.dts',
3701 allow_missing=True)
3702 err = stderr.getvalue()
3703 self.assertRegex(err, "Image 'main-section'.*missing.*: "
3704 "blob-ext blob-ext2")
Simon Glass5d94cc62020-07-09 18:39:38 -06003705
Simon Glasse88cef92020-07-09 18:39:41 -06003706 def testPackX86RomMeMissingDesc(self):
3707 """Test that an missing Intel descriptor entry is allowed"""
Simon Glasse88cef92020-07-09 18:39:41 -06003708 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass14c596c2020-07-25 15:11:19 -06003709 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glasse88cef92020-07-09 18:39:41 -06003710 err = stderr.getvalue()
3711 self.assertRegex(err,
3712 "Image 'main-section'.*missing.*: intel-descriptor")
3713
3714 def testPackX86RomMissingIfwi(self):
3715 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3716 self._SetupIfwi('fitimage.bin')
3717 pathname = os.path.join(self._indir, 'fitimage.bin')
3718 os.remove(pathname)
3719 with test_util.capture_sys_output() as (stdout, stderr):
3720 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3721 err = stderr.getvalue()
3722 self.assertRegex(err, "Image 'main-section'.*missing.*: intel-ifwi")
3723
Simon Glass2a0fa982022-02-11 13:23:21 -07003724 def testPackOverlapZero(self):
Simon Glassd70829a2020-07-09 18:39:42 -06003725 """Test that zero-size overlapping regions are ignored"""
3726 self._DoTestFile('160_pack_overlap_zero.dts')
3727
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003728 def _CheckSimpleFitData(self, fit_data, kernel_data, fdt1_data):
Simon Glass45d556d2020-07-09 18:39:45 -06003729 # The data should be inside the FIT
3730 dtb = fdt.Fdt.FromData(fit_data)
3731 dtb.Scan()
3732 fnode = dtb.GetNode('/images/kernel')
3733 self.assertIn('data', fnode.props)
3734
3735 fname = os.path.join(self._indir, 'fit_data.fit')
Simon Glass80025522022-01-29 14:14:04 -07003736 tools.write_file(fname, fit_data)
3737 out = tools.run('dumpimage', '-l', fname)
Simon Glass45d556d2020-07-09 18:39:45 -06003738
3739 # Check a few features to make sure the plumbing works. We don't need
3740 # to test the operation of mkimage or dumpimage here. First convert the
3741 # output into a dict where the keys are the fields printed by dumpimage
3742 # and the values are a list of values for each field
3743 lines = out.splitlines()
3744
3745 # Converts "Compression: gzip compressed" into two groups:
3746 # 'Compression' and 'gzip compressed'
3747 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3748 vals = collections.defaultdict(list)
3749 for line in lines:
3750 mat = re_line.match(line)
3751 vals[mat.group(1)].append(mat.group(2))
3752
3753 self.assertEquals('FIT description: test-desc', lines[0])
3754 self.assertIn('Created:', lines[1])
3755 self.assertIn('Image 0 (kernel)', vals)
3756 self.assertIn('Hash value', vals)
3757 data_sizes = vals.get('Data Size')
3758 self.assertIsNotNone(data_sizes)
3759 self.assertEqual(2, len(data_sizes))
3760 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003761 self.assertEqual(len(kernel_data), int(data_sizes[0].split()[0]))
3762 self.assertEqual(len(fdt1_data), int(data_sizes[1].split()[0]))
3763
3764 def testSimpleFit(self):
3765 """Test an image with a FIT inside"""
3766 data = self._DoReadFile('161_fit.dts')
3767 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3768 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3769 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3770
3771 self._CheckSimpleFitData(fit_data, U_BOOT_DATA, U_BOOT_SPL_DTB_DATA)
3772
3773 def testSimpleFitExpandsSubentries(self):
3774 """Test that FIT images expand their subentries"""
3775 data = self._DoReadFileDtb('161_fit.dts', use_expanded=True)[0]
3776 self.assertEqual(U_BOOT_EXP_DATA, data[:len(U_BOOT_EXP_DATA)])
3777 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3778 fit_data = data[len(U_BOOT_EXP_DATA):-len(U_BOOT_NODTB_DATA)]
3779
3780 self._CheckSimpleFitData(fit_data, U_BOOT_EXP_DATA, U_BOOT_SPL_DTB_DATA)
Simon Glass45d556d2020-07-09 18:39:45 -06003781
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003782 def testSimpleFitImagePos(self):
3783 """Test that we have correct image-pos for FIT subentries"""
3784 data, _, _, out_dtb_fname = self._DoReadFileDtb('161_fit.dts',
3785 update_dtb=True)
3786 dtb = fdt.Fdt(out_dtb_fname)
3787 dtb.Scan()
3788 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3789
Simon Glassb7bad182022-03-05 20:19:01 -07003790 self.maxDiff = None
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003791 self.assertEqual({
3792 'image-pos': 0,
3793 'offset': 0,
3794 'size': 1890,
3795
3796 'u-boot:image-pos': 0,
3797 'u-boot:offset': 0,
3798 'u-boot:size': 4,
3799
3800 'fit:image-pos': 4,
3801 'fit:offset': 4,
3802 'fit:size': 1840,
3803
Simon Glassb7bad182022-03-05 20:19:01 -07003804 'fit/images/kernel:image-pos': 304,
3805 'fit/images/kernel:offset': 300,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003806 'fit/images/kernel:size': 4,
3807
Simon Glassb7bad182022-03-05 20:19:01 -07003808 'fit/images/kernel/u-boot:image-pos': 304,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003809 'fit/images/kernel/u-boot:offset': 0,
3810 'fit/images/kernel/u-boot:size': 4,
3811
Simon Glassb7bad182022-03-05 20:19:01 -07003812 'fit/images/fdt-1:image-pos': 552,
3813 'fit/images/fdt-1:offset': 548,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003814 'fit/images/fdt-1:size': 6,
3815
Simon Glassb7bad182022-03-05 20:19:01 -07003816 'fit/images/fdt-1/u-boot-spl-dtb:image-pos': 552,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003817 'fit/images/fdt-1/u-boot-spl-dtb:offset': 0,
3818 'fit/images/fdt-1/u-boot-spl-dtb:size': 6,
3819
3820 'u-boot-nodtb:image-pos': 1844,
3821 'u-boot-nodtb:offset': 1844,
3822 'u-boot-nodtb:size': 46,
3823 }, props)
3824
3825 # Actually check the data is where we think it is
3826 for node, expected in [
3827 ("u-boot", U_BOOT_DATA),
3828 ("fit/images/kernel", U_BOOT_DATA),
3829 ("fit/images/kernel/u-boot", U_BOOT_DATA),
3830 ("fit/images/fdt-1", U_BOOT_SPL_DTB_DATA),
3831 ("fit/images/fdt-1/u-boot-spl-dtb", U_BOOT_SPL_DTB_DATA),
3832 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
3833 ]:
3834 image_pos = props[f"{node}:image-pos"]
3835 size = props[f"{node}:size"]
3836 self.assertEqual(len(expected), size)
3837 self.assertEqual(expected, data[image_pos:image_pos+size])
3838
Simon Glass45d556d2020-07-09 18:39:45 -06003839 def testFitExternal(self):
Simon Glass31ee50f2020-09-01 05:13:55 -06003840 """Test an image with an FIT with external images"""
Simon Glass45d556d2020-07-09 18:39:45 -06003841 data = self._DoReadFile('162_fit_external.dts')
3842 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3843
Simon Glass7932c882022-01-09 20:13:39 -07003844 # Size of the external-data region as set up by mkimage
3845 external_data_size = len(U_BOOT_DATA) + 2
3846 expected_size = (len(U_BOOT_DATA) + 0x400 +
Simon Glass80025522022-01-29 14:14:04 -07003847 tools.align(external_data_size, 4) +
Simon Glass7932c882022-01-09 20:13:39 -07003848 len(U_BOOT_NODTB_DATA))
3849
Simon Glass45d556d2020-07-09 18:39:45 -06003850 # The data should be outside the FIT
3851 dtb = fdt.Fdt.FromData(fit_data)
3852 dtb.Scan()
3853 fnode = dtb.GetNode('/images/kernel')
3854 self.assertNotIn('data', fnode.props)
Simon Glass7932c882022-01-09 20:13:39 -07003855 self.assertEqual(len(U_BOOT_DATA),
3856 fdt_util.fdt32_to_cpu(fnode.props['data-size'].value))
3857 fit_pos = 0x400;
3858 self.assertEqual(
3859 fit_pos,
3860 fdt_util.fdt32_to_cpu(fnode.props['data-position'].value))
3861
3862 self.assertEquals(expected_size, len(data))
3863 actual_pos = len(U_BOOT_DATA) + fit_pos
3864 self.assertEqual(U_BOOT_DATA + b'aa',
3865 data[actual_pos:actual_pos + external_data_size])
Simon Glassfb30e292019-07-20 12:23:51 -06003866
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003867 def testFitExternalImagePos(self):
3868 """Test that we have correct image-pos for external FIT subentries"""
3869 data, _, _, out_dtb_fname = self._DoReadFileDtb('162_fit_external.dts',
3870 update_dtb=True)
3871 dtb = fdt.Fdt(out_dtb_fname)
3872 dtb.Scan()
3873 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3874
3875 self.assertEqual({
3876 'image-pos': 0,
3877 'offset': 0,
3878 'size': 1082,
3879
3880 'u-boot:image-pos': 0,
3881 'u-boot:offset': 0,
3882 'u-boot:size': 4,
3883
3884 'fit:size': 1032,
3885 'fit:offset': 4,
3886 'fit:image-pos': 4,
3887
3888 'fit/images/kernel:size': 4,
3889 'fit/images/kernel:offset': 1024,
3890 'fit/images/kernel:image-pos': 1028,
3891
3892 'fit/images/kernel/u-boot:size': 4,
3893 'fit/images/kernel/u-boot:offset': 0,
3894 'fit/images/kernel/u-boot:image-pos': 1028,
3895
3896 'fit/images/fdt-1:size': 2,
3897 'fit/images/fdt-1:offset': 1028,
3898 'fit/images/fdt-1:image-pos': 1032,
3899
3900 'fit/images/fdt-1/_testing:size': 2,
3901 'fit/images/fdt-1/_testing:offset': 0,
3902 'fit/images/fdt-1/_testing:image-pos': 1032,
3903
3904 'u-boot-nodtb:image-pos': 1036,
3905 'u-boot-nodtb:offset': 1036,
3906 'u-boot-nodtb:size': 46,
3907 }, props)
3908
3909 # Actually check the data is where we think it is
3910 for node, expected in [
3911 ("u-boot", U_BOOT_DATA),
3912 ("fit/images/kernel", U_BOOT_DATA),
3913 ("fit/images/kernel/u-boot", U_BOOT_DATA),
3914 ("fit/images/fdt-1", b'aa'),
3915 ("fit/images/fdt-1/_testing", b'aa'),
3916 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
3917 ]:
3918 image_pos = props[f"{node}:image-pos"]
3919 size = props[f"{node}:size"]
3920 self.assertEqual(len(expected), size)
3921 self.assertEqual(expected, data[image_pos:image_pos+size])
3922
Simon Glass66152ce2022-01-09 20:14:09 -07003923 def testFitMissing(self):
3924 """Test that binman still produces a FIT image if mkimage is missing"""
3925 with test_util.capture_sys_output() as (_, stderr):
3926 self._DoTestFile('162_fit_external.dts',
3927 force_missing_bintools='mkimage')
3928 err = stderr.getvalue()
3929 self.assertRegex(err,
3930 "Image 'main-section'.*missing bintools.*: mkimage")
3931
Alper Nebi Yasak6aae2392020-08-31 12:58:18 +03003932 def testSectionIgnoreHashSignature(self):
3933 """Test that sections ignore hash, signature nodes for its data"""
3934 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
3935 expected = (U_BOOT_DATA + U_BOOT_DATA)
3936 self.assertEqual(expected, data)
3937
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03003938 def testPadInSections(self):
3939 """Test pad-before, pad-after for entries in sections"""
Simon Glassd12599d2020-10-26 17:40:09 -06003940 data, _, _, out_dtb_fname = self._DoReadFileDtb(
3941 '166_pad_in_sections.dts', update_dtb=True)
Simon Glass80025522022-01-29 14:14:04 -07003942 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
3943 U_BOOT_DATA + tools.get_bytes(ord('!'), 6) +
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03003944 U_BOOT_DATA)
3945 self.assertEqual(expected, data)
3946
Simon Glassd12599d2020-10-26 17:40:09 -06003947 dtb = fdt.Fdt(out_dtb_fname)
3948 dtb.Scan()
3949 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
3950 expected = {
3951 'image-pos': 0,
3952 'offset': 0,
3953 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
3954
3955 'section:image-pos': 0,
3956 'section:offset': 0,
3957 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
3958
3959 'section/before:image-pos': 0,
3960 'section/before:offset': 0,
3961 'section/before:size': len(U_BOOT_DATA),
3962
3963 'section/u-boot:image-pos': 4,
3964 'section/u-boot:offset': 4,
3965 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
3966
3967 'section/after:image-pos': 26,
3968 'section/after:offset': 26,
3969 'section/after:size': len(U_BOOT_DATA),
3970 }
3971 self.assertEqual(expected, props)
3972
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03003973 def testFitImageSubentryAlignment(self):
3974 """Test relative alignability of FIT image subentries"""
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03003975 self._SetupSplElf()
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03003976 entry_args = {
3977 'test-id': TEXT_DATA,
3978 }
3979 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
3980 entry_args=entry_args)
3981 dtb = fdt.Fdt.FromData(data)
3982 dtb.Scan()
3983
3984 node = dtb.GetNode('/images/kernel')
3985 data = dtb.GetProps(node)["data"].bytes
3986 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
Simon Glass80025522022-01-29 14:14:04 -07003987 expected = (tools.get_bytes(0, 0x20) + U_BOOT_SPL_DATA +
3988 tools.get_bytes(0, align_pad) + U_BOOT_DATA)
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03003989 self.assertEqual(expected, data)
3990
3991 node = dtb.GetNode('/images/fdt-1')
3992 data = dtb.GetProps(node)["data"].bytes
Simon Glass80025522022-01-29 14:14:04 -07003993 expected = (U_BOOT_SPL_DTB_DATA + tools.get_bytes(0, 20) +
3994 tools.to_bytes(TEXT_DATA) + tools.get_bytes(0, 30) +
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03003995 U_BOOT_DTB_DATA)
3996 self.assertEqual(expected, data)
3997
3998 def testFitExtblobMissingOk(self):
3999 """Test a FIT with a missing external blob that is allowed"""
4000 with test_util.capture_sys_output() as (stdout, stderr):
4001 self._DoTestFile('168_fit_missing_blob.dts',
4002 allow_missing=True)
4003 err = stderr.getvalue()
Simon Glassa820af72020-09-06 10:39:09 -06004004 self.assertRegex(err, "Image 'main-section'.*missing.*: atf-bl31")
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004005
Simon Glass21db0ff2020-09-01 05:13:54 -06004006 def testBlobNamedByArgMissing(self):
4007 """Test handling of a missing entry arg"""
4008 with self.assertRaises(ValueError) as e:
4009 self._DoReadFile('068_blob_named_by_arg.dts')
4010 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
4011 str(e.exception))
4012
Simon Glass559c4de2020-09-01 05:13:58 -06004013 def testPackBl31(self):
4014 """Test that an image with an ATF BL31 binary can be created"""
4015 data = self._DoReadFile('169_atf_bl31.dts')
4016 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
4017
Samuel Holland9d8cc632020-10-21 21:12:15 -05004018 def testPackScp(self):
4019 """Test that an image with an SCP binary can be created"""
4020 data = self._DoReadFile('172_scp.dts')
4021 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
4022
Simon Glassa435cd12020-09-01 05:13:59 -06004023 def testFitFdt(self):
4024 """Test an image with an FIT with multiple FDT images"""
4025 def _CheckFdt(seq, expected_data):
4026 """Check the FDT nodes
4027
4028 Args:
4029 seq: Sequence number to check (0 or 1)
4030 expected_data: Expected contents of 'data' property
4031 """
4032 name = 'fdt-%d' % seq
4033 fnode = dtb.GetNode('/images/%s' % name)
4034 self.assertIsNotNone(fnode)
4035 self.assertEqual({'description','type', 'compression', 'data'},
4036 set(fnode.props.keys()))
4037 self.assertEqual(expected_data, fnode.props['data'].bytes)
4038 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
4039 fnode.props['description'].value)
Jan Kiszkaa1419df2022-02-28 17:06:20 +01004040 self.assertEqual(fnode.subnodes[0].name, 'hash')
Simon Glassa435cd12020-09-01 05:13:59 -06004041
4042 def _CheckConfig(seq, expected_data):
4043 """Check the configuration nodes
4044
4045 Args:
4046 seq: Sequence number to check (0 or 1)
4047 expected_data: Expected contents of 'data' property
4048 """
4049 cnode = dtb.GetNode('/configurations')
4050 self.assertIn('default', cnode.props)
Simon Glass1032acc2020-09-06 10:39:08 -06004051 self.assertEqual('config-2', cnode.props['default'].value)
Simon Glassa435cd12020-09-01 05:13:59 -06004052
4053 name = 'config-%d' % seq
4054 fnode = dtb.GetNode('/configurations/%s' % name)
4055 self.assertIsNotNone(fnode)
4056 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
4057 set(fnode.props.keys()))
4058 self.assertEqual('conf-test-fdt%d.dtb' % seq,
4059 fnode.props['description'].value)
4060 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
4061
4062 entry_args = {
4063 'of-list': 'test-fdt1 test-fdt2',
Simon Glass1032acc2020-09-06 10:39:08 -06004064 'default-dt': 'test-fdt2',
Simon Glassa435cd12020-09-01 05:13:59 -06004065 }
4066 data = self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004067 '170_fit_fdt.dts',
Simon Glassa435cd12020-09-01 05:13:59 -06004068 entry_args=entry_args,
4069 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4070 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4071 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4072
4073 dtb = fdt.Fdt.FromData(fit_data)
4074 dtb.Scan()
4075 fnode = dtb.GetNode('/images/kernel')
4076 self.assertIn('data', fnode.props)
4077
4078 # Check all the properties in fdt-1 and fdt-2
4079 _CheckFdt(1, TEST_FDT1_DATA)
4080 _CheckFdt(2, TEST_FDT2_DATA)
4081
4082 # Check configurations
4083 _CheckConfig(1, TEST_FDT1_DATA)
4084 _CheckConfig(2, TEST_FDT2_DATA)
4085
4086 def testFitFdtMissingList(self):
4087 """Test handling of a missing 'of-list' entry arg"""
4088 with self.assertRaises(ValueError) as e:
Bin Meng16cf5662021-05-10 20:23:32 +08004089 self._DoReadFile('170_fit_fdt.dts')
Simon Glassa435cd12020-09-01 05:13:59 -06004090 self.assertIn("Generator node requires 'of-list' entry argument",
4091 str(e.exception))
4092
4093 def testFitFdtEmptyList(self):
4094 """Test handling of an empty 'of-list' entry arg"""
4095 entry_args = {
4096 'of-list': '',
4097 }
4098 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
4099
4100 def testFitFdtMissingProp(self):
4101 """Test handling of a missing 'fit,fdt-list' property"""
4102 with self.assertRaises(ValueError) as e:
4103 self._DoReadFile('171_fit_fdt_missing_prop.dts')
4104 self.assertIn("Generator node requires 'fit,fdt-list' property",
4105 str(e.exception))
Simon Glass559c4de2020-09-01 05:13:58 -06004106
Simon Glass1032acc2020-09-06 10:39:08 -06004107 def testFitFdtMissing(self):
4108 """Test handling of a missing 'default-dt' entry arg"""
4109 entry_args = {
4110 'of-list': 'test-fdt1 test-fdt2',
4111 }
4112 with self.assertRaises(ValueError) as e:
4113 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004114 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004115 entry_args=entry_args,
4116 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4117 self.assertIn("Generated 'default' node requires default-dt entry argument",
4118 str(e.exception))
4119
4120 def testFitFdtNotInList(self):
4121 """Test handling of a default-dt that is not in the of-list"""
4122 entry_args = {
4123 'of-list': 'test-fdt1 test-fdt2',
4124 'default-dt': 'test-fdt3',
4125 }
4126 with self.assertRaises(ValueError) as e:
4127 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004128 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004129 entry_args=entry_args,
4130 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4131 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
4132 str(e.exception))
4133
Simon Glassa820af72020-09-06 10:39:09 -06004134 def testFitExtblobMissingHelp(self):
4135 """Test display of help messages when an external blob is missing"""
4136 control.missing_blob_help = control._ReadMissingBlobHelp()
4137 control.missing_blob_help['wibble'] = 'Wibble test'
4138 control.missing_blob_help['another'] = 'Another test'
4139 with test_util.capture_sys_output() as (stdout, stderr):
4140 self._DoTestFile('168_fit_missing_blob.dts',
4141 allow_missing=True)
4142 err = stderr.getvalue()
4143
4144 # We can get the tag from the name, the type or the missing-msg
4145 # property. Check all three.
4146 self.assertIn('You may need to build ARM Trusted', err)
4147 self.assertIn('Wibble test', err)
4148 self.assertIn('Another test', err)
4149
Simon Glass6f1f4d42020-09-06 10:35:32 -06004150 def testMissingBlob(self):
4151 """Test handling of a blob containing a missing file"""
4152 with self.assertRaises(ValueError) as e:
4153 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
4154 self.assertIn("Filename 'missing' not found in input path",
4155 str(e.exception))
4156
Simon Glassa0729502020-09-06 10:35:33 -06004157 def testEnvironment(self):
4158 """Test adding a U-Boot environment"""
4159 data = self._DoReadFile('174_env.dts')
4160 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
4161 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4162 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4163 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
4164 env)
4165
4166 def testEnvironmentNoSize(self):
4167 """Test that a missing 'size' property is detected"""
4168 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004169 self._DoTestFile('175_env_no_size.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004170 self.assertIn("'u-boot-env' entry must have a size property",
4171 str(e.exception))
4172
4173 def testEnvironmentTooSmall(self):
4174 """Test handling of an environment that does not fit"""
4175 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004176 self._DoTestFile('176_env_too_small.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004177
4178 # checksum, start byte, environment with \0 terminator, final \0
4179 need = 4 + 1 + len(ENV_DATA) + 1 + 1
4180 short = need - 0x8
4181 self.assertIn("too small to hold data (need %#x more bytes)" % short,
4182 str(e.exception))
4183
Simon Glassd1fdf752020-10-26 17:40:01 -06004184 def testSkipAtStart(self):
4185 """Test handling of skip-at-start section"""
4186 data = self._DoReadFile('177_skip_at_start.dts')
4187 self.assertEqual(U_BOOT_DATA, data)
4188
4189 image = control.images['image']
4190 entries = image.GetEntries()
4191 section = entries['section']
4192 self.assertEqual(0, section.offset)
4193 self.assertEqual(len(U_BOOT_DATA), section.size)
4194 self.assertEqual(U_BOOT_DATA, section.GetData())
4195
4196 entry = section.GetEntries()['u-boot']
4197 self.assertEqual(16, entry.offset)
4198 self.assertEqual(len(U_BOOT_DATA), entry.size)
4199 self.assertEqual(U_BOOT_DATA, entry.data)
4200
4201 def testSkipAtStartPad(self):
4202 """Test handling of skip-at-start section with padded entry"""
4203 data = self._DoReadFile('178_skip_at_start_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004204 before = tools.get_bytes(0, 8)
4205 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004206 all = before + U_BOOT_DATA + after
4207 self.assertEqual(all, data)
4208
4209 image = control.images['image']
4210 entries = image.GetEntries()
4211 section = entries['section']
4212 self.assertEqual(0, section.offset)
4213 self.assertEqual(len(all), section.size)
4214 self.assertEqual(all, section.GetData())
4215
4216 entry = section.GetEntries()['u-boot']
4217 self.assertEqual(16, entry.offset)
4218 self.assertEqual(len(all), entry.size)
4219 self.assertEqual(U_BOOT_DATA, entry.data)
4220
4221 def testSkipAtStartSectionPad(self):
4222 """Test handling of skip-at-start section with padding"""
4223 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004224 before = tools.get_bytes(0, 8)
4225 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004226 all = before + U_BOOT_DATA + after
Simon Glass510ef0f2020-10-26 17:40:13 -06004227 self.assertEqual(all, data)
Simon Glassd1fdf752020-10-26 17:40:01 -06004228
4229 image = control.images['image']
4230 entries = image.GetEntries()
4231 section = entries['section']
4232 self.assertEqual(0, section.offset)
4233 self.assertEqual(len(all), section.size)
Simon Glass72eeff12020-10-26 17:40:16 -06004234 self.assertEqual(U_BOOT_DATA, section.data)
Simon Glass510ef0f2020-10-26 17:40:13 -06004235 self.assertEqual(all, section.GetPaddedData())
Simon Glassd1fdf752020-10-26 17:40:01 -06004236
4237 entry = section.GetEntries()['u-boot']
4238 self.assertEqual(16, entry.offset)
4239 self.assertEqual(len(U_BOOT_DATA), entry.size)
4240 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassa0729502020-09-06 10:35:33 -06004241
Simon Glassbb395742020-10-26 17:40:14 -06004242 def testSectionPad(self):
4243 """Testing padding with sections"""
4244 data = self._DoReadFile('180_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004245 expected = (tools.get_bytes(ord('&'), 3) +
4246 tools.get_bytes(ord('!'), 5) +
Simon Glassbb395742020-10-26 17:40:14 -06004247 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004248 tools.get_bytes(ord('!'), 1) +
4249 tools.get_bytes(ord('&'), 2))
Simon Glassbb395742020-10-26 17:40:14 -06004250 self.assertEqual(expected, data)
4251
4252 def testSectionAlign(self):
4253 """Testing alignment with sections"""
4254 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4255 expected = (b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004256 tools.get_bytes(ord('&'), 1) + # padding to section align
Simon Glassbb395742020-10-26 17:40:14 -06004257 b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004258 tools.get_bytes(ord('!'), 3) + # padding to u-boot align
Simon Glassbb395742020-10-26 17:40:14 -06004259 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004260 tools.get_bytes(ord('!'), 4) + # padding to u-boot size
4261 tools.get_bytes(ord('!'), 4)) # padding to section size
Simon Glassbb395742020-10-26 17:40:14 -06004262 self.assertEqual(expected, data)
4263
Simon Glassd92c8362020-10-26 17:40:25 -06004264 def testCompressImage(self):
4265 """Test compression of the entire image"""
4266 self._CheckLz4()
4267 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4268 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4269 dtb = fdt.Fdt(out_dtb_fname)
4270 dtb.Scan()
4271 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4272 'uncomp-size'])
4273 orig = self._decompress(data)
4274 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4275
4276 # Do a sanity check on various fields
4277 image = control.images['image']
4278 entries = image.GetEntries()
4279 self.assertEqual(2, len(entries))
4280
4281 entry = entries['blob']
4282 self.assertEqual(COMPRESS_DATA, entry.data)
4283 self.assertEqual(len(COMPRESS_DATA), entry.size)
4284
4285 entry = entries['u-boot']
4286 self.assertEqual(U_BOOT_DATA, entry.data)
4287 self.assertEqual(len(U_BOOT_DATA), entry.size)
4288
4289 self.assertEqual(len(data), image.size)
4290 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4291 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4292 orig = self._decompress(image.data)
4293 self.assertEqual(orig, image.uncomp_data)
4294
4295 expected = {
4296 'blob:offset': 0,
4297 'blob:size': len(COMPRESS_DATA),
4298 'u-boot:offset': len(COMPRESS_DATA),
4299 'u-boot:size': len(U_BOOT_DATA),
4300 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4301 'offset': 0,
4302 'image-pos': 0,
4303 'size': len(data),
4304 }
4305 self.assertEqual(expected, props)
4306
4307 def testCompressImageLess(self):
4308 """Test compression where compression reduces the image size"""
4309 self._CheckLz4()
4310 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4311 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4312 dtb = fdt.Fdt(out_dtb_fname)
4313 dtb.Scan()
4314 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4315 'uncomp-size'])
4316 orig = self._decompress(data)
4317
4318 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
4319
4320 # Do a sanity check on various fields
4321 image = control.images['image']
4322 entries = image.GetEntries()
4323 self.assertEqual(2, len(entries))
4324
4325 entry = entries['blob']
4326 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4327 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4328
4329 entry = entries['u-boot']
4330 self.assertEqual(U_BOOT_DATA, entry.data)
4331 self.assertEqual(len(U_BOOT_DATA), entry.size)
4332
4333 self.assertEqual(len(data), image.size)
4334 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4335 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4336 image.uncomp_size)
4337 orig = self._decompress(image.data)
4338 self.assertEqual(orig, image.uncomp_data)
4339
4340 expected = {
4341 'blob:offset': 0,
4342 'blob:size': len(COMPRESS_DATA_BIG),
4343 'u-boot:offset': len(COMPRESS_DATA_BIG),
4344 'u-boot:size': len(U_BOOT_DATA),
4345 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4346 'offset': 0,
4347 'image-pos': 0,
4348 'size': len(data),
4349 }
4350 self.assertEqual(expected, props)
4351
4352 def testCompressSectionSize(self):
4353 """Test compression of a section with a fixed size"""
4354 self._CheckLz4()
4355 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4356 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4357 dtb = fdt.Fdt(out_dtb_fname)
4358 dtb.Scan()
4359 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4360 'uncomp-size'])
4361 orig = self._decompress(data)
4362 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4363 expected = {
4364 'section/blob:offset': 0,
4365 'section/blob:size': len(COMPRESS_DATA),
4366 'section/u-boot:offset': len(COMPRESS_DATA),
4367 'section/u-boot:size': len(U_BOOT_DATA),
4368 'section:offset': 0,
4369 'section:image-pos': 0,
4370 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4371 'section:size': 0x30,
4372 'offset': 0,
4373 'image-pos': 0,
4374 'size': 0x30,
4375 }
4376 self.assertEqual(expected, props)
4377
4378 def testCompressSection(self):
4379 """Test compression of a section with no fixed size"""
4380 self._CheckLz4()
4381 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4382 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4383 dtb = fdt.Fdt(out_dtb_fname)
4384 dtb.Scan()
4385 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4386 'uncomp-size'])
4387 orig = self._decompress(data)
4388 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4389 expected = {
4390 'section/blob:offset': 0,
4391 'section/blob:size': len(COMPRESS_DATA),
4392 'section/u-boot:offset': len(COMPRESS_DATA),
4393 'section/u-boot:size': len(U_BOOT_DATA),
4394 'section:offset': 0,
4395 'section:image-pos': 0,
4396 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4397 'section:size': len(data),
4398 'offset': 0,
4399 'image-pos': 0,
4400 'size': len(data),
4401 }
4402 self.assertEqual(expected, props)
4403
4404 def testCompressExtra(self):
4405 """Test compression of a section with no fixed size"""
4406 self._CheckLz4()
4407 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4408 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4409 dtb = fdt.Fdt(out_dtb_fname)
4410 dtb.Scan()
4411 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4412 'uncomp-size'])
4413
4414 base = data[len(U_BOOT_DATA):]
4415 self.assertEquals(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
4416 rest = base[len(U_BOOT_DATA):]
4417
4418 # Check compressed data
4419 section1 = self._decompress(rest)
Simon Glassdd5c14ec2022-01-09 20:14:04 -07004420 expect1 = comp_util.compress(COMPRESS_DATA + U_BOOT_DATA, 'lz4')
Simon Glassd92c8362020-10-26 17:40:25 -06004421 self.assertEquals(expect1, rest[:len(expect1)])
4422 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, section1)
4423 rest1 = rest[len(expect1):]
4424
4425 section2 = self._decompress(rest1)
Simon Glassdd5c14ec2022-01-09 20:14:04 -07004426 expect2 = comp_util.compress(COMPRESS_DATA + COMPRESS_DATA, 'lz4')
Simon Glassd92c8362020-10-26 17:40:25 -06004427 self.assertEquals(expect2, rest1[:len(expect2)])
4428 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA, section2)
4429 rest2 = rest1[len(expect2):]
4430
4431 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4432 len(expect2) + len(U_BOOT_DATA))
4433 #self.assertEquals(expect_size, len(data))
4434
4435 #self.assertEquals(U_BOOT_DATA, rest2)
4436
4437 self.maxDiff = None
4438 expected = {
4439 'u-boot:offset': 0,
4440 'u-boot:image-pos': 0,
4441 'u-boot:size': len(U_BOOT_DATA),
4442
4443 'base:offset': len(U_BOOT_DATA),
4444 'base:image-pos': len(U_BOOT_DATA),
4445 'base:size': len(data) - len(U_BOOT_DATA),
4446 'base/u-boot:offset': 0,
4447 'base/u-boot:image-pos': len(U_BOOT_DATA),
4448 'base/u-boot:size': len(U_BOOT_DATA),
4449 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4450 len(expect2),
4451 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4452 len(expect2),
4453 'base/u-boot2:size': len(U_BOOT_DATA),
4454
4455 'base/section:offset': len(U_BOOT_DATA),
4456 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4457 'base/section:size': len(expect1),
4458 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4459 'base/section/blob:offset': 0,
4460 'base/section/blob:size': len(COMPRESS_DATA),
4461 'base/section/u-boot:offset': len(COMPRESS_DATA),
4462 'base/section/u-boot:size': len(U_BOOT_DATA),
4463
4464 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4465 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4466 'base/section2:size': len(expect2),
4467 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4468 'base/section2/blob:offset': 0,
4469 'base/section2/blob:size': len(COMPRESS_DATA),
4470 'base/section2/blob2:offset': len(COMPRESS_DATA),
4471 'base/section2/blob2:size': len(COMPRESS_DATA),
4472
4473 'offset': 0,
4474 'image-pos': 0,
4475 'size': len(data),
4476 }
4477 self.assertEqual(expected, props)
4478
Simon Glassecbe4732021-01-06 21:35:15 -07004479 def testSymbolsSubsection(self):
4480 """Test binman can assign symbols from a subsection"""
Simon Glass31e04cb2021-03-18 20:24:56 +13004481 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x18)
Simon Glassecbe4732021-01-06 21:35:15 -07004482
Simon Glass3fb25402021-01-06 21:35:16 -07004483 def testReadImageEntryArg(self):
4484 """Test reading an image that would need an entry arg to generate"""
4485 entry_args = {
4486 'cros-ec-rw-path': 'ecrw.bin',
4487 }
4488 data = self.data = self._DoReadFileDtb(
4489 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4490 entry_args=entry_args)
4491
Simon Glass80025522022-01-29 14:14:04 -07004492 image_fname = tools.get_output_filename('image.bin')
Simon Glass3fb25402021-01-06 21:35:16 -07004493 orig_image = control.images['image']
4494
4495 # This should not generate an error about the missing 'cros-ec-rw-path'
4496 # since we are reading the image from a file. Compare with
4497 # testEntryArgsRequired()
4498 image = Image.FromFile(image_fname)
4499 self.assertEqual(orig_image.GetEntries().keys(),
4500 image.GetEntries().keys())
4501
Simon Glassa2af7302021-01-06 21:35:18 -07004502 def testFilesAlign(self):
4503 """Test alignment with files"""
4504 data = self._DoReadFile('190_files_align.dts')
4505
4506 # The first string is 15 bytes so will align to 16
4507 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4508 self.assertEqual(expect, data)
4509
Simon Glassdb84b562021-01-06 21:35:19 -07004510 def testReadImageSkip(self):
4511 """Test reading an image and accessing its FDT map"""
4512 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
Simon Glass80025522022-01-29 14:14:04 -07004513 image_fname = tools.get_output_filename('image.bin')
Simon Glassdb84b562021-01-06 21:35:19 -07004514 orig_image = control.images['image']
4515 image = Image.FromFile(image_fname)
4516 self.assertEqual(orig_image.GetEntries().keys(),
4517 image.GetEntries().keys())
4518
4519 orig_entry = orig_image.GetEntries()['fdtmap']
4520 entry = image.GetEntries()['fdtmap']
4521 self.assertEqual(orig_entry.offset, entry.offset)
4522 self.assertEqual(orig_entry.size, entry.size)
4523 self.assertEqual(16, entry.image_pos)
4524
4525 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4526
4527 self.assertEquals(U_BOOT_DATA, u_boot.ReadData())
4528
Simon Glassc98de972021-03-18 20:24:57 +13004529 def testTplNoDtb(self):
4530 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12004531 self._SetupTplElf()
Simon Glassc98de972021-03-18 20:24:57 +13004532 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4533 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4534 data[:len(U_BOOT_TPL_NODTB_DATA)])
4535
Simon Glass63f41d42021-03-18 20:24:58 +13004536 def testTplBssPad(self):
4537 """Test that we can pad TPL's BSS with zeros"""
4538 # ELF file with a '__bss_size' symbol
4539 self._SetupTplElf()
4540 data = self._DoReadFile('193_tpl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004541 self.assertEqual(U_BOOT_TPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glass63f41d42021-03-18 20:24:58 +13004542 data)
4543
4544 def testTplBssPadMissing(self):
4545 """Test that a missing symbol is detected"""
4546 self._SetupTplElf('u_boot_ucode_ptr')
4547 with self.assertRaises(ValueError) as e:
4548 self._DoReadFile('193_tpl_bss_pad.dts')
4549 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4550 str(e.exception))
4551
Simon Glass718b5292021-03-18 20:25:07 +13004552 def checkDtbSizes(self, data, pad_len, start):
4553 """Check the size arguments in a dtb embedded in an image
4554
4555 Args:
4556 data: The image data
4557 pad_len: Length of the pad section in the image, in bytes
4558 start: Start offset of the devicetree to examine, within the image
4559
4560 Returns:
4561 Size of the devicetree in bytes
4562 """
4563 dtb_data = data[start:]
4564 dtb = fdt.Fdt.FromData(dtb_data)
4565 fdt_size = dtb.GetFdtObj().totalsize()
4566 dtb.Scan()
4567 props = self._GetPropTree(dtb, 'size')
4568 self.assertEqual({
4569 'size': len(data),
4570 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4571 'u-boot-spl/u-boot-spl-dtb:size': 801,
4572 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4573 'u-boot-spl:size': 860,
4574 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4575 'u-boot/u-boot-dtb:size': 781,
4576 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4577 'u-boot:size': 827,
4578 }, props)
4579 return fdt_size
4580
4581 def testExpanded(self):
4582 """Test that an expanded entry type is selected when needed"""
4583 self._SetupSplElf()
4584 self._SetupTplElf()
4585
4586 # SPL has a devicetree, TPL does not
4587 entry_args = {
4588 'spl-dtb': '1',
4589 'spl-bss-pad': 'y',
4590 'tpl-dtb': '',
4591 }
4592 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4593 entry_args=entry_args)
4594 image = control.images['image']
4595 entries = image.GetEntries()
4596 self.assertEqual(3, len(entries))
4597
4598 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4599 self.assertIn('u-boot', entries)
4600 entry = entries['u-boot']
4601 self.assertEqual('u-boot-expanded', entry.etype)
4602 subent = entry.GetEntries()
4603 self.assertEqual(2, len(subent))
4604 self.assertIn('u-boot-nodtb', subent)
4605 self.assertIn('u-boot-dtb', subent)
4606
4607 # Second, u-boot-spl, which should be expanded into three parts
4608 self.assertIn('u-boot-spl', entries)
4609 entry = entries['u-boot-spl']
4610 self.assertEqual('u-boot-spl-expanded', entry.etype)
4611 subent = entry.GetEntries()
4612 self.assertEqual(3, len(subent))
4613 self.assertIn('u-boot-spl-nodtb', subent)
4614 self.assertIn('u-boot-spl-bss-pad', subent)
4615 self.assertIn('u-boot-spl-dtb', subent)
4616
4617 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4618 # devicetree
4619 self.assertIn('u-boot-tpl', entries)
4620 entry = entries['u-boot-tpl']
4621 self.assertEqual('u-boot-tpl', entry.etype)
4622 self.assertEqual(None, entry.GetEntries())
4623
4624 def testExpandedTpl(self):
4625 """Test that an expanded entry type is selected for TPL when needed"""
4626 self._SetupTplElf()
4627
4628 entry_args = {
4629 'tpl-bss-pad': 'y',
4630 'tpl-dtb': 'y',
4631 }
4632 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4633 entry_args=entry_args)
4634 image = control.images['image']
4635 entries = image.GetEntries()
4636 self.assertEqual(1, len(entries))
4637
4638 # We only have u-boot-tpl, which be expanded
4639 self.assertIn('u-boot-tpl', entries)
4640 entry = entries['u-boot-tpl']
4641 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4642 subent = entry.GetEntries()
4643 self.assertEqual(3, len(subent))
4644 self.assertIn('u-boot-tpl-nodtb', subent)
4645 self.assertIn('u-boot-tpl-bss-pad', subent)
4646 self.assertIn('u-boot-tpl-dtb', subent)
4647
4648 def testExpandedNoPad(self):
4649 """Test an expanded entry without BSS pad enabled"""
4650 self._SetupSplElf()
4651 self._SetupTplElf()
4652
4653 # SPL has a devicetree, TPL does not
4654 entry_args = {
4655 'spl-dtb': 'something',
4656 'spl-bss-pad': 'n',
4657 'tpl-dtb': '',
4658 }
4659 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4660 entry_args=entry_args)
4661 image = control.images['image']
4662 entries = image.GetEntries()
4663
4664 # Just check u-boot-spl, which should be expanded into two parts
4665 self.assertIn('u-boot-spl', entries)
4666 entry = entries['u-boot-spl']
4667 self.assertEqual('u-boot-spl-expanded', entry.etype)
4668 subent = entry.GetEntries()
4669 self.assertEqual(2, len(subent))
4670 self.assertIn('u-boot-spl-nodtb', subent)
4671 self.assertIn('u-boot-spl-dtb', subent)
4672
4673 def testExpandedTplNoPad(self):
4674 """Test that an expanded entry type with padding disabled in TPL"""
4675 self._SetupTplElf()
4676
4677 entry_args = {
4678 'tpl-bss-pad': '',
4679 'tpl-dtb': 'y',
4680 }
4681 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4682 entry_args=entry_args)
4683 image = control.images['image']
4684 entries = image.GetEntries()
4685 self.assertEqual(1, len(entries))
4686
4687 # We only have u-boot-tpl, which be expanded
4688 self.assertIn('u-boot-tpl', entries)
4689 entry = entries['u-boot-tpl']
4690 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4691 subent = entry.GetEntries()
4692 self.assertEqual(2, len(subent))
4693 self.assertIn('u-boot-tpl-nodtb', subent)
4694 self.assertIn('u-boot-tpl-dtb', subent)
4695
4696 def testFdtInclude(self):
4697 """Test that an Fdt is update within all binaries"""
4698 self._SetupSplElf()
4699 self._SetupTplElf()
4700
4701 # SPL has a devicetree, TPL does not
4702 self.maxDiff = None
4703 entry_args = {
4704 'spl-dtb': '1',
4705 'spl-bss-pad': 'y',
4706 'tpl-dtb': '',
4707 }
4708 # Build the image. It includes two separate devicetree binaries, each
4709 # with their own contents, but all contain the binman definition.
4710 data = self._DoReadFileDtb(
4711 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4712 update_dtb=True, entry_args=entry_args)[0]
4713 pad_len = 10
4714
4715 # Check the U-Boot dtb
4716 start = len(U_BOOT_NODTB_DATA)
4717 fdt_size = self.checkDtbSizes(data, pad_len, start)
4718
4719 # Now check SPL
4720 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4721 fdt_size = self.checkDtbSizes(data, pad_len, start)
4722
4723 # TPL has no devicetree
4724 start += fdt_size + len(U_BOOT_TPL_DATA)
4725 self.assertEqual(len(data), start)
Simon Glassbb395742020-10-26 17:40:14 -06004726
Simon Glass7098b7f2021-03-21 18:24:30 +13004727 def testSymbolsExpanded(self):
4728 """Test binman can assign symbols in expanded entries"""
4729 entry_args = {
4730 'spl-dtb': '1',
4731 }
4732 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4733 U_BOOT_SPL_DTB_DATA, 0x38,
4734 entry_args=entry_args, use_expanded=True)
4735
Simon Glasse1915782021-03-21 18:24:31 +13004736 def testCollection(self):
4737 """Test a collection"""
4738 data = self._DoReadFile('198_collection.dts')
4739 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004740 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
4741 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
Simon Glasse1915782021-03-21 18:24:31 +13004742 data)
4743
Simon Glass27a7f772021-03-21 18:24:32 +13004744 def testCollectionSection(self):
4745 """Test a collection where a section must be built first"""
4746 # Sections never have their contents when GetData() is called, but when
Simon Glass7e3f89f2021-11-23 11:03:47 -07004747 # BuildSectionData() is called with required=True, a section will force
Simon Glass27a7f772021-03-21 18:24:32 +13004748 # building the contents, producing an error is anything is still
4749 # missing.
4750 data = self._DoReadFile('199_collection_section.dts')
4751 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
Simon Glass80025522022-01-29 14:14:04 -07004752 self.assertEqual(section + U_BOOT_DATA + tools.get_bytes(0xff, 2) +
4753 section + tools.get_bytes(0xfe, 3) + U_BOOT_DATA,
Simon Glass27a7f772021-03-21 18:24:32 +13004754 data)
4755
Simon Glassf427c5f2021-03-21 18:24:33 +13004756 def testAlignDefault(self):
4757 """Test that default alignment works on sections"""
4758 data = self._DoReadFile('200_align_default.dts')
Simon Glass80025522022-01-29 14:14:04 -07004759 expected = (U_BOOT_DATA + tools.get_bytes(0, 8 - len(U_BOOT_DATA)) +
Simon Glassf427c5f2021-03-21 18:24:33 +13004760 U_BOOT_DATA)
4761 # Special alignment for section
Simon Glass80025522022-01-29 14:14:04 -07004762 expected += tools.get_bytes(0, 32 - len(expected))
Simon Glassf427c5f2021-03-21 18:24:33 +13004763 # No alignment within the nested section
4764 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
4765 # Now the final piece, which should be default-aligned
Simon Glass80025522022-01-29 14:14:04 -07004766 expected += tools.get_bytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
Simon Glassf427c5f2021-03-21 18:24:33 +13004767 self.assertEqual(expected, data)
Simon Glass27a7f772021-03-21 18:24:32 +13004768
Bin Mengc0b15742021-05-10 20:23:33 +08004769 def testPackOpenSBI(self):
4770 """Test that an image with an OpenSBI binary can be created"""
4771 data = self._DoReadFile('201_opensbi.dts')
4772 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
4773
Simon Glass76f496d2021-07-06 10:36:37 -06004774 def testSectionsSingleThread(self):
4775 """Test sections without multithreading"""
4776 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
Simon Glass80025522022-01-29 14:14:04 -07004777 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4778 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
4779 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glass76f496d2021-07-06 10:36:37 -06004780 self.assertEqual(expected, data)
4781
4782 def testThreadTimeout(self):
4783 """Test handling a thread that takes too long"""
4784 with self.assertRaises(ValueError) as e:
4785 self._DoTestFile('202_section_timeout.dts',
4786 test_section_timeout=True)
Simon Glass2d59d152021-10-18 12:13:15 -06004787 self.assertIn("Timed out obtaining contents", str(e.exception))
Simon Glass76f496d2021-07-06 10:36:37 -06004788
Simon Glass748a1d42021-07-06 10:36:41 -06004789 def testTiming(self):
4790 """Test output of timing information"""
4791 data = self._DoReadFile('055_sections.dts')
4792 with test_util.capture_sys_output() as (stdout, stderr):
4793 state.TimingShow()
4794 self.assertIn('read:', stdout.getvalue())
4795 self.assertIn('compress:', stdout.getvalue())
4796
Simon Glassadfb8492021-11-03 21:09:18 -06004797 def testUpdateFdtInElf(self):
4798 """Test that we can update the devicetree in an ELF file"""
4799 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4800 outfile = os.path.join(self._indir, 'u-boot.out')
4801 begin_sym = 'dtb_embed_begin'
4802 end_sym = 'dtb_embed_end'
4803 retcode = self._DoTestFile(
4804 '060_fdt_update.dts', update_dtb=True,
4805 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4806 self.assertEqual(0, retcode)
4807
4808 # Check that the output file does in fact contact a dtb with the binman
4809 # definition in the correct place
4810 syms = elf.GetSymbolFileOffset(infile,
4811 ['dtb_embed_begin', 'dtb_embed_end'])
Simon Glass80025522022-01-29 14:14:04 -07004812 data = tools.read_file(outfile)
Simon Glassadfb8492021-11-03 21:09:18 -06004813 dtb_data = data[syms['dtb_embed_begin'].offset:
4814 syms['dtb_embed_end'].offset]
4815
4816 dtb = fdt.Fdt.FromData(dtb_data)
4817 dtb.Scan()
4818 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4819 self.assertEqual({
4820 'image-pos': 0,
4821 'offset': 0,
4822 '_testing:offset': 32,
4823 '_testing:size': 2,
4824 '_testing:image-pos': 32,
4825 'section@0/u-boot:offset': 0,
4826 'section@0/u-boot:size': len(U_BOOT_DATA),
4827 'section@0/u-boot:image-pos': 0,
4828 'section@0:offset': 0,
4829 'section@0:size': 16,
4830 'section@0:image-pos': 0,
4831
4832 'section@1/u-boot:offset': 0,
4833 'section@1/u-boot:size': len(U_BOOT_DATA),
4834 'section@1/u-boot:image-pos': 16,
4835 'section@1:offset': 16,
4836 'section@1:size': 16,
4837 'section@1:image-pos': 16,
4838 'size': 40
4839 }, props)
4840
4841 def testUpdateFdtInElfInvalid(self):
4842 """Test that invalid args are detected with --update-fdt-in-elf"""
4843 with self.assertRaises(ValueError) as e:
4844 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
4845 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
4846 str(e.exception))
4847
4848 def testUpdateFdtInElfNoSyms(self):
4849 """Test that missing symbols are detected with --update-fdt-in-elf"""
4850 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4851 outfile = ''
4852 begin_sym = 'wrong_begin'
4853 end_sym = 'wrong_end'
4854 with self.assertRaises(ValueError) as e:
4855 self._DoTestFile(
4856 '060_fdt_update.dts',
4857 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4858 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
4859 str(e.exception))
4860
4861 def testUpdateFdtInElfTooSmall(self):
4862 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
4863 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
4864 outfile = os.path.join(self._indir, 'u-boot.out')
4865 begin_sym = 'dtb_embed_begin'
4866 end_sym = 'dtb_embed_end'
4867 with self.assertRaises(ValueError) as e:
4868 self._DoTestFile(
4869 '060_fdt_update.dts', update_dtb=True,
4870 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4871 self.assertRegex(
4872 str(e.exception),
4873 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
4874
Simon Glass88e04da2021-11-23 11:03:42 -07004875 def testVersion(self):
4876 """Test we can get the binman version"""
4877 version = '(unreleased)'
4878 self.assertEqual(version, state.GetVersion(self._indir))
4879
4880 with self.assertRaises(SystemExit):
4881 with test_util.capture_sys_output() as (_, stderr):
4882 self._DoBinman('-V')
4883 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
4884
4885 # Try running the tool too, just to be safe
4886 result = self._RunBinman('-V')
4887 self.assertEqual('Binman %s\n' % version, result.stderr)
4888
4889 # Set up a version file to make sure that works
4890 version = 'v2025.01-rc2'
Simon Glass80025522022-01-29 14:14:04 -07004891 tools.write_file(os.path.join(self._indir, 'version'), version,
Simon Glass88e04da2021-11-23 11:03:42 -07004892 binary=False)
4893 self.assertEqual(version, state.GetVersion(self._indir))
4894
Simon Glass637958f2021-11-23 21:09:50 -07004895 def testAltFormat(self):
4896 """Test that alternative formats can be used to extract"""
4897 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
4898
4899 try:
4900 tmpdir, updated_fname = self._SetupImageInTmpdir()
4901 with test_util.capture_sys_output() as (stdout, _):
4902 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
4903 self.assertEqual(
4904 '''Flag (-F) Entry type Description
4905fdt fdtmap Extract the devicetree blob from the fdtmap
4906''',
4907 stdout.getvalue())
4908
4909 dtb = os.path.join(tmpdir, 'fdt.dtb')
4910 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
4911 dtb, 'fdtmap')
4912
4913 # Check that we can read it and it can be scanning, meaning it does
4914 # not have a 16-byte fdtmap header
Simon Glass80025522022-01-29 14:14:04 -07004915 data = tools.read_file(dtb)
Simon Glass637958f2021-11-23 21:09:50 -07004916 dtb = fdt.Fdt.FromData(data)
4917 dtb.Scan()
4918
4919 # Now check u-boot which has no alt_format
4920 fname = os.path.join(tmpdir, 'fdt.dtb')
4921 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
4922 '-f', fname, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07004923 data = tools.read_file(fname)
Simon Glass637958f2021-11-23 21:09:50 -07004924 self.assertEqual(U_BOOT_DATA, data)
4925
4926 finally:
4927 shutil.rmtree(tmpdir)
4928
Simon Glass0b00ae62021-11-23 21:09:52 -07004929 def testExtblobList(self):
4930 """Test an image with an external blob list"""
4931 data = self._DoReadFile('215_blob_ext_list.dts')
4932 self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
4933
4934 def testExtblobListMissing(self):
4935 """Test an image with a missing external blob"""
4936 with self.assertRaises(ValueError) as e:
4937 self._DoReadFile('216_blob_ext_list_missing.dts')
4938 self.assertIn("Filename 'missing-file' not found in input path",
4939 str(e.exception))
4940
4941 def testExtblobListMissingOk(self):
4942 """Test an image with an missing external blob that is allowed"""
4943 with test_util.capture_sys_output() as (stdout, stderr):
4944 self._DoTestFile('216_blob_ext_list_missing.dts',
4945 allow_missing=True)
4946 err = stderr.getvalue()
4947 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
4948
Simon Glass3efb2972021-11-23 21:08:59 -07004949 def testFip(self):
4950 """Basic test of generation of an ARM Firmware Image Package (FIP)"""
4951 data = self._DoReadFile('203_fip.dts')
4952 hdr, fents = fip_util.decode_fip(data)
4953 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
4954 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
4955 self.assertEqual(0x123, hdr.flags)
4956
4957 self.assertEqual(2, len(fents))
4958
4959 fent = fents[0]
4960 self.assertEqual(
4961 bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
4962 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
4963 self.assertEqual('soc-fw', fent.fip_type)
4964 self.assertEqual(0x88, fent.offset)
4965 self.assertEqual(len(ATF_BL31_DATA), fent.size)
4966 self.assertEqual(0x123456789abcdef, fent.flags)
4967 self.assertEqual(ATF_BL31_DATA, fent.data)
4968 self.assertEqual(True, fent.valid)
4969
4970 fent = fents[1]
4971 self.assertEqual(
4972 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
4973 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
4974 self.assertEqual('scp-fwu-cfg', fent.fip_type)
4975 self.assertEqual(0x8c, fent.offset)
4976 self.assertEqual(len(ATF_BL31_DATA), fent.size)
4977 self.assertEqual(0, fent.flags)
4978 self.assertEqual(ATF_BL2U_DATA, fent.data)
4979 self.assertEqual(True, fent.valid)
4980
4981 def testFipOther(self):
4982 """Basic FIP with something that isn't a external blob"""
4983 data = self._DoReadFile('204_fip_other.dts')
4984 hdr, fents = fip_util.decode_fip(data)
4985
4986 self.assertEqual(2, len(fents))
4987 fent = fents[1]
4988 self.assertEqual('rot-cert', fent.fip_type)
4989 self.assertEqual(b'aa', fent.data)
4990
Simon Glass3efb2972021-11-23 21:08:59 -07004991 def testFipNoType(self):
4992 """FIP with an entry of an unknown type"""
4993 with self.assertRaises(ValueError) as e:
4994 self._DoReadFile('205_fip_no_type.dts')
4995 self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
4996 str(e.exception))
4997
4998 def testFipUuid(self):
4999 """Basic FIP with a manual uuid"""
5000 data = self._DoReadFile('206_fip_uuid.dts')
5001 hdr, fents = fip_util.decode_fip(data)
5002
5003 self.assertEqual(2, len(fents))
5004 fent = fents[1]
5005 self.assertEqual(None, fent.fip_type)
5006 self.assertEqual(
5007 bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
5008 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
5009 fent.uuid)
5010 self.assertEqual(U_BOOT_DATA, fent.data)
5011
5012 def testFipLs(self):
5013 """Test listing a FIP"""
5014 data = self._DoReadFileRealDtb('207_fip_ls.dts')
5015 hdr, fents = fip_util.decode_fip(data)
5016
5017 try:
5018 tmpdir, updated_fname = self._SetupImageInTmpdir()
5019 with test_util.capture_sys_output() as (stdout, stderr):
5020 self._DoBinman('ls', '-i', updated_fname)
5021 finally:
5022 shutil.rmtree(tmpdir)
5023 lines = stdout.getvalue().splitlines()
5024 expected = [
5025'Name Image-pos Size Entry-type Offset Uncomp-size',
5026'----------------------------------------------------------------',
5027'main-section 0 2d3 section 0',
5028' atf-fip 0 90 atf-fip 0',
5029' soc-fw 88 4 blob-ext 88',
5030' u-boot 8c 4 u-boot 8c',
5031' fdtmap 90 243 fdtmap 90',
5032]
5033 self.assertEqual(expected, lines)
5034
5035 image = control.images['image']
5036 entries = image.GetEntries()
5037 fdtmap = entries['fdtmap']
5038
5039 fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
5040 magic = fdtmap_data[:8]
5041 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07005042 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass3efb2972021-11-23 21:08:59 -07005043
5044 fdt_data = fdtmap_data[16:]
5045 dtb = fdt.Fdt.FromData(fdt_data)
5046 dtb.Scan()
5047 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
5048 self.assertEqual({
5049 'atf-fip/soc-fw:image-pos': 136,
5050 'atf-fip/soc-fw:offset': 136,
5051 'atf-fip/soc-fw:size': 4,
5052 'atf-fip/u-boot:image-pos': 140,
5053 'atf-fip/u-boot:offset': 140,
5054 'atf-fip/u-boot:size': 4,
5055 'atf-fip:image-pos': 0,
5056 'atf-fip:offset': 0,
5057 'atf-fip:size': 144,
5058 'image-pos': 0,
5059 'offset': 0,
5060 'fdtmap:image-pos': fdtmap.image_pos,
5061 'fdtmap:offset': fdtmap.offset,
5062 'fdtmap:size': len(fdtmap_data),
5063 'size': len(data),
5064 }, props)
5065
5066 def testFipExtractOneEntry(self):
5067 """Test extracting a single entry fron an FIP"""
5068 self._DoReadFileRealDtb('207_fip_ls.dts')
Simon Glass80025522022-01-29 14:14:04 -07005069 image_fname = tools.get_output_filename('image.bin')
Simon Glass3efb2972021-11-23 21:08:59 -07005070 fname = os.path.join(self._indir, 'output.extact')
5071 control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07005072 data = tools.read_file(fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005073 self.assertEqual(U_BOOT_DATA, data)
5074
5075 def testFipReplace(self):
5076 """Test replacing a single file in a FIP"""
Simon Glass80025522022-01-29 14:14:04 -07005077 expected = U_BOOT_DATA + tools.get_bytes(0x78, 50)
Simon Glass3efb2972021-11-23 21:08:59 -07005078 data = self._DoReadFileRealDtb('208_fip_replace.dts')
Simon Glass80025522022-01-29 14:14:04 -07005079 updated_fname = tools.get_output_filename('image-updated.bin')
5080 tools.write_file(updated_fname, data)
Simon Glass3efb2972021-11-23 21:08:59 -07005081 entry_name = 'atf-fip/u-boot'
5082 control.WriteEntry(updated_fname, entry_name, expected,
5083 allow_resize=True)
5084 actual = control.ReadEntry(updated_fname, entry_name)
5085 self.assertEqual(expected, actual)
5086
Simon Glass80025522022-01-29 14:14:04 -07005087 new_data = tools.read_file(updated_fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005088 hdr, fents = fip_util.decode_fip(new_data)
5089
5090 self.assertEqual(2, len(fents))
5091
5092 # Check that the FIP entry is updated
5093 fent = fents[1]
5094 self.assertEqual(0x8c, fent.offset)
5095 self.assertEqual(len(expected), fent.size)
5096 self.assertEqual(0, fent.flags)
5097 self.assertEqual(expected, fent.data)
5098 self.assertEqual(True, fent.valid)
5099
5100 def testFipMissing(self):
5101 with test_util.capture_sys_output() as (stdout, stderr):
5102 self._DoTestFile('209_fip_missing.dts', allow_missing=True)
5103 err = stderr.getvalue()
5104 self.assertRegex(err, "Image 'main-section'.*missing.*: rmm-fw")
5105
5106 def testFipSize(self):
5107 """Test a FIP with a size property"""
5108 data = self._DoReadFile('210_fip_size.dts')
5109 self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
5110 hdr, fents = fip_util.decode_fip(data)
5111 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5112 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5113
5114 self.assertEqual(1, len(fents))
5115
5116 fent = fents[0]
5117 self.assertEqual('soc-fw', fent.fip_type)
5118 self.assertEqual(0x60, fent.offset)
5119 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5120 self.assertEqual(ATF_BL31_DATA, fent.data)
5121 self.assertEqual(True, fent.valid)
5122
5123 rest = data[0x60 + len(ATF_BL31_DATA):0x100]
Simon Glass80025522022-01-29 14:14:04 -07005124 self.assertEqual(tools.get_bytes(0xff, len(rest)), rest)
Simon Glass3efb2972021-11-23 21:08:59 -07005125
5126 def testFipBadAlign(self):
5127 """Test that an invalid alignment value in a FIP is detected"""
5128 with self.assertRaises(ValueError) as e:
5129 self._DoTestFile('211_fip_bad_align.dts')
5130 self.assertIn(
5131 "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
5132 str(e.exception))
5133
5134 def testFipCollection(self):
5135 """Test using a FIP in a collection"""
5136 data = self._DoReadFile('212_fip_collection.dts')
5137 entry1 = control.images['image'].GetEntries()['collection']
5138 data1 = data[:entry1.size]
5139 hdr1, fents2 = fip_util.decode_fip(data1)
5140
5141 entry2 = control.images['image'].GetEntries()['atf-fip']
5142 data2 = data[entry2.offset:entry2.offset + entry2.size]
5143 hdr1, fents2 = fip_util.decode_fip(data2)
5144
5145 # The 'collection' entry should have U-Boot included at the end
5146 self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
5147 self.assertEqual(data1, data2 + U_BOOT_DATA)
5148 self.assertEqual(U_BOOT_DATA, data1[-4:])
5149
5150 # There should be a U-Boot after the final FIP
5151 self.assertEqual(U_BOOT_DATA, data[-4:])
Simon Glass76f496d2021-07-06 10:36:37 -06005152
Simon Glassccae6862022-01-12 13:10:35 -07005153 def testFakeBlob(self):
5154 """Test handling of faking an external blob"""
5155 with test_util.capture_sys_output() as (stdout, stderr):
5156 self._DoTestFile('217_fake_blob.dts', allow_missing=True,
5157 allow_fake_blobs=True)
5158 err = stderr.getvalue()
5159 self.assertRegex(
5160 err,
5161 "Image '.*' has faked external blobs and is non-functional: .*")
Simon Glassccae6862022-01-12 13:10:35 -07005162
Simon Glassceb5f912022-01-09 20:13:46 -07005163 def testExtblobListFaked(self):
5164 """Test an extblob with missing external blob that are faked"""
5165 with test_util.capture_sys_output() as (stdout, stderr):
5166 self._DoTestFile('216_blob_ext_list_missing.dts',
5167 allow_fake_blobs=True)
5168 err = stderr.getvalue()
5169 self.assertRegex(err, "Image 'main-section'.*faked.*: blob-ext-list")
5170
Simon Glass162017b2022-01-09 20:13:57 -07005171 def testListBintools(self):
5172 args = ['tool', '--list']
5173 with test_util.capture_sys_output() as (stdout, _):
5174 self._DoBinman(*args)
5175 out = stdout.getvalue().splitlines()
5176 self.assertTrue(len(out) >= 2)
5177
5178 def testFetchBintools(self):
5179 def fail_download(url):
Simon Glass80025522022-01-29 14:14:04 -07005180 """Take the tools.download() function by raising an exception"""
Simon Glass162017b2022-01-09 20:13:57 -07005181 raise urllib.error.URLError('my error')
5182
5183 args = ['tool']
5184 with self.assertRaises(ValueError) as e:
5185 self._DoBinman(*args)
5186 self.assertIn("Invalid arguments to 'tool' subcommand",
5187 str(e.exception))
5188
5189 args = ['tool', '--fetch']
5190 with self.assertRaises(ValueError) as e:
5191 self._DoBinman(*args)
5192 self.assertIn('Please specify bintools to fetch', str(e.exception))
5193
5194 args = ['tool', '--fetch', '_testing']
Simon Glass80025522022-01-29 14:14:04 -07005195 with unittest.mock.patch.object(tools, 'download',
Simon Glass162017b2022-01-09 20:13:57 -07005196 side_effect=fail_download):
5197 with test_util.capture_sys_output() as (stdout, _):
5198 self._DoBinman(*args)
5199 self.assertIn('failed to fetch with all methods', stdout.getvalue())
5200
Simon Glassdab7c142022-01-09 20:14:10 -07005201 def testInvalidCompress(self):
5202 with self.assertRaises(ValueError) as e:
5203 comp_util.compress(b'', 'invalid')
5204 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
5205
5206 with self.assertRaises(ValueError) as e:
5207 comp_util.decompress(b'1234', 'invalid')
5208 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
5209
Simon Glass620c4462022-01-09 20:14:11 -07005210 def testBintoolDocs(self):
5211 """Test for creation of bintool documentation"""
5212 with test_util.capture_sys_output() as (stdout, stderr):
5213 control.write_bintool_docs(control.bintool.Bintool.get_tool_list())
5214 self.assertTrue(len(stdout.getvalue()) > 0)
5215
5216 def testBintoolDocsMissing(self):
5217 """Test handling of missing bintool documentation"""
5218 with self.assertRaises(ValueError) as e:
5219 with test_util.capture_sys_output() as (stdout, stderr):
5220 control.write_bintool_docs(
5221 control.bintool.Bintool.get_tool_list(), 'mkimage')
5222 self.assertIn('Documentation is missing for modules: mkimage',
5223 str(e.exception))
5224
Jan Kiszka58c407f2022-01-28 20:37:53 +01005225 def testListWithGenNode(self):
5226 """Check handling of an FDT map when the section cannot be found"""
5227 entry_args = {
5228 'of-list': 'test-fdt1 test-fdt2',
5229 }
5230 data = self._DoReadFileDtb(
5231 '219_fit_gennode.dts',
5232 entry_args=entry_args,
5233 use_real_dtb=True,
5234 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])
5235
5236 try:
5237 tmpdir, updated_fname = self._SetupImageInTmpdir()
5238 with test_util.capture_sys_output() as (stdout, stderr):
5239 self._RunBinman('ls', '-i', updated_fname)
5240 finally:
5241 shutil.rmtree(tmpdir)
5242
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005243 def testFitSubentryUsesBintool(self):
5244 """Test that binman FIT subentries can use bintools"""
5245 command.test_result = self._HandleGbbCommand
5246 entry_args = {
5247 'keydir': 'devkeys',
5248 'bmpblk': 'bmpblk.bin',
5249 }
5250 data, _, _, _ = self._DoReadFileDtb('220_fit_subentry_bintool.dts',
5251 entry_args=entry_args)
5252
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03005253 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
5254 tools.get_bytes(0, 0x2180 - 16))
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005255 self.assertIn(expected, data)
5256
5257 def testFitSubentryMissingBintool(self):
5258 """Test that binman reports missing bintools for FIT subentries"""
5259 entry_args = {
5260 'keydir': 'devkeys',
5261 }
5262 with test_util.capture_sys_output() as (_, stderr):
5263 self._DoTestFile('220_fit_subentry_bintool.dts',
5264 force_missing_bintools='futility', entry_args=entry_args)
5265 err = stderr.getvalue()
5266 self.assertRegex(err,
5267 "Image 'main-section'.*missing bintools.*: futility")
Simon Glassccae6862022-01-12 13:10:35 -07005268
Alper Nebi Yasak1e4ffd82022-02-09 22:02:35 +03005269 def testFitSubentryHashSubnode(self):
5270 """Test an image with a FIT inside"""
5271 data, _, _, out_dtb_name = self._DoReadFileDtb(
5272 '221_fit_subentry_hash.dts', use_real_dtb=True, update_dtb=True)
5273
5274 mkimage_dtb = fdt.Fdt.FromData(data)
5275 mkimage_dtb.Scan()
5276 binman_dtb = fdt.Fdt(out_dtb_name)
5277 binman_dtb.Scan()
5278
5279 # Check that binman didn't add hash values
5280 fnode = binman_dtb.GetNode('/binman/fit/images/kernel/hash')
5281 self.assertNotIn('value', fnode.props)
5282
5283 fnode = binman_dtb.GetNode('/binman/fit/images/fdt-1/hash')
5284 self.assertNotIn('value', fnode.props)
5285
5286 # Check that mkimage added hash values
5287 fnode = mkimage_dtb.GetNode('/images/kernel/hash')
5288 self.assertIn('value', fnode.props)
5289
5290 fnode = mkimage_dtb.GetNode('/images/fdt-1/hash')
5291 self.assertIn('value', fnode.props)
5292
Roger Quadros5cdcea02022-02-19 20:50:04 +02005293 def testPackTeeOs(self):
5294 """Test that an image with an TEE binary can be created"""
5295 data = self._DoReadFile('222_tee_os.dts')
5296 self.assertEqual(TEE_OS_DATA, data[:len(TEE_OS_DATA)])
5297
Simon Glass912339f2022-02-08 11:50:03 -07005298 def testFitFdtOper(self):
5299 """Check handling of a specified FIT operation"""
5300 entry_args = {
5301 'of-list': 'test-fdt1 test-fdt2',
5302 'default-dt': 'test-fdt2',
5303 }
5304 self._DoReadFileDtb(
5305 '223_fit_fdt_oper.dts',
5306 entry_args=entry_args,
5307 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
5308
5309 def testFitFdtBadOper(self):
5310 """Check handling of an FDT map when the section cannot be found"""
5311 with self.assertRaises(ValueError) as exc:
5312 self._DoReadFileDtb('224_fit_bad_oper.dts')
Simon Glass05f71dc2022-03-05 20:19:09 -07005313 self.assertIn("Node '/binman/fit': subnode 'images/@fdt-SEQ': Unknown operation 'unknown'",
Simon Glass912339f2022-02-08 11:50:03 -07005314 str(exc.exception))
5315
Simon Glassdd156a42022-03-05 20:18:59 -07005316 def test_uses_expand_size(self):
5317 """Test that the 'expand-size' property cannot be used anymore"""
5318 with self.assertRaises(ValueError) as e:
5319 data = self._DoReadFile('225_expand_size_bad.dts')
5320 self.assertIn(
5321 "Node '/binman/u-boot': Please use 'extend-size' instead of 'expand-size'",
5322 str(e.exception))
5323
Simon Glassfc5a1682022-03-05 20:19:05 -07005324 def testMkimageMissingBlob(self):
5325 """Test using mkimage to build an image"""
5326 with test_util.capture_sys_output() as (stdout, stderr):
5327 self._DoTestFile('229_mkimage_missing.dts', allow_missing=True,
5328 allow_fake_blobs=True)
5329 err = stderr.getvalue()
5330 self.assertRegex(
5331 err,
5332 "Image '.*' has faked external blobs and is non-functional: .*")
5333
Simon Glass5f423422022-03-05 20:19:12 -07005334 def testFitSplitElf(self):
5335 """Test an image with an FIT with an split-elf operation"""
5336 entry_args = {
5337 'of-list': 'test-fdt1 test-fdt2',
5338 'default-dt': 'test-fdt2',
5339 'atf-bl31-path': 'bl31.elf',
5340 'tee-os-path': 'tee.elf',
5341 }
5342 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5343 data = self._DoReadFileDtb(
5344 '226_fit_split_elf.dts',
5345 entry_args=entry_args,
5346 extra_indirs=[test_subdir])[0]
5347
5348 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
5349 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
5350
5351 base_keys = {'description', 'type', 'arch', 'os', 'compression',
5352 'data', 'load'}
5353 dtb = fdt.Fdt.FromData(fit_data)
5354 dtb.Scan()
5355
5356 elf_data = tools.read_file(os.path.join(self._indir, 'bl31.elf'))
5357 segments, entry = elf.read_loadable_segments(elf_data)
5358
5359 # We assume there are two segments
5360 self.assertEquals(2, len(segments))
5361
5362 atf1 = dtb.GetNode('/images/atf-1')
5363 _, start, data = segments[0]
5364 self.assertEqual(base_keys | {'entry'}, atf1.props.keys())
5365 self.assertEqual(entry,
5366 fdt_util.fdt32_to_cpu(atf1.props['entry'].value))
5367 self.assertEqual(start,
5368 fdt_util.fdt32_to_cpu(atf1.props['load'].value))
5369 self.assertEqual(data, atf1.props['data'].bytes)
5370
5371 atf2 = dtb.GetNode('/images/atf-2')
5372 self.assertEqual(base_keys, atf2.props.keys())
5373 _, start, data = segments[1]
5374 self.assertEqual(start,
5375 fdt_util.fdt32_to_cpu(atf2.props['load'].value))
5376 self.assertEqual(data, atf2.props['data'].bytes)
5377
5378 conf = dtb.GetNode('/configurations')
5379 self.assertEqual({'default'}, conf.props.keys())
5380
5381 for subnode in conf.subnodes:
5382 self.assertEqual({'description', 'fdt', 'loadables'},
5383 subnode.props.keys())
5384 self.assertEqual(
5385 ['atf-1', 'atf-2', 'tee-1', 'tee-2'],
5386 fdt_util.GetStringList(subnode, 'loadables'))
5387
5388 def _check_bad_fit(self, dts):
5389 """Check a bad FIT
5390
5391 This runs with the given dts and returns the assertion raised
5392
5393 Args:
5394 dts (str): dts filename to use
5395
5396 Returns:
5397 str: Assertion string raised
5398 """
5399 entry_args = {
5400 'of-list': 'test-fdt1 test-fdt2',
5401 'default-dt': 'test-fdt2',
5402 'atf-bl31-path': 'bl31.elf',
5403 'tee-os-path': 'tee.elf',
5404 }
5405 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5406 with self.assertRaises(ValueError) as exc:
5407 self._DoReadFileDtb(dts, entry_args=entry_args,
5408 extra_indirs=[test_subdir])[0]
5409 return str(exc.exception)
5410
5411 def testFitSplitElfBadElf(self):
5412 """Test a FIT split-elf operation with an invalid ELF file"""
5413 TestFunctional._MakeInputFile('bad.elf', tools.get_bytes(100, 100))
5414 entry_args = {
5415 'of-list': 'test-fdt1 test-fdt2',
5416 'default-dt': 'test-fdt2',
5417 'atf-bl31-path': 'bad.elf',
5418 'tee-os-path': 'tee.elf',
5419 }
5420 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5421 with self.assertRaises(ValueError) as exc:
5422 self._DoReadFileDtb(
5423 '226_fit_split_elf.dts',
5424 entry_args=entry_args,
5425 extra_indirs=[test_subdir])[0]
5426 self.assertIn(
5427 "Node '/binman/fit': subnode 'images/@atf-SEQ': Failed to read ELF file: Magic number does not match",
5428 str(exc.exception))
5429
5430 def testFitSplitElfBadDirective(self):
5431 """Test a FIT split-elf invalid fit,xxx directive in an image node"""
5432 err = self._check_bad_fit('227_fit_bad_dir.dts')
5433 self.assertIn(
5434 "Node '/binman/fit': subnode 'images/@atf-SEQ': Unknown directive 'fit,something'",
5435 err)
5436
5437 def testFitSplitElfBadDirectiveConfig(self):
5438 """Test a FIT split-elf with invalid fit,xxx directive in config"""
5439 err = self._check_bad_fit('228_fit_bad_dir_config.dts')
5440 self.assertEqual(
5441 "Node '/binman/fit': subnode 'configurations/@config-SEQ': Unknown directive 'fit,config'",
5442 err)
5443
5444 def checkFitSplitElf(self, **kwargs):
5445 """Test an split-elf FIT with a missing ELF file"""
5446 entry_args = {
5447 'of-list': 'test-fdt1 test-fdt2',
5448 'default-dt': 'test-fdt2',
5449 'atf-bl31-path': 'bl31.elf',
5450 'tee-os-path': 'missing.elf',
5451 }
5452 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5453 with test_util.capture_sys_output() as (stdout, stderr):
5454 self._DoTestFile(
5455 '226_fit_split_elf.dts', entry_args=entry_args,
5456 extra_indirs=[test_subdir], **kwargs)
5457 err = stderr.getvalue()
5458 return err
5459
5460 def testFitSplitElfMissing(self):
5461 """Test an split-elf FIT with a missing ELF file"""
5462 err = self.checkFitSplitElf(allow_missing=True)
5463 self.assertRegex(
5464 err,
5465 "Image '.*' is missing external blobs and is non-functional: .*")
5466
5467 def testFitSplitElfFaked(self):
5468 """Test an split-elf FIT with faked ELF file"""
5469 err = self.checkFitSplitElf(allow_missing=True, allow_fake_blobs=True)
5470 self.assertRegex(
5471 err,
5472 "Image '.*' is missing external blobs and is non-functional: .*")
5473
Roger Quadros5cdcea02022-02-19 20:50:04 +02005474
Simon Glassac599912017-11-12 21:52:22 -07005475if __name__ == "__main__":
5476 unittest.main()