blob: b5cf549703ad2d6ef140b5b13ca44de359a59366 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001# SPDX-License-Identifier: GPL-2.0+
Simon Glass4f443042016-11-25 20:15:52 -07002# Copyright (c) 2016 Google, Inc
3# Written by Simon Glass <sjg@chromium.org>
4#
Simon Glass4f443042016-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 Glassfdc34362020-07-09 18:39:45 -06009import collections
Simon Glass16287932020-04-17 18:09:03 -060010import gzip
Simon Glasse0e5df92018-09-14 04:57:31 -060011import hashlib
Simon Glass4f443042016-11-25 20:15:52 -070012from optparse import OptionParser
13import os
Simon Glassfdc34362020-07-09 18:39:45 -060014import re
Simon Glass4f443042016-11-25 20:15:52 -070015import shutil
16import struct
17import sys
18import tempfile
19import unittest
Simon Glass56ee85e2022-01-09 20:13:57 -070020import unittest.mock
21import urllib.error
Simon Glass4f443042016-11-25 20:15:52 -070022
Simon Glass386c63c2022-01-09 20:13:50 -070023from binman import bintool
Simon Glass16287932020-04-17 18:09:03 -060024from binman import cbfs_util
25from binman import cmdline
Simon Glassad35ce52022-01-09 20:14:03 -070026from binman import comp_util
Simon Glass16287932020-04-17 18:09:03 -060027from binman import control
28from binman import elf
29from binman import elf_test
Simon Glass75989722021-11-23 21:08:59 -070030from binman import fip_util
Simon Glass16287932020-04-17 18:09:03 -060031from binman import fmap_util
Simon Glass16287932020-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 Glass07237982020-08-05 13:27:47 -060037from binman.image import Image
Simon Glassbf776672020-04-17 18:09:04 -060038from patman import command
39from patman import test_util
40from patman import tools
41from patman import tout
Simon Glass4f443042016-11-25 20:15:52 -070042
43# Contents of test files, corresponding to different entry types
Simon Glassc6c10e72019-05-17 22:00:46 -060044U_BOOT_DATA = b'1234'
45U_BOOT_IMG_DATA = b'img'
Simon Glasseb0086f2019-08-24 07:23:04 -060046U_BOOT_SPL_DATA = b'56780123456789abcdefghi'
47U_BOOT_TPL_DATA = b'tpl9876543210fedcbazyw'
Simon Glassc6c10e72019-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 Glass2250ee62019-08-24 07:22:48 -060057X86_RESET16_DATA = b'reset16'
58X86_RESET16_SPL_DATA = b'reset16spl'
59X86_RESET16_TPL_DATA = b'reset16tpl'
Simon Glassc6c10e72019-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 Yasak21353312022-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 Glassc6c10e72019-05-17 22:00:46 -060067FSP_DATA = b'fsp'
68CMC_DATA = b'cmc'
69VBT_DATA = b'vbt'
70MRC_DATA = b'mrc'
Simon Glassbb748372018-07-17 13:25:33 -060071TEXT_DATA = 'text'
72TEXT_DATA2 = 'text2'
73TEXT_DATA3 = 'text3'
Simon Glassc6c10e72019-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 Glassff5c7e32019-07-08 13:18:42 -060080COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
Simon Glass8f5ef892020-10-26 17:40:25 -060081COMPRESS_DATA_BIG = COMPRESS_DATA * 2
Simon Glassc6c10e72019-05-17 22:00:46 -060082REFCODE_DATA = b'refcode'
Simon Glassea0fff92019-08-24 07:23:07 -060083FSP_M_DATA = b'fsp_m'
Simon Glassbc6a88f2019-10-20 21:31:35 -060084FSP_S_DATA = b'fsp_s'
Simon Glass998d1482019-10-20 21:31:36 -060085FSP_T_DATA = b'fsp_t'
Simon Glassdc2f81a2020-09-01 05:13:58 -060086ATF_BL31_DATA = b'bl31'
Roger Quadros47f420a2022-02-19 20:50:04 +020087TEE_OS_DATA = b'this is some tee OS data'
Simon Glass75989722021-11-23 21:08:59 -070088ATF_BL2U_DATA = b'bl2u'
Bin Meng4c4d6072021-05-10 20:23:33 +080089OPENSBI_DATA = b'opensbi'
Samuel Holland18bd4552020-10-21 21:12:15 -050090SCP_DATA = b'scp'
Simon Glass6cf99532020-09-01 05:13:59 -060091TEST_FDT1_DATA = b'fdt1'
92TEST_FDT2_DATA = b'test-fdt2'
Simon Glassfb91d562020-09-06 10:35:33 -060093ENV_DATA = b'var1=1\nvar2="2"'
Philippe Reynesb1c50932022-03-28 22:57:04 +020094PRE_LOAD_MAGIC = b'UBSH'
95PRE_LOAD_VERSION = 0x11223344.to_bytes(4, 'big')
96PRE_LOAD_HDR_SIZE = 0x00001000.to_bytes(4, 'big')
Simon Glass6cf99532020-09-01 05:13:59 -060097
98# Subdirectory of the input dir to use to put test FDTs
99TEST_FDT_SUBDIR = 'fdts'
Simon Glassec127af2018-07-17 13:25:39 -0600100
Simon Glass6ccbfcd2019-07-20 12:23:47 -0600101# The expected size for the device tree in some tests
Simon Glassf667e452019-07-08 14:25:50 -0600102EXTRACT_DTB_SIZE = 0x3c9
103
Simon Glass6ccbfcd2019-07-20 12:23:47 -0600104# Properties expected to be in the device tree when update_dtb is used
105BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
106
Simon Glass12bb1a92019-07-20 12:23:51 -0600107# Extra properties expected to be in the device tree when allow-repack is used
108REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
109
Simon Glass4f443042016-11-25 20:15:52 -0700110
111class TestFunctional(unittest.TestCase):
112 """Functional tests for binman
113
114 Most of these use a sample .dts file to build an image and then check
115 that it looks correct. The sample files are in the test/ subdirectory
116 and are numbered.
117
118 For each entry type a very small test file is created using fixed
119 string contents. This makes it easy to test that things look right, and
120 debug problems.
121
122 In some cases a 'real' file must be used - these are also supplied in
123 the test/ diurectory.
124 """
125 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600126 def setUpClass(cls):
Simon Glass4d5994f2017-11-12 21:52:20 -0700127 global entry
Simon Glass16287932020-04-17 18:09:03 -0600128 from binman import entry
Simon Glass4d5994f2017-11-12 21:52:20 -0700129
Simon Glass4f443042016-11-25 20:15:52 -0700130 # Handle the case where argv[0] is 'python'
Simon Glassb986b3b2019-08-24 07:22:43 -0600131 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
132 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
Simon Glass4f443042016-11-25 20:15:52 -0700133
134 # Create a temporary directory for input files
Simon Glassb986b3b2019-08-24 07:22:43 -0600135 cls._indir = tempfile.mkdtemp(prefix='binmant.')
Simon Glass4f443042016-11-25 20:15:52 -0700136
137 # Create some test files
138 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
139 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
140 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glassb8ef5b62018-07-17 13:25:48 -0600141 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700142 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -0700143 TestFunctional._MakeInputFile('me.bin', ME_DATA)
144 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glassb986b3b2019-08-24 07:22:43 -0600145 cls._ResetDtbs()
Simon Glass2250ee62019-08-24 07:22:48 -0600146
Jagdish Gediya9d368f32018-09-03 21:35:08 +0530147 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glass2250ee62019-08-24 07:22:48 -0600148
Simon Glass5e239182019-08-24 07:22:49 -0600149 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
150 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
Simon Glass87722132017-11-12 21:52:26 -0700151 X86_START16_SPL_DATA)
Simon Glass5e239182019-08-24 07:22:49 -0600152 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
Simon Glass35b384c2018-09-14 04:57:10 -0600153 X86_START16_TPL_DATA)
Simon Glass2250ee62019-08-24 07:22:48 -0600154
155 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
156 X86_RESET16_DATA)
157 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
158 X86_RESET16_SPL_DATA)
159 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
160 X86_RESET16_TPL_DATA)
161
Simon Glass4f443042016-11-25 20:15:52 -0700162 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass6b187df2017-11-12 21:52:27 -0700163 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
164 U_BOOT_SPL_NODTB_DATA)
Simon Glassf0253632018-09-14 04:57:32 -0600165 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
166 U_BOOT_TPL_NODTB_DATA)
Simon Glassda229092016-11-25 20:15:56 -0700167 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
168 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Meng59ea8c22017-08-15 22:41:54 -0700169 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassca4f4ff2017-11-12 21:52:28 -0700170 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassec127af2018-07-17 13:25:39 -0600171 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glass0ef87aa2018-07-17 13:25:44 -0600172 TestFunctional._MakeInputDir('devkeys')
173 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass3ae192c2018-10-01 12:22:31 -0600174 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glassea0fff92019-08-24 07:23:07 -0600175 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
Simon Glassbc6a88f2019-10-20 21:31:35 -0600176 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
Simon Glass998d1482019-10-20 21:31:36 -0600177 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700178
Simon Glass53e22bf2019-08-24 07:22:53 -0600179 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
180 elf_test.BuildElfTestFiles(cls._elf_testdir)
181
Simon Glasse0ff8552016-11-25 20:15:53 -0700182 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glassf514d8f2019-08-24 07:22:54 -0600183 TestFunctional._MakeInputFile('u-boot',
Simon Glassc1aa66e2022-01-29 14:14:04 -0700184 tools.read_file(cls.ElfTestFile('u_boot_ucode_ptr')))
Simon Glasse0ff8552016-11-25 20:15:53 -0700185
186 # Intel flash descriptor file
Simon Glass0ba4b3d2020-07-09 18:39:41 -0600187 cls._SetupDescriptor()
Simon Glasse0ff8552016-11-25 20:15:53 -0700188
Simon Glassb986b3b2019-08-24 07:22:43 -0600189 shutil.copytree(cls.TestFile('files'),
190 os.path.join(cls._indir, 'files'))
Simon Glass0a98b282018-09-14 04:57:28 -0600191
Simon Glass83d73c22018-09-14 04:57:26 -0600192 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
Simon Glass8f5ef892020-10-26 17:40:25 -0600193 TestFunctional._MakeInputFile('compress_big', COMPRESS_DATA_BIG)
Simon Glassdc2f81a2020-09-01 05:13:58 -0600194 TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
Roger Quadros47f420a2022-02-19 20:50:04 +0200195 TestFunctional._MakeInputFile('tee-pager.bin', TEE_OS_DATA)
Simon Glass75989722021-11-23 21:08:59 -0700196 TestFunctional._MakeInputFile('bl2u.bin', ATF_BL2U_DATA)
Bin Meng4c4d6072021-05-10 20:23:33 +0800197 TestFunctional._MakeInputFile('fw_dynamic.bin', OPENSBI_DATA)
Samuel Holland18bd4552020-10-21 21:12:15 -0500198 TestFunctional._MakeInputFile('scp.bin', SCP_DATA)
Simon Glass83d73c22018-09-14 04:57:26 -0600199
Simon Glass6cf99532020-09-01 05:13:59 -0600200 # Add a few .dtb files for testing
201 TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR,
202 TEST_FDT1_DATA)
203 TestFunctional._MakeInputFile('%s/test-fdt2.dtb' % TEST_FDT_SUBDIR,
204 TEST_FDT2_DATA)
205
Simon Glassfb91d562020-09-06 10:35:33 -0600206 TestFunctional._MakeInputFile('env.txt', ENV_DATA)
207
Simon Glass40c8bdd2022-03-05 20:19:12 -0700208 # ELF file with two sections in different parts of memory, used for both
209 # ATF and OP_TEE
210 TestFunctional._MakeInputFile('bl31.elf',
211 tools.read_file(cls.ElfTestFile('elf_sections')))
212 TestFunctional._MakeInputFile('tee.elf',
213 tools.read_file(cls.ElfTestFile('elf_sections')))
214
Simon Glass33ce3512022-01-09 20:14:06 -0700215 cls.have_lz4 = comp_util.HAVE_LZ4
Simon Glassac62fba2019-07-08 13:18:53 -0600216
Simon Glass4f443042016-11-25 20:15:52 -0700217 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600218 def tearDownClass(cls):
Simon Glass4f443042016-11-25 20:15:52 -0700219 """Remove the temporary input directory and its contents"""
Simon Glassb986b3b2019-08-24 07:22:43 -0600220 if cls.preserve_indir:
221 print('Preserving input dir: %s' % cls._indir)
Simon Glassd5164a72019-07-08 13:18:49 -0600222 else:
Simon Glassb986b3b2019-08-24 07:22:43 -0600223 if cls._indir:
224 shutil.rmtree(cls._indir)
225 cls._indir = None
Simon Glass4f443042016-11-25 20:15:52 -0700226
Simon Glassd5164a72019-07-08 13:18:49 -0600227 @classmethod
Simon Glass8acce602019-07-08 13:18:50 -0600228 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
Simon Glass53cd5d92019-07-08 14:25:29 -0600229 toolpath=None, verbosity=None):
Simon Glassd5164a72019-07-08 13:18:49 -0600230 """Accept arguments controlling test execution
231
232 Args:
233 preserve_indir: Preserve the shared input directory used by all
234 tests in this class.
235 preserve_outdir: Preserve the output directories used by tests. Each
236 test has its own, so this is normally only useful when running a
237 single test.
Simon Glass8acce602019-07-08 13:18:50 -0600238 toolpath: ist of paths to use for tools
Simon Glassd5164a72019-07-08 13:18:49 -0600239 """
240 cls.preserve_indir = preserve_indir
241 cls.preserve_outdirs = preserve_outdirs
Simon Glass8acce602019-07-08 13:18:50 -0600242 cls.toolpath = toolpath
Simon Glass53cd5d92019-07-08 14:25:29 -0600243 cls.verbosity = verbosity
Simon Glassd5164a72019-07-08 13:18:49 -0600244
Simon Glassac62fba2019-07-08 13:18:53 -0600245 def _CheckLz4(self):
246 if not self.have_lz4:
247 self.skipTest('lz4 --no-frame-crc not available')
248
Simon Glassbf574f12019-07-20 12:24:09 -0600249 def _CleanupOutputDir(self):
250 """Remove the temporary output directory"""
251 if self.preserve_outdirs:
252 print('Preserving output dir: %s' % tools.outdir)
253 else:
Simon Glassc1aa66e2022-01-29 14:14:04 -0700254 tools._finalise_for_test()
Simon Glassbf574f12019-07-20 12:24:09 -0600255
Simon Glass4f443042016-11-25 20:15:52 -0700256 def setUp(self):
257 # Enable this to turn on debugging output
Simon Glassf3385a52022-01-29 14:14:15 -0700258 # tout.init(tout.DEBUG)
Simon Glass4f443042016-11-25 20:15:52 -0700259 command.test_result = None
260
261 def tearDown(self):
262 """Remove the temporary output directory"""
Simon Glassbf574f12019-07-20 12:24:09 -0600263 self._CleanupOutputDir()
Simon Glass4f443042016-11-25 20:15:52 -0700264
Simon Glassf86a7362019-07-20 12:24:10 -0600265 def _SetupImageInTmpdir(self):
266 """Set up the output image in a new temporary directory
267
268 This is used when an image has been generated in the output directory,
269 but we want to run binman again. This will create a new output
270 directory and fail to delete the original one.
271
272 This creates a new temporary directory, copies the image to it (with a
273 new name) and removes the old output directory.
274
275 Returns:
276 Tuple:
277 Temporary directory to use
278 New image filename
279 """
Simon Glassc1aa66e2022-01-29 14:14:04 -0700280 image_fname = tools.get_output_filename('image.bin')
Simon Glassf86a7362019-07-20 12:24:10 -0600281 tmpdir = tempfile.mkdtemp(prefix='binman.')
282 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
Simon Glassc1aa66e2022-01-29 14:14:04 -0700283 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassf86a7362019-07-20 12:24:10 -0600284 self._CleanupOutputDir()
285 return tmpdir, updated_fname
286
Simon Glassb8ef5b62018-07-17 13:25:48 -0600287 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600288 def _ResetDtbs(cls):
Simon Glassb8ef5b62018-07-17 13:25:48 -0600289 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
290 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
291 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
292
Simon Glass4f443042016-11-25 20:15:52 -0700293 def _RunBinman(self, *args, **kwargs):
294 """Run binman using the command line
295
296 Args:
297 Arguments to pass, as a list of strings
298 kwargs: Arguments to pass to Command.RunPipe()
299 """
Simon Glassd9800692022-01-29 14:14:05 -0700300 result = command.run_pipe([[self._binman_pathname] + list(args)],
Simon Glass4f443042016-11-25 20:15:52 -0700301 capture=True, capture_stderr=True, raise_on_error=False)
302 if result.return_code and kwargs.get('raise_on_error', True):
303 raise Exception("Error running '%s': %s" % (' '.join(args),
304 result.stdout + result.stderr))
305 return result
306
Simon Glass53cd5d92019-07-08 14:25:29 -0600307 def _DoBinman(self, *argv):
Simon Glass4f443042016-11-25 20:15:52 -0700308 """Run binman using directly (in the same process)
309
310 Args:
311 Arguments to pass, as a list of strings
312 Returns:
313 Return value (0 for success)
314 """
Simon Glass53cd5d92019-07-08 14:25:29 -0600315 argv = list(argv)
316 args = cmdline.ParseArgs(argv)
317 args.pager = 'binman-invalid-pager'
318 args.build_dir = self._indir
Simon Glass4f443042016-11-25 20:15:52 -0700319
320 # For testing, you can force an increase in verbosity here
Simon Glass53cd5d92019-07-08 14:25:29 -0600321 # args.verbosity = tout.DEBUG
322 return control.Binman(args)
Simon Glass4f443042016-11-25 20:15:52 -0700323
Simon Glass53af22a2018-07-17 13:25:32 -0600324 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glasseb833d82019-04-25 21:58:34 -0600325 entry_args=None, images=None, use_real_dtb=False,
Simon Glass63aeaeb2021-03-18 20:25:05 +1300326 use_expanded=False, verbosity=None, allow_missing=False,
Heiko Thierya89c8f22022-01-06 11:49:41 +0100327 allow_fake_blobs=False, extra_indirs=None, threads=None,
Simon Glass4f9ee832022-01-09 20:14:09 -0700328 test_section_timeout=False, update_fdt_in_elf=None,
329 force_missing_bintools=''):
Simon Glass4f443042016-11-25 20:15:52 -0700330 """Run binman with a given test file
331
332 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600333 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600334 debug: True to enable debugging output
Simon Glass3b0c38212018-06-01 09:38:20 -0600335 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600336 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600337 tree before packing it into the image
Simon Glass0bfa7b02018-09-14 04:57:12 -0600338 entry_args: Dict of entry args to supply to binman
339 key: arg name
340 value: value of that arg
341 images: List of image names to build
Simon Glasse9d336d2020-09-01 05:13:55 -0600342 use_real_dtb: True to use the test file as the contents of
343 the u-boot-dtb entry. Normally this is not needed and the
344 test contents (the U_BOOT_DTB_DATA string) can be used.
345 But in some test we need the real contents.
Simon Glass63aeaeb2021-03-18 20:25:05 +1300346 use_expanded: True to use expanded entries where available, e.g.
347 'u-boot-expanded' instead of 'u-boot'
Simon Glasse9d336d2020-09-01 05:13:55 -0600348 verbosity: Verbosity level to use (0-3, None=don't set it)
349 allow_missing: Set the '--allow-missing' flag so that missing
350 external binaries just produce a warning instead of an error
Heiko Thierya89c8f22022-01-06 11:49:41 +0100351 allow_fake_blobs: Set the '--fake-ext-blobs' flag
Simon Glass6cf99532020-09-01 05:13:59 -0600352 extra_indirs: Extra input directories to add using -I
Simon Glassc69d19c2021-07-06 10:36:37 -0600353 threads: Number of threads to use (None for default, 0 for
354 single-threaded)
Simon Glass7115f002021-11-03 21:09:17 -0600355 test_section_timeout: True to force the first time to timeout, as
356 used in testThreadTimeout()
Simon Glass0427bed2021-11-03 21:09:18 -0600357 update_fdt_in_elf: Value to pass with --update-fdt-in-elf=xxx
Simon Glass4f9ee832022-01-09 20:14:09 -0700358 force_missing_tools (str): comma-separated list of bintools to
359 regard as missing
Simon Glass7115f002021-11-03 21:09:17 -0600360
361 Returns:
362 int return code, 0 on success
Simon Glass4f443042016-11-25 20:15:52 -0700363 """
Simon Glass53cd5d92019-07-08 14:25:29 -0600364 args = []
Simon Glass7fe91732017-11-13 18:55:00 -0700365 if debug:
366 args.append('-D')
Simon Glass53cd5d92019-07-08 14:25:29 -0600367 if verbosity is not None:
368 args.append('-v%d' % verbosity)
369 elif self.verbosity:
370 args.append('-v%d' % self.verbosity)
371 if self.toolpath:
372 for path in self.toolpath:
373 args += ['--toolpath', path]
Simon Glassc69d19c2021-07-06 10:36:37 -0600374 if threads is not None:
375 args.append('-T%d' % threads)
376 if test_section_timeout:
377 args.append('--test-section-timeout')
Simon Glass53cd5d92019-07-08 14:25:29 -0600378 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass3b0c38212018-06-01 09:38:20 -0600379 if map:
380 args.append('-m')
Simon Glass16b8d6b2018-07-06 10:27:42 -0600381 if update_dtb:
Simon Glass2569e102019-07-08 13:18:47 -0600382 args.append('-u')
Simon Glass93d17412018-09-14 04:57:23 -0600383 if not use_real_dtb:
384 args.append('--fake-dtb')
Simon Glass63aeaeb2021-03-18 20:25:05 +1300385 if not use_expanded:
386 args.append('--no-expanded')
Simon Glass53af22a2018-07-17 13:25:32 -0600387 if entry_args:
Simon Glass50979152019-05-14 15:53:41 -0600388 for arg, value in entry_args.items():
Simon Glass53af22a2018-07-17 13:25:32 -0600389 args.append('-a%s=%s' % (arg, value))
Simon Glass4f9f1052020-07-09 18:39:38 -0600390 if allow_missing:
391 args.append('-M')
Heiko Thierya89c8f22022-01-06 11:49:41 +0100392 if allow_fake_blobs:
393 args.append('--fake-ext-blobs')
Simon Glass4f9ee832022-01-09 20:14:09 -0700394 if force_missing_bintools:
395 args += ['--force-missing-bintools', force_missing_bintools]
Simon Glass0427bed2021-11-03 21:09:18 -0600396 if update_fdt_in_elf:
397 args += ['--update-fdt-in-elf', update_fdt_in_elf]
Simon Glass0bfa7b02018-09-14 04:57:12 -0600398 if images:
399 for image in images:
400 args += ['-i', image]
Simon Glass6cf99532020-09-01 05:13:59 -0600401 if extra_indirs:
402 for indir in extra_indirs:
403 args += ['-I', indir]
Simon Glass7fe91732017-11-13 18:55:00 -0700404 return self._DoBinman(*args)
Simon Glass4f443042016-11-25 20:15:52 -0700405
406 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glasse0ff8552016-11-25 20:15:53 -0700407 """Set up a new test device-tree file
408
409 The given file is compiled and set up as the device tree to be used
410 for ths test.
411
412 Args:
413 fname: Filename of .dts file to read
Simon Glass7ae5f312018-06-01 09:38:19 -0600414 outfile: Output filename for compiled device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700415
416 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600417 Contents of device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700418 """
Simon Glassa004f292019-07-20 12:23:49 -0600419 tmpdir = tempfile.mkdtemp(prefix='binmant.')
420 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
Simon Glass1d0ebf72019-05-14 15:53:42 -0600421 with open(dtb, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700422 data = fd.read()
423 TestFunctional._MakeInputFile(outfile, data)
Simon Glassa004f292019-07-20 12:23:49 -0600424 shutil.rmtree(tmpdir)
Simon Glasse0e62752018-10-01 21:12:41 -0600425 return data
Simon Glass4f443042016-11-25 20:15:52 -0700426
Simon Glass6ed45ba2018-09-14 04:57:24 -0600427 def _GetDtbContentsForSplTpl(self, dtb_data, name):
428 """Create a version of the main DTB for SPL or SPL
429
430 For testing we don't actually have different versions of the DTB. With
431 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
432 we don't normally have any unwanted nodes.
433
434 We still want the DTBs for SPL and TPL to be different though, since
435 otherwise it is confusing to know which one we are looking at. So add
436 an 'spl' or 'tpl' property to the top-level node.
Simon Glasse9d336d2020-09-01 05:13:55 -0600437
438 Args:
439 dtb_data: dtb data to modify (this should be a value devicetree)
440 name: Name of a new property to add
441
442 Returns:
443 New dtb data with the property added
Simon Glass6ed45ba2018-09-14 04:57:24 -0600444 """
445 dtb = fdt.Fdt.FromData(dtb_data)
446 dtb.Scan()
447 dtb.GetNode('/binman').AddZeroProp(name)
448 dtb.Sync(auto_resize=True)
449 dtb.Pack()
450 return dtb.GetContents()
451
Simon Glass63aeaeb2021-03-18 20:25:05 +1300452 def _DoReadFileDtb(self, fname, use_real_dtb=False, use_expanded=False,
453 map=False, update_dtb=False, entry_args=None,
Simon Glassc69d19c2021-07-06 10:36:37 -0600454 reset_dtbs=True, extra_indirs=None, threads=None):
Simon Glass4f443042016-11-25 20:15:52 -0700455 """Run binman and return the resulting image
456
457 This runs binman with a given test file and then reads the resulting
458 output file. It is a shortcut function since most tests need to do
459 these steps.
460
461 Raises an assertion failure if binman returns a non-zero exit code.
462
463 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600464 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass4f443042016-11-25 20:15:52 -0700465 use_real_dtb: True to use the test file as the contents of
466 the u-boot-dtb entry. Normally this is not needed and the
467 test contents (the U_BOOT_DTB_DATA string) can be used.
468 But in some test we need the real contents.
Simon Glass63aeaeb2021-03-18 20:25:05 +1300469 use_expanded: True to use expanded entries where available, e.g.
470 'u-boot-expanded' instead of 'u-boot'
Simon Glass3b0c38212018-06-01 09:38:20 -0600471 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600472 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600473 tree before packing it into the image
Simon Glasse9d336d2020-09-01 05:13:55 -0600474 entry_args: Dict of entry args to supply to binman
475 key: arg name
476 value: value of that arg
477 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
478 function. If reset_dtbs is True, then the original test dtb
479 is written back before this function finishes
Simon Glass6cf99532020-09-01 05:13:59 -0600480 extra_indirs: Extra input directories to add using -I
Simon Glassc69d19c2021-07-06 10:36:37 -0600481 threads: Number of threads to use (None for default, 0 for
482 single-threaded)
Simon Glasse0ff8552016-11-25 20:15:53 -0700483
484 Returns:
485 Tuple:
486 Resulting image contents
487 Device tree contents
Simon Glass3b0c38212018-06-01 09:38:20 -0600488 Map data showing contents of image (or None if none)
Simon Glassea6922e2018-07-17 13:25:27 -0600489 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass4f443042016-11-25 20:15:52 -0700490 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700491 dtb_data = None
Simon Glass4f443042016-11-25 20:15:52 -0700492 # Use the compiled test file as the u-boot-dtb input
493 if use_real_dtb:
Simon Glasse0ff8552016-11-25 20:15:53 -0700494 dtb_data = self._SetupDtb(fname)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600495
496 # For testing purposes, make a copy of the DT for SPL and TPL. Add
497 # a node indicating which it is, so aid verification.
498 for name in ['spl', 'tpl']:
499 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
500 outfile = os.path.join(self._indir, dtb_fname)
501 TestFunctional._MakeInputFile(dtb_fname,
502 self._GetDtbContentsForSplTpl(dtb_data, name))
Simon Glass4f443042016-11-25 20:15:52 -0700503
504 try:
Simon Glass53af22a2018-07-17 13:25:32 -0600505 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glass6cf99532020-09-01 05:13:59 -0600506 entry_args=entry_args, use_real_dtb=use_real_dtb,
Simon Glassc69d19c2021-07-06 10:36:37 -0600507 use_expanded=use_expanded, extra_indirs=extra_indirs,
508 threads=threads)
Simon Glass4f443042016-11-25 20:15:52 -0700509 self.assertEqual(0, retcode)
Simon Glassc1aa66e2022-01-29 14:14:04 -0700510 out_dtb_fname = tools.get_output_filename('u-boot.dtb.out')
Simon Glass4f443042016-11-25 20:15:52 -0700511
512 # Find the (only) image, read it and return its contents
513 image = control.images['image']
Simon Glassc1aa66e2022-01-29 14:14:04 -0700514 image_fname = tools.get_output_filename('image.bin')
Simon Glass16b8d6b2018-07-06 10:27:42 -0600515 self.assertTrue(os.path.exists(image_fname))
Simon Glass3b0c38212018-06-01 09:38:20 -0600516 if map:
Simon Glassc1aa66e2022-01-29 14:14:04 -0700517 map_fname = tools.get_output_filename('image.map')
Simon Glass3b0c38212018-06-01 09:38:20 -0600518 with open(map_fname) as fd:
519 map_data = fd.read()
520 else:
521 map_data = None
Simon Glass1d0ebf72019-05-14 15:53:42 -0600522 with open(image_fname, 'rb') as fd:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600523 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass4f443042016-11-25 20:15:52 -0700524 finally:
525 # Put the test file back
Simon Glass6ed45ba2018-09-14 04:57:24 -0600526 if reset_dtbs and use_real_dtb:
Simon Glassb8ef5b62018-07-17 13:25:48 -0600527 self._ResetDtbs()
Simon Glass4f443042016-11-25 20:15:52 -0700528
Simon Glass3c081312019-07-08 14:25:26 -0600529 def _DoReadFileRealDtb(self, fname):
530 """Run binman with a real .dtb file and return the resulting data
531
532 Args:
533 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
534
535 Returns:
536 Resulting image contents
537 """
538 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
539
Simon Glasse0ff8552016-11-25 20:15:53 -0700540 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass7ae5f312018-06-01 09:38:19 -0600541 """Helper function which discards the device-tree binary
542
543 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600544 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600545 use_real_dtb: True to use the test file as the contents of
546 the u-boot-dtb entry. Normally this is not needed and the
547 test contents (the U_BOOT_DTB_DATA string) can be used.
548 But in some test we need the real contents.
Simon Glassea6922e2018-07-17 13:25:27 -0600549
550 Returns:
551 Resulting image contents
Simon Glass7ae5f312018-06-01 09:38:19 -0600552 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700553 return self._DoReadFileDtb(fname, use_real_dtb)[0]
554
Simon Glass4f443042016-11-25 20:15:52 -0700555 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600556 def _MakeInputFile(cls, fname, contents):
Simon Glass4f443042016-11-25 20:15:52 -0700557 """Create a new test input file, creating directories as needed
558
559 Args:
Simon Glass3ab95982018-08-01 15:22:37 -0600560 fname: Filename to create
Simon Glass4f443042016-11-25 20:15:52 -0700561 contents: File contents to write in to the file
562 Returns:
563 Full pathname of file created
564 """
Simon Glassb986b3b2019-08-24 07:22:43 -0600565 pathname = os.path.join(cls._indir, fname)
Simon Glass4f443042016-11-25 20:15:52 -0700566 dirname = os.path.dirname(pathname)
567 if dirname and not os.path.exists(dirname):
568 os.makedirs(dirname)
569 with open(pathname, 'wb') as fd:
570 fd.write(contents)
571 return pathname
572
573 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600574 def _MakeInputDir(cls, dirname):
Simon Glass0ef87aa2018-07-17 13:25:44 -0600575 """Create a new test input directory, creating directories as needed
576
577 Args:
578 dirname: Directory name to create
579
580 Returns:
581 Full pathname of directory created
582 """
Simon Glassb986b3b2019-08-24 07:22:43 -0600583 pathname = os.path.join(cls._indir, dirname)
Simon Glass0ef87aa2018-07-17 13:25:44 -0600584 if not os.path.exists(pathname):
585 os.makedirs(pathname)
586 return pathname
587
588 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600589 def _SetupSplElf(cls, src_fname='bss_data'):
Simon Glass11ae93e2018-10-01 21:12:47 -0600590 """Set up an ELF file with a '_dt_ucode_base_size' symbol
591
592 Args:
593 Filename of ELF file to use as SPL
594 """
Simon Glassc9a0b272019-08-24 07:22:59 -0600595 TestFunctional._MakeInputFile('spl/u-boot-spl',
Simon Glassc1aa66e2022-01-29 14:14:04 -0700596 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass11ae93e2018-10-01 21:12:47 -0600597
598 @classmethod
Simon Glass2090f1e2019-08-24 07:23:00 -0600599 def _SetupTplElf(cls, src_fname='bss_data'):
600 """Set up an ELF file with a '_dt_ucode_base_size' symbol
601
602 Args:
603 Filename of ELF file to use as TPL
604 """
605 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
Simon Glassc1aa66e2022-01-29 14:14:04 -0700606 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass2090f1e2019-08-24 07:23:00 -0600607
608 @classmethod
Simon Glass0ba4b3d2020-07-09 18:39:41 -0600609 def _SetupDescriptor(cls):
610 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
611 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
612
613 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600614 def TestFile(cls, fname):
615 return os.path.join(cls._binman_dir, 'test', fname)
Simon Glass4f443042016-11-25 20:15:52 -0700616
Simon Glass53e22bf2019-08-24 07:22:53 -0600617 @classmethod
618 def ElfTestFile(cls, fname):
619 return os.path.join(cls._elf_testdir, fname)
620
Simon Glass4f443042016-11-25 20:15:52 -0700621 def AssertInList(self, grep_list, target):
622 """Assert that at least one of a list of things is in a target
623
624 Args:
625 grep_list: List of strings to check
626 target: Target string
627 """
628 for grep in grep_list:
629 if grep in target:
630 return
Simon Glass1fc62de2019-05-17 22:00:50 -0600631 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass4f443042016-11-25 20:15:52 -0700632
633 def CheckNoGaps(self, entries):
634 """Check that all entries fit together without gaps
635
636 Args:
637 entries: List of entries to check
638 """
Simon Glass3ab95982018-08-01 15:22:37 -0600639 offset = 0
Simon Glass4f443042016-11-25 20:15:52 -0700640 for entry in entries.values():
Simon Glass3ab95982018-08-01 15:22:37 -0600641 self.assertEqual(offset, entry.offset)
642 offset += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700643
Simon Glasse0ff8552016-11-25 20:15:53 -0700644 def GetFdtLen(self, dtb):
Simon Glass7ae5f312018-06-01 09:38:19 -0600645 """Get the totalsize field from a device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700646
647 Args:
Simon Glass7ae5f312018-06-01 09:38:19 -0600648 dtb: Device-tree binary contents
Simon Glasse0ff8552016-11-25 20:15:53 -0700649
650 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600651 Total size of device-tree binary, from the header
Simon Glasse0ff8552016-11-25 20:15:53 -0700652 """
653 return struct.unpack('>L', dtb[4:8])[0]
654
Simon Glass086cec92019-07-08 14:25:27 -0600655 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glass16b8d6b2018-07-06 10:27:42 -0600656 def AddNode(node, path):
657 if node.name != '/':
658 path += '/' + node.name
Simon Glass086cec92019-07-08 14:25:27 -0600659 for prop in node.props.values():
660 if prop.name in prop_names:
661 prop_path = path + ':' + prop.name
662 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
663 prop.value)
Simon Glass16b8d6b2018-07-06 10:27:42 -0600664 for subnode in node.subnodes:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600665 AddNode(subnode, path)
666
667 tree = {}
Simon Glass16b8d6b2018-07-06 10:27:42 -0600668 AddNode(dtb.GetRoot(), '')
669 return tree
670
Simon Glass4f443042016-11-25 20:15:52 -0700671 def testRun(self):
672 """Test a basic run with valid args"""
673 result = self._RunBinman('-h')
674
675 def testFullHelp(self):
676 """Test that the full help is displayed with -H"""
677 result = self._RunBinman('-H')
Simon Glass61adb2d2021-03-18 20:25:13 +1300678 help_file = os.path.join(self._binman_dir, 'README.rst')
Tom Rini3759df02018-01-16 15:29:50 -0500679 # Remove possible extraneous strings
680 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
681 gothelp = result.stdout.replace(extra, '')
682 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass4f443042016-11-25 20:15:52 -0700683 self.assertEqual(0, len(result.stderr))
684 self.assertEqual(0, result.return_code)
685
686 def testFullHelpInternal(self):
687 """Test that the full help is displayed with -H"""
688 try:
689 command.test_result = command.CommandResult()
690 result = self._DoBinman('-H')
Simon Glass61adb2d2021-03-18 20:25:13 +1300691 help_file = os.path.join(self._binman_dir, 'README.rst')
Simon Glass4f443042016-11-25 20:15:52 -0700692 finally:
693 command.test_result = None
694
695 def testHelp(self):
696 """Test that the basic help is displayed with -h"""
697 result = self._RunBinman('-h')
698 self.assertTrue(len(result.stdout) > 200)
699 self.assertEqual(0, len(result.stderr))
700 self.assertEqual(0, result.return_code)
701
Simon Glass4f443042016-11-25 20:15:52 -0700702 def testBoard(self):
703 """Test that we can run it with a specific board"""
Simon Glass741f2d62018-10-01 12:22:30 -0600704 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass4f443042016-11-25 20:15:52 -0700705 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glass63aeaeb2021-03-18 20:25:05 +1300706 result = self._DoBinman('build', '-n', '-b', 'sandbox')
Simon Glass4f443042016-11-25 20:15:52 -0700707 self.assertEqual(0, result)
708
709 def testNeedBoard(self):
710 """Test that we get an error when no board ius supplied"""
711 with self.assertRaises(ValueError) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600712 result = self._DoBinman('build')
Simon Glass4f443042016-11-25 20:15:52 -0700713 self.assertIn("Must provide a board to process (use -b <board>)",
714 str(e.exception))
715
716 def testMissingDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600717 """Test that an invalid device-tree file generates an error"""
Simon Glass4f443042016-11-25 20:15:52 -0700718 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600719 self._RunBinman('build', '-d', 'missing_file')
Simon Glass4f443042016-11-25 20:15:52 -0700720 # We get one error from libfdt, and a different one from fdtget.
721 self.AssertInList(["Couldn't open blob from 'missing_file'",
722 'No such file or directory'], str(e.exception))
723
724 def testBrokenDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600725 """Test that an invalid device-tree source file generates an error
Simon Glass4f443042016-11-25 20:15:52 -0700726
727 Since this is a source file it should be compiled and the error
728 will come from the device-tree compiler (dtc).
729 """
730 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600731 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700732 self.assertIn("FATAL ERROR: Unable to parse input tree",
733 str(e.exception))
734
735 def testMissingNode(self):
736 """Test that a device tree without a 'binman' node generates an error"""
737 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600738 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700739 self.assertIn("does not have a 'binman' node", str(e.exception))
740
741 def testEmpty(self):
742 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glass53cd5d92019-07-08 14:25:29 -0600743 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700744 self.assertEqual(0, len(result.stderr))
745 self.assertEqual(0, result.return_code)
746
747 def testInvalidEntry(self):
748 """Test that an invalid entry is flagged"""
749 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600750 result = self._RunBinman('build', '-d',
Simon Glass741f2d62018-10-01 12:22:30 -0600751 self.TestFile('004_invalid_entry.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700752 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
753 "'/binman/not-a-valid-type'", str(e.exception))
754
755 def testSimple(self):
756 """Test a simple binman with a single file"""
Simon Glass741f2d62018-10-01 12:22:30 -0600757 data = self._DoReadFile('005_simple.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700758 self.assertEqual(U_BOOT_DATA, data)
759
Simon Glass7fe91732017-11-13 18:55:00 -0700760 def testSimpleDebug(self):
761 """Test a simple binman run with debugging enabled"""
Simon Glasse2705fa2019-07-08 14:25:53 -0600762 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass7fe91732017-11-13 18:55:00 -0700763
Simon Glass4f443042016-11-25 20:15:52 -0700764 def testDual(self):
765 """Test that we can handle creating two images
766
767 This also tests image padding.
768 """
Simon Glass741f2d62018-10-01 12:22:30 -0600769 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700770 self.assertEqual(0, retcode)
771
772 image = control.images['image1']
Simon Glass8beb11e2019-07-08 14:25:47 -0600773 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glassc1aa66e2022-01-29 14:14:04 -0700774 fname = tools.get_output_filename('image1.bin')
Simon Glass4f443042016-11-25 20:15:52 -0700775 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600776 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700777 data = fd.read()
778 self.assertEqual(U_BOOT_DATA, data)
779
780 image = control.images['image2']
Simon Glass8beb11e2019-07-08 14:25:47 -0600781 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glassc1aa66e2022-01-29 14:14:04 -0700782 fname = tools.get_output_filename('image2.bin')
Simon Glass4f443042016-11-25 20:15:52 -0700783 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600784 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700785 data = fd.read()
786 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glassc1aa66e2022-01-29 14:14:04 -0700787 self.assertEqual(tools.get_bytes(0, 3), data[:3])
788 self.assertEqual(tools.get_bytes(0, 5), data[7:])
Simon Glass4f443042016-11-25 20:15:52 -0700789
790 def testBadAlign(self):
791 """Test that an invalid alignment value is detected"""
792 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600793 self._DoTestFile('007_bad_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700794 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
795 "of two", str(e.exception))
796
797 def testPackSimple(self):
798 """Test that packing works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600799 retcode = self._DoTestFile('008_pack.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700800 self.assertEqual(0, retcode)
801 self.assertIn('image', control.images)
802 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600803 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700804 self.assertEqual(5, len(entries))
805
806 # First u-boot
807 self.assertIn('u-boot', entries)
808 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600809 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700810 self.assertEqual(len(U_BOOT_DATA), entry.size)
811
812 # Second u-boot, aligned to 16-byte boundary
813 self.assertIn('u-boot-align', entries)
814 entry = entries['u-boot-align']
Simon Glass3ab95982018-08-01 15:22:37 -0600815 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700816 self.assertEqual(len(U_BOOT_DATA), entry.size)
817
818 # Third u-boot, size 23 bytes
819 self.assertIn('u-boot-size', entries)
820 entry = entries['u-boot-size']
Simon Glass3ab95982018-08-01 15:22:37 -0600821 self.assertEqual(20, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700822 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
823 self.assertEqual(23, entry.size)
824
825 # Fourth u-boot, placed immediate after the above
826 self.assertIn('u-boot-next', entries)
827 entry = entries['u-boot-next']
Simon Glass3ab95982018-08-01 15:22:37 -0600828 self.assertEqual(43, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700829 self.assertEqual(len(U_BOOT_DATA), entry.size)
830
Simon Glass3ab95982018-08-01 15:22:37 -0600831 # Fifth u-boot, placed at a fixed offset
Simon Glass4f443042016-11-25 20:15:52 -0700832 self.assertIn('u-boot-fixed', entries)
833 entry = entries['u-boot-fixed']
Simon Glass3ab95982018-08-01 15:22:37 -0600834 self.assertEqual(61, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700835 self.assertEqual(len(U_BOOT_DATA), entry.size)
836
Simon Glass8beb11e2019-07-08 14:25:47 -0600837 self.assertEqual(65, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700838
839 def testPackExtra(self):
840 """Test that extra packing feature works as expected"""
Simon Glass4eec34c2020-10-26 17:40:10 -0600841 data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
842 update_dtb=True)
Simon Glass4f443042016-11-25 20:15:52 -0700843
Simon Glass4f443042016-11-25 20:15:52 -0700844 self.assertIn('image', control.images)
845 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600846 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700847 self.assertEqual(5, len(entries))
848
849 # First u-boot with padding before and after
850 self.assertIn('u-boot', entries)
851 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600852 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700853 self.assertEqual(3, entry.pad_before)
854 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600855 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassc1aa66e2022-01-29 14:14:04 -0700856 self.assertEqual(tools.get_bytes(0, 3) + U_BOOT_DATA +
857 tools.get_bytes(0, 5), data[:entry.size])
Simon Glassef439ed2020-10-26 17:40:08 -0600858 pos = entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700859
860 # Second u-boot has an aligned size, but it has no effect
861 self.assertIn('u-boot-align-size-nop', entries)
862 entry = entries['u-boot-align-size-nop']
Simon Glassef439ed2020-10-26 17:40:08 -0600863 self.assertEqual(pos, entry.offset)
864 self.assertEqual(len(U_BOOT_DATA), entry.size)
865 self.assertEqual(U_BOOT_DATA, entry.data)
866 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
867 pos += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700868
869 # Third u-boot has an aligned size too
870 self.assertIn('u-boot-align-size', entries)
871 entry = entries['u-boot-align-size']
Simon Glassef439ed2020-10-26 17:40:08 -0600872 self.assertEqual(pos, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700873 self.assertEqual(32, entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600874 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassc1aa66e2022-01-29 14:14:04 -0700875 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
Simon Glassef439ed2020-10-26 17:40:08 -0600876 data[pos:pos + entry.size])
877 pos += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700878
879 # Fourth u-boot has an aligned end
880 self.assertIn('u-boot-align-end', entries)
881 entry = entries['u-boot-align-end']
Simon Glass3ab95982018-08-01 15:22:37 -0600882 self.assertEqual(48, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700883 self.assertEqual(16, entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600884 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glassc1aa66e2022-01-29 14:14:04 -0700885 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 16 - len(U_BOOT_DATA)),
Simon Glassef439ed2020-10-26 17:40:08 -0600886 data[pos:pos + entry.size])
887 pos += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700888
889 # Fifth u-boot immediately afterwards
890 self.assertIn('u-boot-align-both', entries)
891 entry = entries['u-boot-align-both']
Simon Glass3ab95982018-08-01 15:22:37 -0600892 self.assertEqual(64, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700893 self.assertEqual(64, entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600894 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glassc1aa66e2022-01-29 14:14:04 -0700895 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 64 - len(U_BOOT_DATA)),
Simon Glassef439ed2020-10-26 17:40:08 -0600896 data[pos:pos + entry.size])
Simon Glass4f443042016-11-25 20:15:52 -0700897
898 self.CheckNoGaps(entries)
Simon Glass8beb11e2019-07-08 14:25:47 -0600899 self.assertEqual(128, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700900
Simon Glass4eec34c2020-10-26 17:40:10 -0600901 dtb = fdt.Fdt(out_dtb_fname)
902 dtb.Scan()
903 props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
904 expected = {
905 'image-pos': 0,
906 'offset': 0,
907 'size': 128,
908
909 'u-boot:image-pos': 0,
910 'u-boot:offset': 0,
911 'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
912
913 'u-boot-align-size-nop:image-pos': 12,
914 'u-boot-align-size-nop:offset': 12,
915 'u-boot-align-size-nop:size': 4,
916
917 'u-boot-align-size:image-pos': 16,
918 'u-boot-align-size:offset': 16,
919 'u-boot-align-size:size': 32,
920
921 'u-boot-align-end:image-pos': 48,
922 'u-boot-align-end:offset': 48,
923 'u-boot-align-end:size': 16,
924
925 'u-boot-align-both:image-pos': 64,
926 'u-boot-align-both:offset': 64,
927 'u-boot-align-both:size': 64,
928 }
929 self.assertEqual(expected, props)
930
Simon Glass4f443042016-11-25 20:15:52 -0700931 def testPackAlignPowerOf2(self):
932 """Test that invalid entry alignment is detected"""
933 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600934 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700935 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
936 "of two", str(e.exception))
937
938 def testPackAlignSizePowerOf2(self):
939 """Test that invalid entry size alignment is detected"""
940 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600941 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700942 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
943 "power of two", str(e.exception))
944
945 def testPackInvalidAlign(self):
Simon Glass3ab95982018-08-01 15:22:37 -0600946 """Test detection of an offset that does not match its alignment"""
Simon Glass4f443042016-11-25 20:15:52 -0700947 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600948 self._DoTestFile('012_pack_inv_align.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600949 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700950 "align 0x4 (4)", str(e.exception))
951
952 def testPackInvalidSizeAlign(self):
953 """Test that invalid entry size alignment is detected"""
954 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600955 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700956 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
957 "align-size 0x4 (4)", str(e.exception))
958
959 def testPackOverlap(self):
960 """Test that overlapping regions are detected"""
961 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600962 self._DoTestFile('014_pack_overlap.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600963 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -0700964 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
965 str(e.exception))
966
967 def testPackEntryOverflow(self):
968 """Test that entries that overflow their size are detected"""
969 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600970 self._DoTestFile('015_pack_overflow.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700971 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
972 "but entry size is 0x3 (3)", str(e.exception))
973
974 def testPackImageOverflow(self):
975 """Test that entries which overflow the image size are detected"""
976 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600977 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600978 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass4f443042016-11-25 20:15:52 -0700979 "size 0x3 (3)", str(e.exception))
980
981 def testPackImageSize(self):
982 """Test that the image size can be set"""
Simon Glass741f2d62018-10-01 12:22:30 -0600983 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700984 self.assertEqual(0, retcode)
985 self.assertIn('image', control.images)
986 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -0600987 self.assertEqual(7, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700988
989 def testPackImageSizeAlign(self):
990 """Test that image size alignemnt works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600991 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700992 self.assertEqual(0, retcode)
993 self.assertIn('image', control.images)
994 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -0600995 self.assertEqual(16, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700996
997 def testPackInvalidImageAlign(self):
998 """Test that invalid image alignment is detected"""
999 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001000 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glass8f1da502018-06-01 09:38:12 -06001001 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass4f443042016-11-25 20:15:52 -07001002 "align-size 0x8 (8)", str(e.exception))
1003
Simon Glass8d2ef3e2022-02-11 13:23:21 -07001004 def testPackAlignPowerOf2Inv(self):
Simon Glass4f443042016-11-25 20:15:52 -07001005 """Test that invalid image alignment is detected"""
1006 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001007 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -06001008 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass4f443042016-11-25 20:15:52 -07001009 "two", str(e.exception))
1010
1011 def testImagePadByte(self):
1012 """Test that the image pad byte can be specified"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001013 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001014 data = self._DoReadFile('021_image_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001015 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0xff, 1) +
Simon Glasse6d85ff2019-05-14 15:53:47 -06001016 U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -07001017
1018 def testImageName(self):
1019 """Test that image files can be named"""
Simon Glass741f2d62018-10-01 12:22:30 -06001020 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001021 self.assertEqual(0, retcode)
1022 image = control.images['image1']
Simon Glassc1aa66e2022-01-29 14:14:04 -07001023 fname = tools.get_output_filename('test-name')
Simon Glass4f443042016-11-25 20:15:52 -07001024 self.assertTrue(os.path.exists(fname))
1025
1026 image = control.images['image2']
Simon Glassc1aa66e2022-01-29 14:14:04 -07001027 fname = tools.get_output_filename('test-name.xx')
Simon Glass4f443042016-11-25 20:15:52 -07001028 self.assertTrue(os.path.exists(fname))
1029
1030 def testBlobFilename(self):
1031 """Test that generic blobs can be provided by filename"""
Simon Glass741f2d62018-10-01 12:22:30 -06001032 data = self._DoReadFile('023_blob.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001033 self.assertEqual(BLOB_DATA, data)
1034
1035 def testPackSorted(self):
1036 """Test that entries can be sorted"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001037 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001038 data = self._DoReadFile('024_sorted.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001039 self.assertEqual(tools.get_bytes(0, 1) + U_BOOT_SPL_DATA +
1040 tools.get_bytes(0, 2) + U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -07001041
Simon Glass3ab95982018-08-01 15:22:37 -06001042 def testPackZeroOffset(self):
1043 """Test that an entry at offset 0 is not given a new offset"""
Simon Glass4f443042016-11-25 20:15:52 -07001044 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001045 self._DoTestFile('025_pack_zero_size.dts')
Simon Glass3ab95982018-08-01 15:22:37 -06001046 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -07001047 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1048 str(e.exception))
1049
1050 def testPackUbootDtb(self):
1051 """Test that a device tree can be added to U-Boot"""
Simon Glass741f2d62018-10-01 12:22:30 -06001052 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001053 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glasse0ff8552016-11-25 20:15:53 -07001054
1055 def testPackX86RomNoSize(self):
1056 """Test that the end-at-4gb property requires a size property"""
1057 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001058 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -06001059 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glasse0ff8552016-11-25 20:15:53 -07001060 "using end-at-4gb", str(e.exception))
1061
Jagdish Gediya94b57db2018-09-03 21:35:07 +05301062 def test4gbAndSkipAtStartTogether(self):
1063 """Test that the end-at-4gb and skip-at-size property can't be used
1064 together"""
1065 with self.assertRaises(ValueError) as e:
Simon Glassdfdd2b62019-08-24 07:23:02 -06001066 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -06001067 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya94b57db2018-09-03 21:35:07 +05301068 "'skip-at-start'", str(e.exception))
1069
Simon Glasse0ff8552016-11-25 20:15:53 -07001070 def testPackX86RomOutside(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001071 """Test that the end-at-4gb property checks for offset boundaries"""
Simon Glasse0ff8552016-11-25 20:15:53 -07001072 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001073 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glasse6bed4f2020-10-26 17:40:05 -06001074 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
1075 "is outside the section '/binman' starting at "
1076 '0xffffffe0 (4294967264) of size 0x20 (32)',
Simon Glasse0ff8552016-11-25 20:15:53 -07001077 str(e.exception))
1078
1079 def testPackX86Rom(self):
1080 """Test that a basic x86 ROM can be created"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001081 self._SetupSplElf()
Simon Glass9255f3c2019-08-24 07:23:01 -06001082 data = self._DoReadFile('029_x86_rom.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001083 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 3) + U_BOOT_SPL_DATA +
1084 tools.get_bytes(0, 2), data)
Simon Glasse0ff8552016-11-25 20:15:53 -07001085
1086 def testPackX86RomMeNoDesc(self):
1087 """Test that an invalid Intel descriptor entry is detected"""
Simon Glass0ba4b3d2020-07-09 18:39:41 -06001088 try:
Simon Glass52b10dd2020-07-25 15:11:19 -06001089 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
Simon Glass0ba4b3d2020-07-09 18:39:41 -06001090 with self.assertRaises(ValueError) as e:
Simon Glass52b10dd2020-07-25 15:11:19 -06001091 self._DoTestFile('163_x86_rom_me_empty.dts')
Simon Glass0ba4b3d2020-07-09 18:39:41 -06001092 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1093 str(e.exception))
1094 finally:
1095 self._SetupDescriptor()
Simon Glasse0ff8552016-11-25 20:15:53 -07001096
1097 def testPackX86RomBadDesc(self):
1098 """Test that the Intel requires a descriptor entry"""
1099 with self.assertRaises(ValueError) as e:
Simon Glass9255f3c2019-08-24 07:23:01 -06001100 self._DoTestFile('030_x86_rom_me_no_desc.dts')
Simon Glass3ab95982018-08-01 15:22:37 -06001101 self.assertIn("Node '/binman/intel-me': No offset set with "
1102 "offset-unset: should another entry provide this correct "
1103 "offset?", str(e.exception))
Simon Glasse0ff8552016-11-25 20:15:53 -07001104
1105 def testPackX86RomMe(self):
1106 """Test that an x86 ROM with an ME region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001107 data = self._DoReadFile('031_x86_rom_me.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001108 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glassc5ac1382019-07-08 13:18:54 -06001109 if data[:0x1000] != expected_desc:
1110 self.fail('Expected descriptor binary at start of image')
Simon Glasse0ff8552016-11-25 20:15:53 -07001111 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1112
1113 def testPackVga(self):
1114 """Test that an image with a VGA binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001115 data = self._DoReadFile('032_intel_vga.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -07001116 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1117
1118 def testPackStart16(self):
1119 """Test that an image with an x86 start16 region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001120 data = self._DoReadFile('033_x86_start16.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -07001121 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1122
Jagdish Gediya9d368f32018-09-03 21:35:08 +05301123 def testPackPowerpcMpc85xxBootpgResetvec(self):
1124 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1125 created"""
Simon Glassdfdd2b62019-08-24 07:23:02 -06001126 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
Jagdish Gediya9d368f32018-09-03 21:35:08 +05301127 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1128
Simon Glass736bb0a2018-07-06 10:27:17 -06001129 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glassadc57012018-07-06 10:27:16 -06001130 """Handle running a test for insertion of microcode
1131
1132 Args:
1133 dts_fname: Name of test .dts file
1134 nodtb_data: Data that we expect in the first section
Simon Glass736bb0a2018-07-06 10:27:17 -06001135 ucode_second: True if the microsecond entry is second instead of
1136 third
Simon Glassadc57012018-07-06 10:27:16 -06001137
1138 Returns:
1139 Tuple:
1140 Contents of first region (U-Boot or SPL)
Simon Glass3ab95982018-08-01 15:22:37 -06001141 Offset and size components of microcode pointer, as inserted
Simon Glassadc57012018-07-06 10:27:16 -06001142 in the above (two 4-byte words)
1143 """
Simon Glass6b187df2017-11-12 21:52:27 -07001144 data = self._DoReadFile(dts_fname, True)
Simon Glasse0ff8552016-11-25 20:15:53 -07001145
1146 # Now check the device tree has no microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001147 if ucode_second:
1148 ucode_content = data[len(nodtb_data):]
1149 ucode_pos = len(nodtb_data)
1150 dtb_with_ucode = ucode_content[16:]
1151 fdt_len = self.GetFdtLen(dtb_with_ucode)
1152 else:
1153 dtb_with_ucode = data[len(nodtb_data):]
1154 fdt_len = self.GetFdtLen(dtb_with_ucode)
1155 ucode_content = dtb_with_ucode[fdt_len:]
1156 ucode_pos = len(nodtb_data) + fdt_len
Simon Glassc1aa66e2022-01-29 14:14:04 -07001157 fname = tools.get_output_filename('test.dtb')
Simon Glasse0ff8552016-11-25 20:15:53 -07001158 with open(fname, 'wb') as fd:
Simon Glassadc57012018-07-06 10:27:16 -06001159 fd.write(dtb_with_ucode)
Simon Glassec3f3782017-05-27 07:38:29 -06001160 dtb = fdt.FdtScan(fname)
1161 ucode = dtb.GetNode('/microcode')
Simon Glasse0ff8552016-11-25 20:15:53 -07001162 self.assertTrue(ucode)
1163 for node in ucode.subnodes:
1164 self.assertFalse(node.props.get('data'))
1165
Simon Glasse0ff8552016-11-25 20:15:53 -07001166 # Check that the microcode appears immediately after the Fdt
1167 # This matches the concatenation of the data properties in
Simon Glass87722132017-11-12 21:52:26 -07001168 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glasse0ff8552016-11-25 20:15:53 -07001169 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1170 0x78235609)
Simon Glassadc57012018-07-06 10:27:16 -06001171 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glasse0ff8552016-11-25 20:15:53 -07001172
1173 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -06001174 # expected offset and size
Simon Glasse0ff8552016-11-25 20:15:53 -07001175 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1176 len(ucode_data))
Simon Glass736bb0a2018-07-06 10:27:17 -06001177 u_boot = data[:len(nodtb_data)]
1178 return u_boot, pos_and_size
Simon Glass6b187df2017-11-12 21:52:27 -07001179
1180 def testPackUbootMicrocode(self):
1181 """Test that x86 microcode can be handled correctly
1182
1183 We expect to see the following in the image, in order:
1184 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1185 place
1186 u-boot.dtb with the microcode removed
1187 the microcode
1188 """
Simon Glass741f2d62018-10-01 12:22:30 -06001189 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass6b187df2017-11-12 21:52:27 -07001190 U_BOOT_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001191 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1192 b' somewhere in here', first)
Simon Glasse0ff8552016-11-25 20:15:53 -07001193
Simon Glass160a7662017-05-27 07:38:26 -06001194 def _RunPackUbootSingleMicrocode(self):
Simon Glasse0ff8552016-11-25 20:15:53 -07001195 """Test that x86 microcode can be handled correctly
1196
1197 We expect to see the following in the image, in order:
1198 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1199 place
1200 u-boot.dtb with the microcode
1201 an empty microcode region
1202 """
1203 # We need the libfdt library to run this test since only that allows
1204 # finding the offset of a property. This is required by
1205 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass741f2d62018-10-01 12:22:30 -06001206 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glasse0ff8552016-11-25 20:15:53 -07001207
1208 second = data[len(U_BOOT_NODTB_DATA):]
1209
1210 fdt_len = self.GetFdtLen(second)
1211 third = second[fdt_len:]
1212 second = second[:fdt_len]
1213
Simon Glass160a7662017-05-27 07:38:26 -06001214 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1215 self.assertIn(ucode_data, second)
1216 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -07001217
Simon Glass160a7662017-05-27 07:38:26 -06001218 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -06001219 # expected offset and size
Simon Glass160a7662017-05-27 07:38:26 -06001220 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1221 len(ucode_data))
1222 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glassc6c10e72019-05-17 22:00:46 -06001223 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1224 b' somewhere in here', first)
Simon Glassc49deb82016-11-25 20:15:54 -07001225
Simon Glass75db0862016-11-25 20:15:55 -07001226 def testPackUbootSingleMicrocode(self):
1227 """Test that x86 microcode can be handled correctly with fdt_normal.
1228 """
Simon Glass160a7662017-05-27 07:38:26 -06001229 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001230
Simon Glassc49deb82016-11-25 20:15:54 -07001231 def testUBootImg(self):
1232 """Test that u-boot.img can be put in a file"""
Simon Glass741f2d62018-10-01 12:22:30 -06001233 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glassc49deb82016-11-25 20:15:54 -07001234 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glass75db0862016-11-25 20:15:55 -07001235
1236 def testNoMicrocode(self):
1237 """Test that a missing microcode region is detected"""
1238 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001239 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001240 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1241 "node found in ", str(e.exception))
1242
1243 def testMicrocodeWithoutNode(self):
1244 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1245 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001246 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001247 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1248 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1249
1250 def testMicrocodeWithoutNode2(self):
1251 """Test that a missing u-boot-ucode node is detected"""
1252 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001253 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001254 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1255 "microcode region u-boot-ucode", str(e.exception))
1256
1257 def testMicrocodeWithoutPtrInElf(self):
1258 """Test that a U-Boot binary without the microcode symbol is detected"""
1259 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glass75db0862016-11-25 20:15:55 -07001260 try:
Simon Glassbccd91d2019-08-24 07:22:55 -06001261 TestFunctional._MakeInputFile('u-boot',
Simon Glassc1aa66e2022-01-29 14:14:04 -07001262 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass75db0862016-11-25 20:15:55 -07001263
1264 with self.assertRaises(ValueError) as e:
Simon Glass160a7662017-05-27 07:38:26 -06001265 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001266 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1267 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1268
1269 finally:
1270 # Put the original file back
Simon Glassf514d8f2019-08-24 07:22:54 -06001271 TestFunctional._MakeInputFile('u-boot',
Simon Glassc1aa66e2022-01-29 14:14:04 -07001272 tools.read_file(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glass75db0862016-11-25 20:15:55 -07001273
1274 def testMicrocodeNotInImage(self):
1275 """Test that microcode must be placed within the image"""
1276 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001277 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001278 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1279 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glass25ac0e62018-06-01 09:38:14 -06001280 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glass75db0862016-11-25 20:15:55 -07001281
1282 def testWithoutMicrocode(self):
1283 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glassbccd91d2019-08-24 07:22:55 -06001284 TestFunctional._MakeInputFile('u-boot',
Simon Glassc1aa66e2022-01-29 14:14:04 -07001285 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass741f2d62018-10-01 12:22:30 -06001286 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001287
1288 # Now check the device tree has no microcode
1289 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1290 second = data[len(U_BOOT_NODTB_DATA):]
1291
1292 fdt_len = self.GetFdtLen(second)
1293 self.assertEqual(dtb, second[:fdt_len])
1294
1295 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1296 third = data[used_len:]
Simon Glassc1aa66e2022-01-29 14:14:04 -07001297 self.assertEqual(tools.get_bytes(0, 0x200 - used_len), third)
Simon Glass75db0862016-11-25 20:15:55 -07001298
1299 def testUnknownPosSize(self):
1300 """Test that microcode must be placed within the image"""
1301 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001302 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glass3ab95982018-08-01 15:22:37 -06001303 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glass75db0862016-11-25 20:15:55 -07001304 "entry 'invalid-entry'", str(e.exception))
Simon Glassda229092016-11-25 20:15:56 -07001305
1306 def testPackFsp(self):
1307 """Test that an image with a FSP binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001308 data = self._DoReadFile('042_intel_fsp.dts')
Simon Glassda229092016-11-25 20:15:56 -07001309 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1310
1311 def testPackCmc(self):
Bin Meng59ea8c22017-08-15 22:41:54 -07001312 """Test that an image with a CMC binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001313 data = self._DoReadFile('043_intel_cmc.dts')
Simon Glassda229092016-11-25 20:15:56 -07001314 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Meng59ea8c22017-08-15 22:41:54 -07001315
1316 def testPackVbt(self):
1317 """Test that an image with a VBT binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001318 data = self._DoReadFile('046_intel_vbt.dts')
Bin Meng59ea8c22017-08-15 22:41:54 -07001319 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glass9fc60b42017-11-12 21:52:22 -07001320
Simon Glass56509842017-11-12 21:52:25 -07001321 def testSplBssPad(self):
1322 """Test that we can pad SPL's BSS with zeros"""
Simon Glass6b187df2017-11-12 21:52:27 -07001323 # ELF file with a '__bss_size' symbol
Simon Glass11ae93e2018-10-01 21:12:47 -06001324 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001325 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001326 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glasse6d85ff2019-05-14 15:53:47 -06001327 data)
Simon Glass56509842017-11-12 21:52:25 -07001328
Simon Glass86af5112018-10-01 21:12:42 -06001329 def testSplBssPadMissing(self):
1330 """Test that a missing symbol is detected"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001331 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glassb50e5612017-11-13 18:54:54 -07001332 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001333 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassb50e5612017-11-13 18:54:54 -07001334 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1335 str(e.exception))
1336
Simon Glass87722132017-11-12 21:52:26 -07001337 def testPackStart16Spl(self):
Simon Glass35b384c2018-09-14 04:57:10 -06001338 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001339 data = self._DoReadFile('048_x86_start16_spl.dts')
Simon Glass87722132017-11-12 21:52:26 -07001340 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1341
Simon Glass736bb0a2018-07-06 10:27:17 -06001342 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1343 """Helper function for microcode tests
Simon Glass6b187df2017-11-12 21:52:27 -07001344
1345 We expect to see the following in the image, in order:
1346 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1347 correct place
1348 u-boot.dtb with the microcode removed
1349 the microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001350
1351 Args:
1352 dts: Device tree file to use for test
1353 ucode_second: True if the microsecond entry is second instead of
1354 third
Simon Glass6b187df2017-11-12 21:52:27 -07001355 """
Simon Glass11ae93e2018-10-01 21:12:47 -06001356 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass736bb0a2018-07-06 10:27:17 -06001357 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1358 ucode_second=ucode_second)
Simon Glassc6c10e72019-05-17 22:00:46 -06001359 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1360 b'ter somewhere in here', first)
Simon Glass6b187df2017-11-12 21:52:27 -07001361
Simon Glass736bb0a2018-07-06 10:27:17 -06001362 def testPackUbootSplMicrocode(self):
1363 """Test that x86 microcode can be handled correctly in SPL"""
Simon Glass741f2d62018-10-01 12:22:30 -06001364 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass736bb0a2018-07-06 10:27:17 -06001365
1366 def testPackUbootSplMicrocodeReorder(self):
1367 """Test that order doesn't matter for microcode entries
1368
1369 This is the same as testPackUbootSplMicrocode but when we process the
1370 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1371 entry, so we reply on binman to try later.
1372 """
Simon Glass741f2d62018-10-01 12:22:30 -06001373 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass736bb0a2018-07-06 10:27:17 -06001374 ucode_second=True)
1375
Simon Glassca4f4ff2017-11-12 21:52:28 -07001376 def testPackMrc(self):
1377 """Test that an image with an MRC binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001378 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassca4f4ff2017-11-12 21:52:28 -07001379 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1380
Simon Glass47419ea2017-11-13 18:54:55 -07001381 def testSplDtb(self):
1382 """Test that an image with spl/u-boot-spl.dtb can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001383 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass47419ea2017-11-13 18:54:55 -07001384 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1385
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001386 def testSplNoDtb(self):
1387 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass0fe44dc2021-04-25 08:39:32 +12001388 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001389 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001390 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1391
Simon Glass3d433382021-03-21 18:24:30 +13001392 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
1393 use_expanded=False):
Simon Glassf5898822021-03-18 20:24:56 +13001394 """Check the image contains the expected symbol values
1395
1396 Args:
1397 dts: Device tree file to use for test
1398 base_data: Data before and after 'u-boot' section
1399 u_boot_offset: Offset of 'u-boot' section in image
Simon Glass3d433382021-03-21 18:24:30 +13001400 entry_args: Dict of entry args to supply to binman
1401 key: arg name
1402 value: value of that arg
1403 use_expanded: True to use expanded entries where available, e.g.
1404 'u-boot-expanded' instead of 'u-boot'
Simon Glassf5898822021-03-18 20:24:56 +13001405 """
Simon Glass1542c8b2019-08-24 07:22:56 -06001406 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass19790632017-11-13 18:55:01 -07001407 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1408 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Simon Glassf5898822021-03-18 20:24:56 +13001409 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
1410 addr)
Simon Glass19790632017-11-13 18:55:01 -07001411
Simon Glass11ae93e2018-10-01 21:12:47 -06001412 self._SetupSplElf('u_boot_binman_syms')
Simon Glass3d433382021-03-21 18:24:30 +13001413 data = self._DoReadFileDtb(dts, entry_args=entry_args,
1414 use_expanded=use_expanded)[0]
Simon Glassf5898822021-03-18 20:24:56 +13001415 # The image should contain the symbols from u_boot_binman_syms.c
1416 # Note that image_pos is adjusted by the base address of the image,
1417 # which is 0x10 in our test image
1418 sym_values = struct.pack('<LQLL', 0x00,
1419 u_boot_offset + len(U_BOOT_DATA),
1420 0x10 + u_boot_offset, 0x04)
1421 expected = (sym_values + base_data[20:] +
Simon Glassc1aa66e2022-01-29 14:14:04 -07001422 tools.get_bytes(0xff, 1) + U_BOOT_DATA + sym_values +
Simon Glassf5898822021-03-18 20:24:56 +13001423 base_data[20:])
Simon Glass19790632017-11-13 18:55:01 -07001424 self.assertEqual(expected, data)
1425
Simon Glassf5898822021-03-18 20:24:56 +13001426 def testSymbols(self):
1427 """Test binman can assign symbols embedded in U-Boot"""
1428 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x18)
1429
1430 def testSymbolsNoDtb(self):
1431 """Test binman can assign symbols embedded in U-Boot SPL"""
Simon Glasse9e0db82021-03-21 18:24:29 +13001432 self.checkSymbols('196_symbols_nodtb.dts',
Simon Glassf5898822021-03-18 20:24:56 +13001433 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1434 0x38)
1435
Simon Glassdd57c132018-06-01 09:38:11 -06001436 def testPackUnitAddress(self):
1437 """Test that we support multiple binaries with the same name"""
Simon Glass741f2d62018-10-01 12:22:30 -06001438 data = self._DoReadFile('054_unit_address.dts')
Simon Glassdd57c132018-06-01 09:38:11 -06001439 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1440
Simon Glass18546952018-06-01 09:38:16 -06001441 def testSections(self):
1442 """Basic test of sections"""
Simon Glass741f2d62018-10-01 12:22:30 -06001443 data = self._DoReadFile('055_sections.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001444 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1445 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
1446 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glass18546952018-06-01 09:38:16 -06001447 self.assertEqual(expected, data)
Simon Glass9fc60b42017-11-12 21:52:22 -07001448
Simon Glass3b0c38212018-06-01 09:38:20 -06001449 def testMap(self):
1450 """Tests outputting a map of the images"""
Simon Glass741f2d62018-10-01 12:22:30 -06001451 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001452 self.assertEqual('''ImagePos Offset Size Name
145300000000 00000000 00000028 main-section
145400000000 00000000 00000010 section@0
145500000000 00000000 00000004 u-boot
145600000010 00000010 00000010 section@1
145700000010 00000000 00000004 u-boot
145800000020 00000020 00000004 section@2
145900000020 00000000 00000004 u-boot
Simon Glass3b0c38212018-06-01 09:38:20 -06001460''', map_data)
1461
Simon Glassc8d48ef2018-06-01 09:38:21 -06001462 def testNamePrefix(self):
1463 """Tests that name prefixes are used"""
Simon Glass741f2d62018-10-01 12:22:30 -06001464 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001465 self.assertEqual('''ImagePos Offset Size Name
146600000000 00000000 00000028 main-section
146700000000 00000000 00000010 section@0
146800000000 00000000 00000004 ro-u-boot
146900000010 00000010 00000010 section@1
147000000010 00000000 00000004 rw-u-boot
Simon Glassc8d48ef2018-06-01 09:38:21 -06001471''', map_data)
1472
Simon Glass736bb0a2018-07-06 10:27:17 -06001473 def testUnknownContents(self):
1474 """Test that obtaining the contents works as expected"""
1475 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001476 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass8beb11e2019-07-08 14:25:47 -06001477 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glass16287932020-04-17 18:09:03 -06001478 "processing of contents: remaining ["
1479 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass736bb0a2018-07-06 10:27:17 -06001480
Simon Glass5c890232018-07-06 10:27:19 -06001481 def testBadChangeSize(self):
1482 """Test that trying to change the size of an entry fails"""
Simon Glassc52c9e72019-07-08 14:25:37 -06001483 try:
1484 state.SetAllowEntryExpansion(False)
1485 with self.assertRaises(ValueError) as e:
1486 self._DoReadFile('059_change_size.dts', True)
Simon Glass79d3c582019-07-20 12:23:57 -06001487 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glassc52c9e72019-07-08 14:25:37 -06001488 str(e.exception))
1489 finally:
1490 state.SetAllowEntryExpansion(True)
Simon Glass5c890232018-07-06 10:27:19 -06001491
Simon Glass16b8d6b2018-07-06 10:27:42 -06001492 def testUpdateFdt(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001493 """Test that we can update the device tree with offset/size info"""
Simon Glass741f2d62018-10-01 12:22:30 -06001494 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glass16b8d6b2018-07-06 10:27:42 -06001495 update_dtb=True)
Simon Glasscee02e62018-07-17 13:25:52 -06001496 dtb = fdt.Fdt(out_dtb_fname)
1497 dtb.Scan()
Simon Glass12bb1a92019-07-20 12:23:51 -06001498 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001499 self.assertEqual({
Simon Glassdbf6be92018-08-01 15:22:42 -06001500 'image-pos': 0,
Simon Glass8122f392018-07-17 13:25:28 -06001501 'offset': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001502 '_testing:offset': 32,
Simon Glass79d3c582019-07-20 12:23:57 -06001503 '_testing:size': 2,
Simon Glassdbf6be92018-08-01 15:22:42 -06001504 '_testing:image-pos': 32,
Simon Glass3ab95982018-08-01 15:22:37 -06001505 'section@0/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001506 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001507 'section@0/u-boot:image-pos': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001508 'section@0:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001509 'section@0:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001510 'section@0:image-pos': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001511
Simon Glass3ab95982018-08-01 15:22:37 -06001512 'section@1/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001513 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001514 'section@1/u-boot:image-pos': 16,
Simon Glass3ab95982018-08-01 15:22:37 -06001515 'section@1:offset': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001516 'section@1:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001517 'section@1:image-pos': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001518 'size': 40
1519 }, props)
1520
1521 def testUpdateFdtBad(self):
1522 """Test that we detect when ProcessFdt never completes"""
1523 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001524 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001525 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glass16287932020-04-17 18:09:03 -06001526 '[<binman.etype._testing.Entry__testing',
1527 str(e.exception))
Simon Glass5c890232018-07-06 10:27:19 -06001528
Simon Glass53af22a2018-07-17 13:25:32 -06001529 def testEntryArgs(self):
1530 """Test passing arguments to entries from the command line"""
1531 entry_args = {
1532 'test-str-arg': 'test1',
1533 'test-int-arg': '456',
1534 }
Simon Glass741f2d62018-10-01 12:22:30 -06001535 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001536 self.assertIn('image', control.images)
1537 entry = control.images['image'].GetEntries()['_testing']
1538 self.assertEqual('test0', entry.test_str_fdt)
1539 self.assertEqual('test1', entry.test_str_arg)
1540 self.assertEqual(123, entry.test_int_fdt)
1541 self.assertEqual(456, entry.test_int_arg)
1542
1543 def testEntryArgsMissing(self):
1544 """Test missing arguments and properties"""
1545 entry_args = {
1546 'test-int-arg': '456',
1547 }
Simon Glass741f2d62018-10-01 12:22:30 -06001548 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001549 entry = control.images['image'].GetEntries()['_testing']
1550 self.assertEqual('test0', entry.test_str_fdt)
1551 self.assertEqual(None, entry.test_str_arg)
1552 self.assertEqual(None, entry.test_int_fdt)
1553 self.assertEqual(456, entry.test_int_arg)
1554
1555 def testEntryArgsRequired(self):
1556 """Test missing arguments and properties"""
1557 entry_args = {
1558 'test-int-arg': '456',
1559 }
1560 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001561 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass3decfa32020-09-01 05:13:54 -06001562 self.assertIn("Node '/binman/_testing': "
1563 'Missing required properties/entry args: test-str-arg, '
1564 'test-int-fdt, test-int-arg',
Simon Glass53af22a2018-07-17 13:25:32 -06001565 str(e.exception))
1566
1567 def testEntryArgsInvalidFormat(self):
1568 """Test that an invalid entry-argument format is detected"""
Simon Glass53cd5d92019-07-08 14:25:29 -06001569 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1570 '-ano-value']
Simon Glass53af22a2018-07-17 13:25:32 -06001571 with self.assertRaises(ValueError) as e:
1572 self._DoBinman(*args)
1573 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1574
1575 def testEntryArgsInvalidInteger(self):
1576 """Test that an invalid entry-argument integer is detected"""
1577 entry_args = {
1578 'test-int-arg': 'abc',
1579 }
1580 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001581 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001582 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1583 "'test-int-arg' (value 'abc') to integer",
1584 str(e.exception))
1585
1586 def testEntryArgsInvalidDatatype(self):
1587 """Test that an invalid entry-argument datatype is detected
1588
1589 This test could be written in entry_test.py except that it needs
1590 access to control.entry_args, which seems more than that module should
1591 be able to see.
1592 """
1593 entry_args = {
1594 'test-bad-datatype-arg': '12',
1595 }
1596 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001597 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass53af22a2018-07-17 13:25:32 -06001598 entry_args=entry_args)
1599 self.assertIn('GetArg() internal error: Unknown data type ',
1600 str(e.exception))
1601
Simon Glassbb748372018-07-17 13:25:33 -06001602 def testText(self):
1603 """Test for a text entry type"""
1604 entry_args = {
1605 'test-id': TEXT_DATA,
1606 'test-id2': TEXT_DATA2,
1607 'test-id3': TEXT_DATA3,
1608 }
Simon Glass741f2d62018-10-01 12:22:30 -06001609 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glassbb748372018-07-17 13:25:33 -06001610 entry_args=entry_args)
Simon Glassc1aa66e2022-01-29 14:14:04 -07001611 expected = (tools.to_bytes(TEXT_DATA) +
1612 tools.get_bytes(0, 8 - len(TEXT_DATA)) +
1613 tools.to_bytes(TEXT_DATA2) + tools.to_bytes(TEXT_DATA3) +
Simon Glassaa88b502019-07-08 13:18:40 -06001614 b'some text' + b'more text')
Simon Glassbb748372018-07-17 13:25:33 -06001615 self.assertEqual(expected, data)
1616
Simon Glassfd8d1f72018-07-17 13:25:36 -06001617 def testEntryDocs(self):
1618 """Test for creation of entry documentation"""
1619 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass87d43322020-08-05 13:27:46 -06001620 control.WriteEntryDocs(control.GetEntryModules())
Simon Glassfd8d1f72018-07-17 13:25:36 -06001621 self.assertTrue(len(stdout.getvalue()) > 0)
1622
1623 def testEntryDocsMissing(self):
1624 """Test handling of missing entry documentation"""
1625 with self.assertRaises(ValueError) as e:
1626 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass87d43322020-08-05 13:27:46 -06001627 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glassfd8d1f72018-07-17 13:25:36 -06001628 self.assertIn('Documentation is missing for modules: u_boot',
1629 str(e.exception))
1630
Simon Glass11e36cc2018-07-17 13:25:38 -06001631 def testFmap(self):
1632 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001633 data = self._DoReadFile('067_fmap.dts')
Simon Glass11e36cc2018-07-17 13:25:38 -06001634 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc1aa66e2022-01-29 14:14:04 -07001635 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1636 U_BOOT_DATA + tools.get_bytes(ord('a'), 12))
Simon Glass11e36cc2018-07-17 13:25:38 -06001637 self.assertEqual(expected, data[:32])
Simon Glassc6c10e72019-05-17 22:00:46 -06001638 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass11e36cc2018-07-17 13:25:38 -06001639 self.assertEqual(1, fhdr.ver_major)
1640 self.assertEqual(0, fhdr.ver_minor)
1641 self.assertEqual(0, fhdr.base)
Simon Glass17365752021-04-03 11:05:10 +13001642 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 5
Simon Glassc7722e82021-04-03 11:05:09 +13001643 self.assertEqual(16 + 16 + expect_size, fhdr.image_size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001644 self.assertEqual(b'FMAP', fhdr.name)
Simon Glass17365752021-04-03 11:05:10 +13001645 self.assertEqual(5, fhdr.nareas)
Simon Glassc7722e82021-04-03 11:05:09 +13001646 fiter = iter(fentries)
Simon Glass11e36cc2018-07-17 13:25:38 -06001647
Simon Glassc7722e82021-04-03 11:05:09 +13001648 fentry = next(fiter)
Simon Glass17365752021-04-03 11:05:10 +13001649 self.assertEqual(b'SECTION0', fentry.name)
1650 self.assertEqual(0, fentry.offset)
1651 self.assertEqual(16, fentry.size)
1652 self.assertEqual(0, fentry.flags)
1653
1654 fentry = next(fiter)
Simon Glassc7722e82021-04-03 11:05:09 +13001655 self.assertEqual(b'RO_U_BOOT', fentry.name)
1656 self.assertEqual(0, fentry.offset)
1657 self.assertEqual(4, fentry.size)
1658 self.assertEqual(0, fentry.flags)
Simon Glass11e36cc2018-07-17 13:25:38 -06001659
Simon Glassc7722e82021-04-03 11:05:09 +13001660 fentry = next(fiter)
Simon Glass17365752021-04-03 11:05:10 +13001661 self.assertEqual(b'SECTION1', fentry.name)
1662 self.assertEqual(16, fentry.offset)
1663 self.assertEqual(16, fentry.size)
1664 self.assertEqual(0, fentry.flags)
1665
1666 fentry = next(fiter)
Simon Glassc7722e82021-04-03 11:05:09 +13001667 self.assertEqual(b'RW_U_BOOT', fentry.name)
1668 self.assertEqual(16, fentry.offset)
1669 self.assertEqual(4, fentry.size)
1670 self.assertEqual(0, fentry.flags)
Simon Glass11e36cc2018-07-17 13:25:38 -06001671
Simon Glassc7722e82021-04-03 11:05:09 +13001672 fentry = next(fiter)
1673 self.assertEqual(b'FMAP', fentry.name)
1674 self.assertEqual(32, fentry.offset)
1675 self.assertEqual(expect_size, fentry.size)
1676 self.assertEqual(0, fentry.flags)
Simon Glass11e36cc2018-07-17 13:25:38 -06001677
Simon Glassec127af2018-07-17 13:25:39 -06001678 def testBlobNamedByArg(self):
1679 """Test we can add a blob with the filename coming from an entry arg"""
1680 entry_args = {
1681 'cros-ec-rw-path': 'ecrw.bin',
1682 }
Simon Glass3decfa32020-09-01 05:13:54 -06001683 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassec127af2018-07-17 13:25:39 -06001684
Simon Glass3af8e492018-07-17 13:25:40 -06001685 def testFill(self):
1686 """Test for an fill entry type"""
Simon Glass741f2d62018-10-01 12:22:30 -06001687 data = self._DoReadFile('069_fill.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001688 expected = tools.get_bytes(0xff, 8) + tools.get_bytes(0, 8)
Simon Glass3af8e492018-07-17 13:25:40 -06001689 self.assertEqual(expected, data)
1690
1691 def testFillNoSize(self):
1692 """Test for an fill entry type with no size"""
1693 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001694 self._DoReadFile('070_fill_no_size.dts')
Simon Glass3af8e492018-07-17 13:25:40 -06001695 self.assertIn("'fill' entry must have a size property",
1696 str(e.exception))
1697
Simon Glass0ef87aa2018-07-17 13:25:44 -06001698 def _HandleGbbCommand(self, pipe_list):
1699 """Fake calls to the futility utility"""
1700 if pipe_list[0][0] == 'futility':
1701 fname = pipe_list[0][-1]
1702 # Append our GBB data to the file, which will happen every time the
1703 # futility command is called.
Simon Glass1d0ebf72019-05-14 15:53:42 -06001704 with open(fname, 'ab') as fd:
Simon Glass0ef87aa2018-07-17 13:25:44 -06001705 fd.write(GBB_DATA)
1706 return command.CommandResult()
1707
1708 def testGbb(self):
1709 """Test for the Chromium OS Google Binary Block"""
1710 command.test_result = self._HandleGbbCommand
1711 entry_args = {
1712 'keydir': 'devkeys',
1713 'bmpblk': 'bmpblk.bin',
1714 }
Simon Glass741f2d62018-10-01 12:22:30 -06001715 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glass0ef87aa2018-07-17 13:25:44 -06001716
1717 # Since futility
Simon Glassc1aa66e2022-01-29 14:14:04 -07001718 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
1719 tools.get_bytes(0, 0x2180 - 16))
Simon Glass0ef87aa2018-07-17 13:25:44 -06001720 self.assertEqual(expected, data)
1721
1722 def testGbbTooSmall(self):
1723 """Test for the Chromium OS Google Binary Block being large enough"""
1724 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001725 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001726 self.assertIn("Node '/binman/gbb': GBB is too small",
1727 str(e.exception))
1728
1729 def testGbbNoSize(self):
1730 """Test for the Chromium OS Google Binary Block having a size"""
1731 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001732 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001733 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1734 str(e.exception))
1735
Simon Glass4f9ee832022-01-09 20:14:09 -07001736 def testGbbMissing(self):
1737 """Test that binman still produces an image if futility is missing"""
1738 entry_args = {
1739 'keydir': 'devkeys',
1740 }
1741 with test_util.capture_sys_output() as (_, stderr):
1742 self._DoTestFile('071_gbb.dts', force_missing_bintools='futility',
1743 entry_args=entry_args)
1744 err = stderr.getvalue()
1745 self.assertRegex(err,
1746 "Image 'main-section'.*missing bintools.*: futility")
1747
Simon Glass24d0d3c2018-07-17 13:25:47 -06001748 def _HandleVblockCommand(self, pipe_list):
Simon Glass5af9ebc2021-01-06 21:35:17 -07001749 """Fake calls to the futility utility
1750
1751 The expected pipe is:
1752
1753 [('futility', 'vbutil_firmware', '--vblock',
1754 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1755 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1756 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1757 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1758
1759 This writes to the output file (here, 'vblock.vblock'). If
1760 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1761 of the input data (here, 'input.vblock').
1762 """
Simon Glass24d0d3c2018-07-17 13:25:47 -06001763 if pipe_list[0][0] == 'futility':
1764 fname = pipe_list[0][3]
Simon Glassa326b492018-09-14 04:57:11 -06001765 with open(fname, 'wb') as fd:
Simon Glass5af9ebc2021-01-06 21:35:17 -07001766 if self._hash_data:
1767 infile = pipe_list[0][11]
1768 m = hashlib.sha256()
Simon Glassc1aa66e2022-01-29 14:14:04 -07001769 data = tools.read_file(infile)
Simon Glass5af9ebc2021-01-06 21:35:17 -07001770 m.update(data)
1771 fd.write(m.digest())
1772 else:
1773 fd.write(VBLOCK_DATA)
1774
Simon Glass24d0d3c2018-07-17 13:25:47 -06001775 return command.CommandResult()
1776
1777 def testVblock(self):
1778 """Test for the Chromium OS Verified Boot Block"""
Simon Glass5af9ebc2021-01-06 21:35:17 -07001779 self._hash_data = False
Simon Glass24d0d3c2018-07-17 13:25:47 -06001780 command.test_result = self._HandleVblockCommand
1781 entry_args = {
1782 'keydir': 'devkeys',
1783 }
Simon Glass741f2d62018-10-01 12:22:30 -06001784 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass24d0d3c2018-07-17 13:25:47 -06001785 entry_args=entry_args)
1786 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1787 self.assertEqual(expected, data)
1788
1789 def testVblockNoContent(self):
1790 """Test we detect a vblock which has no content to sign"""
1791 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001792 self._DoReadFile('075_vblock_no_content.dts')
Simon Glass189f2912021-03-21 18:24:31 +13001793 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
Simon Glass24d0d3c2018-07-17 13:25:47 -06001794 'property', str(e.exception))
1795
1796 def testVblockBadPhandle(self):
1797 """Test that we detect a vblock with an invalid phandle in contents"""
1798 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001799 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001800 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1801 '1000', str(e.exception))
1802
1803 def testVblockBadEntry(self):
1804 """Test that we detect an entry that points to a non-entry"""
1805 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001806 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001807 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1808 "'other'", str(e.exception))
1809
Simon Glass5af9ebc2021-01-06 21:35:17 -07001810 def testVblockContent(self):
1811 """Test that the vblock signs the right data"""
1812 self._hash_data = True
1813 command.test_result = self._HandleVblockCommand
1814 entry_args = {
1815 'keydir': 'devkeys',
1816 }
1817 data = self._DoReadFileDtb(
1818 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1819 entry_args=entry_args)[0]
1820 hashlen = 32 # SHA256 hash is 32 bytes
1821 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1822 hashval = data[-hashlen:]
1823 dtb = data[len(U_BOOT_DATA):-hashlen]
1824
1825 expected_data = U_BOOT_DATA + dtb
1826
1827 # The hashval should be a hash of the dtb
1828 m = hashlib.sha256()
1829 m.update(expected_data)
1830 expected_hashval = m.digest()
1831 self.assertEqual(expected_hashval, hashval)
1832
Simon Glass4f9ee832022-01-09 20:14:09 -07001833 def testVblockMissing(self):
1834 """Test that binman still produces an image if futility is missing"""
1835 entry_args = {
1836 'keydir': 'devkeys',
1837 }
1838 with test_util.capture_sys_output() as (_, stderr):
1839 self._DoTestFile('074_vblock.dts',
1840 force_missing_bintools='futility',
1841 entry_args=entry_args)
1842 err = stderr.getvalue()
1843 self.assertRegex(err,
1844 "Image 'main-section'.*missing bintools.*: futility")
1845
Simon Glassb8ef5b62018-07-17 13:25:48 -06001846 def testTpl(self):
Simon Glass2090f1e2019-08-24 07:23:00 -06001847 """Test that an image with TPL and its device tree can be created"""
Simon Glassb8ef5b62018-07-17 13:25:48 -06001848 # ELF file with a '__bss_size' symbol
Simon Glass2090f1e2019-08-24 07:23:00 -06001849 self._SetupTplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001850 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glassb8ef5b62018-07-17 13:25:48 -06001851 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1852
Simon Glass15a587c2018-07-17 13:25:51 -06001853 def testUsesPos(self):
1854 """Test that the 'pos' property cannot be used anymore"""
1855 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001856 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass15a587c2018-07-17 13:25:51 -06001857 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1858 "'pos'", str(e.exception))
1859
Simon Glassd178eab2018-09-14 04:57:08 -06001860 def testFillZero(self):
1861 """Test for an fill entry type with a size of 0"""
Simon Glass741f2d62018-10-01 12:22:30 -06001862 data = self._DoReadFile('080_fill_empty.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001863 self.assertEqual(tools.get_bytes(0, 16), data)
Simon Glassd178eab2018-09-14 04:57:08 -06001864
Simon Glass0b489362018-09-14 04:57:09 -06001865 def testTextMissing(self):
1866 """Test for a text entry type where there is no text"""
1867 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001868 self._DoReadFileDtb('066_text.dts',)
Simon Glass0b489362018-09-14 04:57:09 -06001869 self.assertIn("Node '/binman/text': No value provided for text label "
1870 "'test-id'", str(e.exception))
1871
Simon Glass35b384c2018-09-14 04:57:10 -06001872 def testPackStart16Tpl(self):
1873 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001874 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glass35b384c2018-09-14 04:57:10 -06001875 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1876
Simon Glass0bfa7b02018-09-14 04:57:12 -06001877 def testSelectImage(self):
1878 """Test that we can select which images to build"""
Simon Glasseb833d82019-04-25 21:58:34 -06001879 expected = 'Skipping images: image1'
Simon Glass0bfa7b02018-09-14 04:57:12 -06001880
Simon Glasseb833d82019-04-25 21:58:34 -06001881 # We should only get the expected message in verbose mode
Simon Glassee0c9a72019-07-08 13:18:48 -06001882 for verbosity in (0, 2):
Simon Glasseb833d82019-04-25 21:58:34 -06001883 with test_util.capture_sys_output() as (stdout, stderr):
1884 retcode = self._DoTestFile('006_dual_image.dts',
1885 verbosity=verbosity,
1886 images=['image2'])
1887 self.assertEqual(0, retcode)
1888 if verbosity:
1889 self.assertIn(expected, stdout.getvalue())
1890 else:
1891 self.assertNotIn(expected, stdout.getvalue())
1892
Simon Glassc1aa66e2022-01-29 14:14:04 -07001893 self.assertFalse(os.path.exists(tools.get_output_filename('image1.bin')))
1894 self.assertTrue(os.path.exists(tools.get_output_filename('image2.bin')))
Simon Glassf86a7362019-07-20 12:24:10 -06001895 self._CleanupOutputDir()
Simon Glass0bfa7b02018-09-14 04:57:12 -06001896
Simon Glass6ed45ba2018-09-14 04:57:24 -06001897 def testUpdateFdtAll(self):
1898 """Test that all device trees are updated with offset/size info"""
Simon Glass3c081312019-07-08 14:25:26 -06001899 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glass6ed45ba2018-09-14 04:57:24 -06001900
1901 base_expected = {
1902 'section:image-pos': 0,
1903 'u-boot-tpl-dtb:size': 513,
1904 'u-boot-spl-dtb:size': 513,
1905 'u-boot-spl-dtb:offset': 493,
1906 'image-pos': 0,
1907 'section/u-boot-dtb:image-pos': 0,
1908 'u-boot-spl-dtb:image-pos': 493,
1909 'section/u-boot-dtb:size': 493,
1910 'u-boot-tpl-dtb:image-pos': 1006,
1911 'section/u-boot-dtb:offset': 0,
1912 'section:size': 493,
1913 'offset': 0,
1914 'section:offset': 0,
1915 'u-boot-tpl-dtb:offset': 1006,
1916 'size': 1519
1917 }
1918
1919 # We expect three device-tree files in the output, one after the other.
1920 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1921 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1922 # main U-Boot tree. All three should have the same postions and offset.
1923 start = 0
1924 for item in ['', 'spl', 'tpl']:
1925 dtb = fdt.Fdt.FromData(data[start:])
1926 dtb.Scan()
Simon Glass12bb1a92019-07-20 12:23:51 -06001927 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
1928 ['spl', 'tpl'])
Simon Glass6ed45ba2018-09-14 04:57:24 -06001929 expected = dict(base_expected)
1930 if item:
1931 expected[item] = 0
1932 self.assertEqual(expected, props)
1933 start += dtb._fdt_obj.totalsize()
1934
1935 def testUpdateFdtOutput(self):
1936 """Test that output DTB files are updated"""
1937 try:
Simon Glass741f2d62018-10-01 12:22:30 -06001938 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glass6ed45ba2018-09-14 04:57:24 -06001939 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1940
1941 # Unfortunately, compiling a source file always results in a file
1942 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass741f2d62018-10-01 12:22:30 -06001943 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glass6ed45ba2018-09-14 04:57:24 -06001944 # binman as a file called u-boot.dtb. To fix this, copy the file
1945 # over to the expected place.
Simon Glass6ed45ba2018-09-14 04:57:24 -06001946 start = 0
1947 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1948 'tpl/u-boot-tpl.dtb.out']:
1949 dtb = fdt.Fdt.FromData(data[start:])
1950 size = dtb._fdt_obj.totalsize()
Simon Glassc1aa66e2022-01-29 14:14:04 -07001951 pathname = tools.get_output_filename(os.path.split(fname)[1])
1952 outdata = tools.read_file(pathname)
Simon Glass6ed45ba2018-09-14 04:57:24 -06001953 name = os.path.split(fname)[0]
1954
1955 if name:
1956 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1957 else:
1958 orig_indata = dtb_data
1959 self.assertNotEqual(outdata, orig_indata,
1960 "Expected output file '%s' be updated" % pathname)
1961 self.assertEqual(outdata, data[start:start + size],
1962 "Expected output file '%s' to match output image" %
1963 pathname)
1964 start += size
1965 finally:
1966 self._ResetDtbs()
1967
Simon Glass83d73c22018-09-14 04:57:26 -06001968 def _decompress(self, data):
Simon Glass0d1e95a2022-01-09 20:14:04 -07001969 return comp_util.decompress(data, 'lz4')
Simon Glass83d73c22018-09-14 04:57:26 -06001970
1971 def testCompress(self):
1972 """Test compression of blobs"""
Simon Glassac62fba2019-07-08 13:18:53 -06001973 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06001974 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass83d73c22018-09-14 04:57:26 -06001975 use_real_dtb=True, update_dtb=True)
1976 dtb = fdt.Fdt(out_dtb_fname)
1977 dtb.Scan()
1978 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1979 orig = self._decompress(data)
1980 self.assertEquals(COMPRESS_DATA, orig)
Simon Glass97c3e9a2020-10-26 17:40:15 -06001981
1982 # Do a sanity check on various fields
1983 image = control.images['image']
1984 entries = image.GetEntries()
1985 self.assertEqual(1, len(entries))
1986
1987 entry = entries['blob']
1988 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
1989 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
1990 orig = self._decompress(entry.data)
1991 self.assertEqual(orig, entry.uncomp_data)
1992
Simon Glass63e7ba62020-10-26 17:40:16 -06001993 self.assertEqual(image.data, entry.data)
1994
Simon Glass83d73c22018-09-14 04:57:26 -06001995 expected = {
1996 'blob:uncomp-size': len(COMPRESS_DATA),
1997 'blob:size': len(data),
1998 'size': len(data),
1999 }
2000 self.assertEqual(expected, props)
2001
Simon Glass0a98b282018-09-14 04:57:28 -06002002 def testFiles(self):
2003 """Test bringing in multiple files"""
Simon Glass741f2d62018-10-01 12:22:30 -06002004 data = self._DoReadFile('084_files.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06002005 self.assertEqual(FILES_DATA, data)
2006
2007 def testFilesCompress(self):
2008 """Test bringing in multiple files and compressing them"""
Simon Glassac62fba2019-07-08 13:18:53 -06002009 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06002010 data = self._DoReadFile('085_files_compress.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06002011
2012 image = control.images['image']
2013 entries = image.GetEntries()
2014 files = entries['files']
Simon Glass8beb11e2019-07-08 14:25:47 -06002015 entries = files._entries
Simon Glass0a98b282018-09-14 04:57:28 -06002016
Simon Glassc6c10e72019-05-17 22:00:46 -06002017 orig = b''
Simon Glass0a98b282018-09-14 04:57:28 -06002018 for i in range(1, 3):
2019 key = '%d.dat' % i
2020 start = entries[key].image_pos
2021 len = entries[key].size
2022 chunk = data[start:start + len]
2023 orig += self._decompress(chunk)
2024
2025 self.assertEqual(FILES_DATA, orig)
2026
2027 def testFilesMissing(self):
2028 """Test missing files"""
2029 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002030 data = self._DoReadFile('086_files_none.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06002031 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
2032 'no files', str(e.exception))
2033
2034 def testFilesNoPattern(self):
2035 """Test missing files"""
2036 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002037 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06002038 self.assertIn("Node '/binman/files': Missing 'pattern' property",
2039 str(e.exception))
2040
Simon Glass80a66ae2022-03-05 20:18:59 -07002041 def testExtendSize(self):
2042 """Test an extending entry"""
2043 data, _, map_data, _ = self._DoReadFileDtb('088_extend_size.dts',
Simon Glassba64a0b2018-09-14 04:57:29 -06002044 map=True)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002045 expect = (tools.get_bytes(ord('a'), 8) + U_BOOT_DATA +
2046 MRC_DATA + tools.get_bytes(ord('b'), 1) + U_BOOT_DATA +
2047 tools.get_bytes(ord('c'), 8) + U_BOOT_DATA +
2048 tools.get_bytes(ord('d'), 8))
Simon Glassba64a0b2018-09-14 04:57:29 -06002049 self.assertEqual(expect, data)
2050 self.assertEqual('''ImagePos Offset Size Name
205100000000 00000000 00000028 main-section
205200000000 00000000 00000008 fill
205300000008 00000008 00000004 u-boot
20540000000c 0000000c 00000004 section
20550000000c 00000000 00000003 intel-mrc
205600000010 00000010 00000004 u-boot2
205700000014 00000014 0000000c section2
205800000014 00000000 00000008 fill
20590000001c 00000008 00000004 u-boot
206000000020 00000020 00000008 fill2
2061''', map_data)
2062
Simon Glass80a66ae2022-03-05 20:18:59 -07002063 def testExtendSizeBad(self):
2064 """Test an extending entry which fails to provide contents"""
Simon Glass163ed6c2018-09-14 04:57:36 -06002065 with test_util.capture_sys_output() as (stdout, stderr):
2066 with self.assertRaises(ValueError) as e:
Simon Glass80a66ae2022-03-05 20:18:59 -07002067 self._DoReadFileDtb('089_extend_size_bad.dts', map=True)
Simon Glassba64a0b2018-09-14 04:57:29 -06002068 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
2069 'expanding entry', str(e.exception))
2070
Simon Glasse0e5df92018-09-14 04:57:31 -06002071 def testHash(self):
2072 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06002073 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06002074 use_real_dtb=True, update_dtb=True)
2075 dtb = fdt.Fdt(out_dtb_fname)
2076 dtb.Scan()
2077 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
2078 m = hashlib.sha256()
2079 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06002080 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06002081
2082 def testHashNoAlgo(self):
2083 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002084 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06002085 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2086 'hash node', str(e.exception))
2087
2088 def testHashBadAlgo(self):
2089 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002090 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glass8db1f992022-02-08 10:59:44 -07002091 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm 'invalid'",
Simon Glasse0e5df92018-09-14 04:57:31 -06002092 str(e.exception))
2093
2094 def testHashSection(self):
2095 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06002096 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06002097 use_real_dtb=True, update_dtb=True)
2098 dtb = fdt.Fdt(out_dtb_fname)
2099 dtb.Scan()
2100 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2101 m = hashlib.sha256()
2102 m.update(U_BOOT_DATA)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002103 m.update(tools.get_bytes(ord('a'), 16))
Simon Glassc6c10e72019-05-17 22:00:46 -06002104 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06002105
Simon Glassf0253632018-09-14 04:57:32 -06002106 def testPackUBootTplMicrocode(self):
2107 """Test that x86 microcode can be handled correctly in TPL
2108
2109 We expect to see the following in the image, in order:
2110 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2111 place
2112 u-boot-tpl.dtb with the microcode removed
2113 the microcode
2114 """
Simon Glass2090f1e2019-08-24 07:23:00 -06002115 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass741f2d62018-10-01 12:22:30 -06002116 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glassf0253632018-09-14 04:57:32 -06002117 U_BOOT_TPL_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06002118 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2119 b'ter somewhere in here', first)
Simon Glassf0253632018-09-14 04:57:32 -06002120
Simon Glassf8f8df62018-09-14 04:57:34 -06002121 def testFmapX86(self):
2122 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06002123 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassf8f8df62018-09-14 04:57:34 -06002124 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc1aa66e2022-01-29 14:14:04 -07002125 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('a'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06002126 self.assertEqual(expected, data[:32])
2127 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2128
2129 self.assertEqual(0x100, fhdr.image_size)
2130
2131 self.assertEqual(0, fentries[0].offset)
2132 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06002133 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06002134
2135 self.assertEqual(4, fentries[1].offset)
2136 self.assertEqual(3, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06002137 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06002138
2139 self.assertEqual(32, fentries[2].offset)
2140 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2141 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06002142 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06002143
2144 def testFmapX86Section(self):
2145 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06002146 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002147 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('b'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06002148 self.assertEqual(expected, data[:32])
2149 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2150
Simon Glass17365752021-04-03 11:05:10 +13002151 self.assertEqual(0x180, fhdr.image_size)
2152 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
Simon Glassc7722e82021-04-03 11:05:09 +13002153 fiter = iter(fentries)
Simon Glassf8f8df62018-09-14 04:57:34 -06002154
Simon Glassc7722e82021-04-03 11:05:09 +13002155 fentry = next(fiter)
2156 self.assertEqual(b'U_BOOT', fentry.name)
2157 self.assertEqual(0, fentry.offset)
2158 self.assertEqual(4, fentry.size)
Simon Glassf8f8df62018-09-14 04:57:34 -06002159
Simon Glassc7722e82021-04-03 11:05:09 +13002160 fentry = next(fiter)
Simon Glass17365752021-04-03 11:05:10 +13002161 self.assertEqual(b'SECTION', fentry.name)
2162 self.assertEqual(4, fentry.offset)
2163 self.assertEqual(0x20 + expect_size, fentry.size)
2164
2165 fentry = next(fiter)
Simon Glassc7722e82021-04-03 11:05:09 +13002166 self.assertEqual(b'INTEL_MRC', fentry.name)
2167 self.assertEqual(4, fentry.offset)
2168 self.assertEqual(3, fentry.size)
Simon Glassf8f8df62018-09-14 04:57:34 -06002169
Simon Glassc7722e82021-04-03 11:05:09 +13002170 fentry = next(fiter)
2171 self.assertEqual(b'FMAP', fentry.name)
2172 self.assertEqual(36, fentry.offset)
2173 self.assertEqual(expect_size, fentry.size)
Simon Glassf8f8df62018-09-14 04:57:34 -06002174
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002175 def testElf(self):
2176 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06002177 self._SetupSplElf()
Simon Glass2090f1e2019-08-24 07:23:00 -06002178 self._SetupTplElf()
Simon Glass53e22bf2019-08-24 07:22:53 -06002179 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002180 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06002181 data = self._DoReadFile('096_elf.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002182
Simon Glass093d1682019-07-08 13:18:25 -06002183 def testElfStrip(self):
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002184 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06002185 self._SetupSplElf()
Simon Glass53e22bf2019-08-24 07:22:53 -06002186 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002187 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06002188 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002189
Simon Glass163ed6c2018-09-14 04:57:36 -06002190 def testPackOverlapMap(self):
2191 """Test that overlapping regions are detected"""
2192 with test_util.capture_sys_output() as (stdout, stderr):
2193 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002194 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002195 map_fname = tools.get_output_filename('image.map')
Simon Glass163ed6c2018-09-14 04:57:36 -06002196 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2197 stdout.getvalue())
2198
2199 # We should not get an inmage, but there should be a map file
Simon Glassc1aa66e2022-01-29 14:14:04 -07002200 self.assertFalse(os.path.exists(tools.get_output_filename('image.bin')))
Simon Glass163ed6c2018-09-14 04:57:36 -06002201 self.assertTrue(os.path.exists(map_fname))
Simon Glassc1aa66e2022-01-29 14:14:04 -07002202 map_data = tools.read_file(map_fname, binary=False)
Simon Glass163ed6c2018-09-14 04:57:36 -06002203 self.assertEqual('''ImagePos Offset Size Name
Simon Glass0ff83da2020-10-26 17:40:24 -06002204<none> 00000000 00000008 main-section
Simon Glass163ed6c2018-09-14 04:57:36 -06002205<none> 00000000 00000004 u-boot
2206<none> 00000003 00000004 u-boot-align
2207''', map_data)
2208
Simon Glass093d1682019-07-08 13:18:25 -06002209 def testPackRefCode(self):
Simon Glass3ae192c2018-10-01 12:22:31 -06002210 """Test that an image with an Intel Reference code binary works"""
2211 data = self._DoReadFile('100_intel_refcode.dts')
2212 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2213
Simon Glass9481c802019-04-25 21:58:39 -06002214 def testSectionOffset(self):
2215 """Tests use of a section with an offset"""
2216 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2217 map=True)
2218 self.assertEqual('''ImagePos Offset Size Name
221900000000 00000000 00000038 main-section
222000000004 00000004 00000010 section@0
222100000004 00000000 00000004 u-boot
222200000018 00000018 00000010 section@1
222300000018 00000000 00000004 u-boot
22240000002c 0000002c 00000004 section@2
22250000002c 00000000 00000004 u-boot
2226''', map_data)
2227 self.assertEqual(data,
Simon Glassc1aa66e2022-01-29 14:14:04 -07002228 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2229 tools.get_bytes(0x21, 12) +
2230 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2231 tools.get_bytes(0x61, 12) +
2232 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2233 tools.get_bytes(0x26, 8))
Simon Glass9481c802019-04-25 21:58:39 -06002234
Simon Glassac62fba2019-07-08 13:18:53 -06002235 def testCbfsRaw(self):
2236 """Test base handling of a Coreboot Filesystem (CBFS)
2237
2238 The exact contents of the CBFS is verified by similar tests in
2239 cbfs_util_test.py. The tests here merely check that the files added to
2240 the CBFS can be found in the final image.
2241 """
2242 data = self._DoReadFile('102_cbfs_raw.dts')
2243 size = 0xb0
2244
2245 cbfs = cbfs_util.CbfsReader(data)
2246 self.assertEqual(size, cbfs.rom_size)
2247
2248 self.assertIn('u-boot-dtb', cbfs.files)
2249 cfile = cbfs.files['u-boot-dtb']
2250 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2251
2252 def testCbfsArch(self):
2253 """Test on non-x86 architecture"""
2254 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2255 size = 0x100
2256
2257 cbfs = cbfs_util.CbfsReader(data)
2258 self.assertEqual(size, cbfs.rom_size)
2259
2260 self.assertIn('u-boot-dtb', cbfs.files)
2261 cfile = cbfs.files['u-boot-dtb']
2262 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2263
2264 def testCbfsStage(self):
2265 """Tests handling of a Coreboot Filesystem (CBFS)"""
2266 if not elf.ELF_TOOLS:
2267 self.skipTest('Python elftools not available')
2268 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2269 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2270 size = 0xb0
2271
2272 data = self._DoReadFile('104_cbfs_stage.dts')
2273 cbfs = cbfs_util.CbfsReader(data)
2274 self.assertEqual(size, cbfs.rom_size)
2275
2276 self.assertIn('u-boot', cbfs.files)
2277 cfile = cbfs.files['u-boot']
2278 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2279
2280 def testCbfsRawCompress(self):
2281 """Test handling of compressing raw files"""
2282 self._CheckLz4()
2283 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2284 size = 0x140
2285
2286 cbfs = cbfs_util.CbfsReader(data)
2287 self.assertIn('u-boot', cbfs.files)
2288 cfile = cbfs.files['u-boot']
2289 self.assertEqual(COMPRESS_DATA, cfile.data)
2290
2291 def testCbfsBadArch(self):
2292 """Test handling of a bad architecture"""
2293 with self.assertRaises(ValueError) as e:
2294 self._DoReadFile('106_cbfs_bad_arch.dts')
2295 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2296
2297 def testCbfsNoSize(self):
2298 """Test handling of a missing size property"""
2299 with self.assertRaises(ValueError) as e:
2300 self._DoReadFile('107_cbfs_no_size.dts')
2301 self.assertIn('entry must have a size property', str(e.exception))
2302
Simon Glasse2f04742021-11-23 11:03:54 -07002303 def testCbfsNoContents(self):
Simon Glassac62fba2019-07-08 13:18:53 -06002304 """Test handling of a CBFS entry which does not provide contentsy"""
2305 with self.assertRaises(ValueError) as e:
2306 self._DoReadFile('108_cbfs_no_contents.dts')
2307 self.assertIn('Could not complete processing of contents',
2308 str(e.exception))
2309
2310 def testCbfsBadCompress(self):
2311 """Test handling of a bad architecture"""
2312 with self.assertRaises(ValueError) as e:
2313 self._DoReadFile('109_cbfs_bad_compress.dts')
2314 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2315 str(e.exception))
2316
2317 def testCbfsNamedEntries(self):
2318 """Test handling of named entries"""
2319 data = self._DoReadFile('110_cbfs_name.dts')
2320
2321 cbfs = cbfs_util.CbfsReader(data)
2322 self.assertIn('FRED', cbfs.files)
2323 cfile1 = cbfs.files['FRED']
2324 self.assertEqual(U_BOOT_DATA, cfile1.data)
2325
2326 self.assertIn('hello', cbfs.files)
2327 cfile2 = cbfs.files['hello']
2328 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2329
Simon Glassc5ac1382019-07-08 13:18:54 -06002330 def _SetupIfwi(self, fname):
2331 """Set up to run an IFWI test
2332
2333 Args:
2334 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2335 """
2336 self._SetupSplElf()
Simon Glass2090f1e2019-08-24 07:23:00 -06002337 self._SetupTplElf()
Simon Glassc5ac1382019-07-08 13:18:54 -06002338
2339 # Intel Integrated Firmware Image (IFWI) file
2340 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2341 data = fd.read()
2342 TestFunctional._MakeInputFile(fname,data)
2343
2344 def _CheckIfwi(self, data):
2345 """Check that an image with an IFWI contains the correct output
2346
2347 Args:
2348 data: Conents of output file
2349 """
Simon Glassc1aa66e2022-01-29 14:14:04 -07002350 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glassc5ac1382019-07-08 13:18:54 -06002351 if data[:0x1000] != expected_desc:
2352 self.fail('Expected descriptor binary at start of image')
2353
2354 # We expect to find the TPL wil in subpart IBBP entry IBBL
Simon Glassc1aa66e2022-01-29 14:14:04 -07002355 image_fname = tools.get_output_filename('image.bin')
2356 tpl_fname = tools.get_output_filename('tpl.out')
Simon Glass532ae702022-01-09 20:14:01 -07002357 ifwitool = bintool.Bintool.create('ifwitool')
2358 ifwitool.extract(image_fname, 'IBBP', 'IBBL', tpl_fname)
Simon Glassc5ac1382019-07-08 13:18:54 -06002359
Simon Glassc1aa66e2022-01-29 14:14:04 -07002360 tpl_data = tools.read_file(tpl_fname)
Simon Glasse95be632019-08-24 07:22:51 -06002361 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glassc5ac1382019-07-08 13:18:54 -06002362
2363 def testPackX86RomIfwi(self):
2364 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2365 self._SetupIfwi('fitimage.bin')
Simon Glass9255f3c2019-08-24 07:23:01 -06002366 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002367 self._CheckIfwi(data)
2368
2369 def testPackX86RomIfwiNoDesc(self):
2370 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2371 self._SetupIfwi('ifwi.bin')
Simon Glass9255f3c2019-08-24 07:23:01 -06002372 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002373 self._CheckIfwi(data)
2374
2375 def testPackX86RomIfwiNoData(self):
2376 """Test that an x86 ROM with IFWI handles missing data"""
2377 self._SetupIfwi('ifwi.bin')
2378 with self.assertRaises(ValueError) as e:
Simon Glass9255f3c2019-08-24 07:23:01 -06002379 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002380 self.assertIn('Could not complete processing of contents',
2381 str(e.exception))
Simon Glass53af22a2018-07-17 13:25:32 -06002382
Simon Glass4f9ee832022-01-09 20:14:09 -07002383 def testIfwiMissing(self):
2384 """Test that binman still produces an image if ifwitool is missing"""
2385 self._SetupIfwi('fitimage.bin')
2386 with test_util.capture_sys_output() as (_, stderr):
2387 self._DoTestFile('111_x86_rom_ifwi.dts',
2388 force_missing_bintools='ifwitool')
2389 err = stderr.getvalue()
2390 self.assertRegex(err,
2391 "Image 'main-section'.*missing bintools.*: ifwitool")
2392
Simon Glasse073d4e2019-07-08 13:18:56 -06002393 def testCbfsOffset(self):
2394 """Test a CBFS with files at particular offsets
2395
2396 Like all CFBS tests, this is just checking the logic that calls
2397 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2398 """
2399 data = self._DoReadFile('114_cbfs_offset.dts')
2400 size = 0x200
2401
2402 cbfs = cbfs_util.CbfsReader(data)
2403 self.assertEqual(size, cbfs.rom_size)
2404
2405 self.assertIn('u-boot', cbfs.files)
2406 cfile = cbfs.files['u-boot']
2407 self.assertEqual(U_BOOT_DATA, cfile.data)
2408 self.assertEqual(0x40, cfile.cbfs_offset)
2409
2410 self.assertIn('u-boot-dtb', cbfs.files)
2411 cfile2 = cbfs.files['u-boot-dtb']
2412 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2413 self.assertEqual(0x140, cfile2.cbfs_offset)
2414
Simon Glass086cec92019-07-08 14:25:27 -06002415 def testFdtmap(self):
2416 """Test an FDT map can be inserted in the image"""
2417 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2418 fdtmap_data = data[len(U_BOOT_DATA):]
2419 magic = fdtmap_data[:8]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002420 self.assertEqual(b'_FDTMAP_', magic)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002421 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass086cec92019-07-08 14:25:27 -06002422
2423 fdt_data = fdtmap_data[16:]
2424 dtb = fdt.Fdt.FromData(fdt_data)
2425 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002426 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass086cec92019-07-08 14:25:27 -06002427 self.assertEqual({
2428 'image-pos': 0,
2429 'offset': 0,
2430 'u-boot:offset': 0,
2431 'u-boot:size': len(U_BOOT_DATA),
2432 'u-boot:image-pos': 0,
2433 'fdtmap:image-pos': 4,
2434 'fdtmap:offset': 4,
2435 'fdtmap:size': len(fdtmap_data),
2436 'size': len(data),
2437 }, props)
2438
2439 def testFdtmapNoMatch(self):
2440 """Check handling of an FDT map when the section cannot be found"""
2441 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2442
2443 # Mangle the section name, which should cause a mismatch between the
2444 # correct FDT path and the one expected by the section
2445 image = control.images['image']
Simon Glasscf228942019-07-08 14:25:28 -06002446 image._node.path += '-suffix'
Simon Glass086cec92019-07-08 14:25:27 -06002447 entries = image.GetEntries()
2448 fdtmap = entries['fdtmap']
2449 with self.assertRaises(ValueError) as e:
2450 fdtmap._GetFdtmap()
2451 self.assertIn("Cannot locate node for path '/binman-suffix'",
2452 str(e.exception))
2453
Simon Glasscf228942019-07-08 14:25:28 -06002454 def testFdtmapHeader(self):
2455 """Test an FDT map and image header can be inserted in the image"""
2456 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2457 fdtmap_pos = len(U_BOOT_DATA)
2458 fdtmap_data = data[fdtmap_pos:]
2459 fdt_data = fdtmap_data[16:]
2460 dtb = fdt.Fdt.FromData(fdt_data)
2461 fdt_size = dtb.GetFdtObj().totalsize()
2462 hdr_data = data[-8:]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002463 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002464 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2465 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2466
2467 def testFdtmapHeaderStart(self):
2468 """Test an image header can be inserted at the image start"""
2469 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2470 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2471 hdr_data = data[:8]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002472 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002473 offset = struct.unpack('<I', hdr_data[4:])[0]
2474 self.assertEqual(fdtmap_pos, offset)
2475
2476 def testFdtmapHeaderPos(self):
2477 """Test an image header can be inserted at a chosen position"""
2478 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2479 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2480 hdr_data = data[0x80:0x88]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002481 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002482 offset = struct.unpack('<I', hdr_data[4:])[0]
2483 self.assertEqual(fdtmap_pos, offset)
2484
2485 def testHeaderMissingFdtmap(self):
2486 """Test an image header requires an fdtmap"""
2487 with self.assertRaises(ValueError) as e:
2488 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2489 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2490 str(e.exception))
2491
2492 def testHeaderNoLocation(self):
2493 """Test an image header with a no specified location is detected"""
2494 with self.assertRaises(ValueError) as e:
2495 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2496 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2497 str(e.exception))
2498
Simon Glassc52c9e72019-07-08 14:25:37 -06002499 def testEntryExpand(self):
Simon Glass80a66ae2022-03-05 20:18:59 -07002500 """Test extending an entry after it is packed"""
2501 data = self._DoReadFile('121_entry_extend.dts')
Simon Glass79d3c582019-07-20 12:23:57 -06002502 self.assertEqual(b'aaa', data[:3])
2503 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2504 self.assertEqual(b'aaa', data[-3:])
Simon Glassc52c9e72019-07-08 14:25:37 -06002505
Simon Glass80a66ae2022-03-05 20:18:59 -07002506 def testEntryExtendBad(self):
2507 """Test extending an entry after it is packed, twice"""
Simon Glassc52c9e72019-07-08 14:25:37 -06002508 with self.assertRaises(ValueError) as e:
Simon Glass80a66ae2022-03-05 20:18:59 -07002509 self._DoReadFile('122_entry_extend_twice.dts')
Simon Glass61ec04f2019-07-20 12:23:58 -06002510 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glassc52c9e72019-07-08 14:25:37 -06002511 str(e.exception))
2512
Simon Glass80a66ae2022-03-05 20:18:59 -07002513 def testEntryExtendSection(self):
2514 """Test extending an entry within a section after it is packed"""
2515 data = self._DoReadFile('123_entry_extend_section.dts')
Simon Glass79d3c582019-07-20 12:23:57 -06002516 self.assertEqual(b'aaa', data[:3])
2517 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2518 self.assertEqual(b'aaa', data[-3:])
Simon Glassc52c9e72019-07-08 14:25:37 -06002519
Simon Glass6c223fd2019-07-08 14:25:38 -06002520 def testCompressDtb(self):
2521 """Test that compress of device-tree files is supported"""
2522 self._CheckLz4()
2523 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2524 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2525 comp_data = data[len(U_BOOT_DATA):]
2526 orig = self._decompress(comp_data)
2527 dtb = fdt.Fdt.FromData(orig)
2528 dtb.Scan()
2529 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2530 expected = {
2531 'u-boot:size': len(U_BOOT_DATA),
2532 'u-boot-dtb:uncomp-size': len(orig),
2533 'u-boot-dtb:size': len(comp_data),
2534 'size': len(data),
2535 }
2536 self.assertEqual(expected, props)
2537
Simon Glass69f7cb32019-07-08 14:25:41 -06002538 def testCbfsUpdateFdt(self):
2539 """Test that we can update the device tree with CBFS offset/size info"""
2540 self._CheckLz4()
2541 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2542 update_dtb=True)
2543 dtb = fdt.Fdt(out_dtb_fname)
2544 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002545 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass69f7cb32019-07-08 14:25:41 -06002546 del props['cbfs/u-boot:size']
2547 self.assertEqual({
2548 'offset': 0,
2549 'size': len(data),
2550 'image-pos': 0,
2551 'cbfs:offset': 0,
2552 'cbfs:size': len(data),
2553 'cbfs:image-pos': 0,
2554 'cbfs/u-boot:offset': 0x38,
2555 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2556 'cbfs/u-boot:image-pos': 0x38,
2557 'cbfs/u-boot-dtb:offset': 0xb8,
2558 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2559 'cbfs/u-boot-dtb:image-pos': 0xb8,
2560 }, props)
2561
Simon Glass8a1ad062019-07-08 14:25:42 -06002562 def testCbfsBadType(self):
2563 """Test an image header with a no specified location is detected"""
2564 with self.assertRaises(ValueError) as e:
2565 self._DoReadFile('126_cbfs_bad_type.dts')
2566 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2567
Simon Glass41b8ba02019-07-08 14:25:43 -06002568 def testList(self):
2569 """Test listing the files in an image"""
2570 self._CheckLz4()
2571 data = self._DoReadFile('127_list.dts')
2572 image = control.images['image']
2573 entries = image.BuildEntryList()
2574 self.assertEqual(7, len(entries))
2575
2576 ent = entries[0]
2577 self.assertEqual(0, ent.indent)
2578 self.assertEqual('main-section', ent.name)
2579 self.assertEqual('section', ent.etype)
2580 self.assertEqual(len(data), ent.size)
2581 self.assertEqual(0, ent.image_pos)
2582 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002583 self.assertEqual(0, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002584
2585 ent = entries[1]
2586 self.assertEqual(1, ent.indent)
2587 self.assertEqual('u-boot', ent.name)
2588 self.assertEqual('u-boot', ent.etype)
2589 self.assertEqual(len(U_BOOT_DATA), ent.size)
2590 self.assertEqual(0, ent.image_pos)
2591 self.assertEqual(None, ent.uncomp_size)
2592 self.assertEqual(0, ent.offset)
2593
2594 ent = entries[2]
2595 self.assertEqual(1, ent.indent)
2596 self.assertEqual('section', ent.name)
2597 self.assertEqual('section', ent.etype)
2598 section_size = ent.size
2599 self.assertEqual(0x100, ent.image_pos)
2600 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002601 self.assertEqual(0x100, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002602
2603 ent = entries[3]
2604 self.assertEqual(2, ent.indent)
2605 self.assertEqual('cbfs', ent.name)
2606 self.assertEqual('cbfs', ent.etype)
2607 self.assertEqual(0x400, ent.size)
2608 self.assertEqual(0x100, ent.image_pos)
2609 self.assertEqual(None, ent.uncomp_size)
2610 self.assertEqual(0, ent.offset)
2611
2612 ent = entries[4]
2613 self.assertEqual(3, ent.indent)
2614 self.assertEqual('u-boot', ent.name)
2615 self.assertEqual('u-boot', ent.etype)
2616 self.assertEqual(len(U_BOOT_DATA), ent.size)
2617 self.assertEqual(0x138, ent.image_pos)
2618 self.assertEqual(None, ent.uncomp_size)
2619 self.assertEqual(0x38, ent.offset)
2620
2621 ent = entries[5]
2622 self.assertEqual(3, ent.indent)
2623 self.assertEqual('u-boot-dtb', ent.name)
2624 self.assertEqual('text', ent.etype)
2625 self.assertGreater(len(COMPRESS_DATA), ent.size)
2626 self.assertEqual(0x178, ent.image_pos)
2627 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2628 self.assertEqual(0x78, ent.offset)
2629
2630 ent = entries[6]
2631 self.assertEqual(2, ent.indent)
2632 self.assertEqual('u-boot-dtb', ent.name)
2633 self.assertEqual('u-boot-dtb', ent.etype)
2634 self.assertEqual(0x500, ent.image_pos)
2635 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2636 dtb_size = ent.size
2637 # Compressing this data expands it since headers are added
2638 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2639 self.assertEqual(0x400, ent.offset)
2640
2641 self.assertEqual(len(data), 0x100 + section_size)
2642 self.assertEqual(section_size, 0x400 + dtb_size)
2643
Simon Glasse1925fa2019-07-08 14:25:44 -06002644 def testFindFdtmap(self):
2645 """Test locating an FDT map in an image"""
2646 self._CheckLz4()
2647 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2648 image = control.images['image']
2649 entries = image.GetEntries()
2650 entry = entries['fdtmap']
2651 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2652
2653 def testFindFdtmapMissing(self):
2654 """Test failing to locate an FDP map"""
2655 data = self._DoReadFile('005_simple.dts')
2656 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2657
Simon Glass2d260032019-07-08 14:25:45 -06002658 def testFindImageHeader(self):
2659 """Test locating a image header"""
2660 self._CheckLz4()
Simon Glassffded752019-07-08 14:25:46 -06002661 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002662 image = control.images['image']
2663 entries = image.GetEntries()
2664 entry = entries['fdtmap']
2665 # The header should point to the FDT map
2666 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2667
2668 def testFindImageHeaderStart(self):
2669 """Test locating a image header located at the start of an image"""
Simon Glassffded752019-07-08 14:25:46 -06002670 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002671 image = control.images['image']
2672 entries = image.GetEntries()
2673 entry = entries['fdtmap']
2674 # The header should point to the FDT map
2675 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2676
2677 def testFindImageHeaderMissing(self):
2678 """Test failing to locate an image header"""
2679 data = self._DoReadFile('005_simple.dts')
2680 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2681
Simon Glassffded752019-07-08 14:25:46 -06002682 def testReadImage(self):
2683 """Test reading an image and accessing its FDT map"""
2684 self._CheckLz4()
2685 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002686 image_fname = tools.get_output_filename('image.bin')
Simon Glassffded752019-07-08 14:25:46 -06002687 orig_image = control.images['image']
2688 image = Image.FromFile(image_fname)
2689 self.assertEqual(orig_image.GetEntries().keys(),
2690 image.GetEntries().keys())
2691
2692 orig_entry = orig_image.GetEntries()['fdtmap']
2693 entry = image.GetEntries()['fdtmap']
2694 self.assertEquals(orig_entry.offset, entry.offset)
2695 self.assertEquals(orig_entry.size, entry.size)
2696 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2697
2698 def testReadImageNoHeader(self):
2699 """Test accessing an image's FDT map without an image header"""
2700 self._CheckLz4()
2701 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002702 image_fname = tools.get_output_filename('image.bin')
Simon Glassffded752019-07-08 14:25:46 -06002703 image = Image.FromFile(image_fname)
2704 self.assertTrue(isinstance(image, Image))
Simon Glass10f9d002019-07-20 12:23:50 -06002705 self.assertEqual('image', image.image_name[-5:])
Simon Glassffded752019-07-08 14:25:46 -06002706
2707 def testReadImageFail(self):
2708 """Test failing to read an image image's FDT map"""
2709 self._DoReadFile('005_simple.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002710 image_fname = tools.get_output_filename('image.bin')
Simon Glassffded752019-07-08 14:25:46 -06002711 with self.assertRaises(ValueError) as e:
2712 image = Image.FromFile(image_fname)
2713 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glasse073d4e2019-07-08 13:18:56 -06002714
Simon Glass61f564d2019-07-08 14:25:48 -06002715 def testListCmd(self):
2716 """Test listing the files in an image using an Fdtmap"""
2717 self._CheckLz4()
2718 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2719
2720 # lz4 compression size differs depending on the version
2721 image = control.images['image']
2722 entries = image.GetEntries()
2723 section_size = entries['section'].size
2724 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2725 fdtmap_offset = entries['fdtmap'].offset
2726
Simon Glassf86a7362019-07-20 12:24:10 -06002727 try:
2728 tmpdir, updated_fname = self._SetupImageInTmpdir()
2729 with test_util.capture_sys_output() as (stdout, stderr):
2730 self._DoBinman('ls', '-i', updated_fname)
2731 finally:
2732 shutil.rmtree(tmpdir)
Simon Glass61f564d2019-07-08 14:25:48 -06002733 lines = stdout.getvalue().splitlines()
2734 expected = [
2735'Name Image-pos Size Entry-type Offset Uncomp-size',
2736'----------------------------------------------------------------------',
2737'main-section 0 c00 section 0',
2738' u-boot 0 4 u-boot 0',
2739' section 100 %x section 100' % section_size,
2740' cbfs 100 400 cbfs 0',
2741' u-boot 138 4 u-boot 38',
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002742' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glass61f564d2019-07-08 14:25:48 -06002743' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002744' fdtmap %x 3bd fdtmap %x' %
Simon Glass61f564d2019-07-08 14:25:48 -06002745 (fdtmap_offset, fdtmap_offset),
2746' image-header bf8 8 image-header bf8',
2747 ]
2748 self.assertEqual(expected, lines)
2749
2750 def testListCmdFail(self):
2751 """Test failing to list an image"""
2752 self._DoReadFile('005_simple.dts')
Simon Glassf86a7362019-07-20 12:24:10 -06002753 try:
2754 tmpdir, updated_fname = self._SetupImageInTmpdir()
2755 with self.assertRaises(ValueError) as e:
2756 self._DoBinman('ls', '-i', updated_fname)
2757 finally:
2758 shutil.rmtree(tmpdir)
Simon Glass61f564d2019-07-08 14:25:48 -06002759 self.assertIn("Cannot find FDT map in image", str(e.exception))
2760
2761 def _RunListCmd(self, paths, expected):
2762 """List out entries and check the result
2763
2764 Args:
2765 paths: List of paths to pass to the list command
2766 expected: Expected list of filenames to be returned, in order
2767 """
2768 self._CheckLz4()
2769 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002770 image_fname = tools.get_output_filename('image.bin')
Simon Glass61f564d2019-07-08 14:25:48 -06002771 image = Image.FromFile(image_fname)
2772 lines = image.GetListEntries(paths)[1]
2773 files = [line[0].strip() for line in lines[1:]]
2774 self.assertEqual(expected, files)
2775
2776 def testListCmdSection(self):
2777 """Test listing the files in a section"""
2778 self._RunListCmd(['section'],
2779 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2780
2781 def testListCmdFile(self):
2782 """Test listing a particular file"""
2783 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2784
2785 def testListCmdWildcard(self):
2786 """Test listing a wildcarded file"""
2787 self._RunListCmd(['*boot*'],
2788 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2789
2790 def testListCmdWildcardMulti(self):
2791 """Test listing a wildcarded file"""
2792 self._RunListCmd(['*cb*', '*head*'],
2793 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2794
2795 def testListCmdEmpty(self):
2796 """Test listing a wildcarded file"""
2797 self._RunListCmd(['nothing'], [])
2798
2799 def testListCmdPath(self):
2800 """Test listing the files in a sub-entry of a section"""
2801 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2802
Simon Glassf667e452019-07-08 14:25:50 -06002803 def _RunExtractCmd(self, entry_name, decomp=True):
2804 """Extract an entry from an image
2805
2806 Args:
2807 entry_name: Entry name to extract
2808 decomp: True to decompress the data if compressed, False to leave
2809 it in its raw uncompressed format
2810
2811 Returns:
2812 data from entry
2813 """
2814 self._CheckLz4()
2815 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002816 image_fname = tools.get_output_filename('image.bin')
Simon Glassf667e452019-07-08 14:25:50 -06002817 return control.ReadEntry(image_fname, entry_name, decomp)
2818
2819 def testExtractSimple(self):
2820 """Test extracting a single file"""
2821 data = self._RunExtractCmd('u-boot')
2822 self.assertEqual(U_BOOT_DATA, data)
2823
Simon Glass71ce0ba2019-07-08 14:25:52 -06002824 def testExtractSection(self):
2825 """Test extracting the files in a section"""
2826 data = self._RunExtractCmd('section')
2827 cbfs_data = data[:0x400]
2828 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002829 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass71ce0ba2019-07-08 14:25:52 -06002830 dtb_data = data[0x400:]
2831 dtb = self._decompress(dtb_data)
2832 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2833
2834 def testExtractCompressed(self):
2835 """Test extracting compressed data"""
2836 data = self._RunExtractCmd('section/u-boot-dtb')
2837 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2838
2839 def testExtractRaw(self):
2840 """Test extracting compressed data without decompressing it"""
2841 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2842 dtb = self._decompress(data)
2843 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2844
2845 def testExtractCbfs(self):
2846 """Test extracting CBFS data"""
2847 data = self._RunExtractCmd('section/cbfs/u-boot')
2848 self.assertEqual(U_BOOT_DATA, data)
2849
2850 def testExtractCbfsCompressed(self):
2851 """Test extracting CBFS compressed data"""
2852 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2853 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2854
2855 def testExtractCbfsRaw(self):
2856 """Test extracting CBFS compressed data without decompressing it"""
2857 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Simon Glass0d1e95a2022-01-09 20:14:04 -07002858 dtb = comp_util.decompress(data, 'lzma', with_header=False)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002859 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2860
Simon Glassf667e452019-07-08 14:25:50 -06002861 def testExtractBadEntry(self):
2862 """Test extracting a bad section path"""
2863 with self.assertRaises(ValueError) as e:
2864 self._RunExtractCmd('section/does-not-exist')
2865 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2866 str(e.exception))
2867
2868 def testExtractMissingFile(self):
2869 """Test extracting file that does not exist"""
2870 with self.assertRaises(IOError) as e:
2871 control.ReadEntry('missing-file', 'name')
2872
2873 def testExtractBadFile(self):
2874 """Test extracting an invalid file"""
2875 fname = os.path.join(self._indir, 'badfile')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002876 tools.write_file(fname, b'')
Simon Glassf667e452019-07-08 14:25:50 -06002877 with self.assertRaises(ValueError) as e:
2878 control.ReadEntry(fname, 'name')
2879
Simon Glass71ce0ba2019-07-08 14:25:52 -06002880 def testExtractCmd(self):
2881 """Test extracting a file fron an image on the command line"""
2882 self._CheckLz4()
2883 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass71ce0ba2019-07-08 14:25:52 -06002884 fname = os.path.join(self._indir, 'output.extact')
Simon Glassf86a7362019-07-20 12:24:10 -06002885 try:
2886 tmpdir, updated_fname = self._SetupImageInTmpdir()
2887 with test_util.capture_sys_output() as (stdout, stderr):
2888 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2889 '-f', fname)
2890 finally:
2891 shutil.rmtree(tmpdir)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002892 data = tools.read_file(fname)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002893 self.assertEqual(U_BOOT_DATA, data)
2894
2895 def testExtractOneEntry(self):
2896 """Test extracting a single entry fron an image """
2897 self._CheckLz4()
2898 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002899 image_fname = tools.get_output_filename('image.bin')
Simon Glass71ce0ba2019-07-08 14:25:52 -06002900 fname = os.path.join(self._indir, 'output.extact')
2901 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
Simon Glassc1aa66e2022-01-29 14:14:04 -07002902 data = tools.read_file(fname)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002903 self.assertEqual(U_BOOT_DATA, data)
2904
2905 def _CheckExtractOutput(self, decomp):
2906 """Helper to test file output with and without decompression
2907
2908 Args:
2909 decomp: True to decompress entry data, False to output it raw
2910 """
2911 def _CheckPresent(entry_path, expect_data, expect_size=None):
2912 """Check and remove expected file
2913
2914 This checks the data/size of a file and removes the file both from
2915 the outfiles set and from the output directory. Once all files are
2916 processed, both the set and directory should be empty.
2917
2918 Args:
2919 entry_path: Entry path
2920 expect_data: Data to expect in file, or None to skip check
2921 expect_size: Size of data to expect in file, or None to skip
2922 """
2923 path = os.path.join(outdir, entry_path)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002924 data = tools.read_file(path)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002925 os.remove(path)
2926 if expect_data:
2927 self.assertEqual(expect_data, data)
2928 elif expect_size:
2929 self.assertEqual(expect_size, len(data))
2930 outfiles.remove(path)
2931
2932 def _CheckDirPresent(name):
2933 """Remove expected directory
2934
2935 This gives an error if the directory does not exist as expected
2936
2937 Args:
2938 name: Name of directory to remove
2939 """
2940 path = os.path.join(outdir, name)
2941 os.rmdir(path)
2942
2943 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002944 image_fname = tools.get_output_filename('image.bin')
Simon Glass71ce0ba2019-07-08 14:25:52 -06002945 outdir = os.path.join(self._indir, 'extract')
2946 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2947
2948 # Create a set of all file that were output (should be 9)
2949 outfiles = set()
2950 for root, dirs, files in os.walk(outdir):
2951 outfiles |= set([os.path.join(root, fname) for fname in files])
2952 self.assertEqual(9, len(outfiles))
2953 self.assertEqual(9, len(einfos))
2954
2955 image = control.images['image']
2956 entries = image.GetEntries()
2957
2958 # Check the 9 files in various ways
2959 section = entries['section']
2960 section_entries = section.GetEntries()
2961 cbfs_entries = section_entries['cbfs'].GetEntries()
2962 _CheckPresent('u-boot', U_BOOT_DATA)
2963 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
2964 dtb_len = EXTRACT_DTB_SIZE
2965 if not decomp:
2966 dtb_len = cbfs_entries['u-boot-dtb'].size
2967 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
2968 if not decomp:
2969 dtb_len = section_entries['u-boot-dtb'].size
2970 _CheckPresent('section/u-boot-dtb', None, dtb_len)
2971
2972 fdtmap = entries['fdtmap']
2973 _CheckPresent('fdtmap', fdtmap.data)
2974 hdr = entries['image-header']
2975 _CheckPresent('image-header', hdr.data)
2976
2977 _CheckPresent('section/root', section.data)
2978 cbfs = section_entries['cbfs']
2979 _CheckPresent('section/cbfs/root', cbfs.data)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002980 data = tools.read_file(image_fname)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002981 _CheckPresent('root', data)
2982
2983 # There should be no files left. Remove all the directories to check.
2984 # If there are any files/dirs remaining, one of these checks will fail.
2985 self.assertEqual(0, len(outfiles))
2986 _CheckDirPresent('section/cbfs')
2987 _CheckDirPresent('section')
2988 _CheckDirPresent('')
2989 self.assertFalse(os.path.exists(outdir))
2990
2991 def testExtractAllEntries(self):
2992 """Test extracting all entries"""
2993 self._CheckLz4()
2994 self._CheckExtractOutput(decomp=True)
2995
2996 def testExtractAllEntriesRaw(self):
2997 """Test extracting all entries without decompressing them"""
2998 self._CheckLz4()
2999 self._CheckExtractOutput(decomp=False)
3000
3001 def testExtractSelectedEntries(self):
3002 """Test extracting some entries"""
3003 self._CheckLz4()
3004 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003005 image_fname = tools.get_output_filename('image.bin')
Simon Glass71ce0ba2019-07-08 14:25:52 -06003006 outdir = os.path.join(self._indir, 'extract')
3007 einfos = control.ExtractEntries(image_fname, None, outdir,
3008 ['*cb*', '*head*'])
3009
3010 # File output is tested by testExtractAllEntries(), so just check that
3011 # the expected entries are selected
3012 names = [einfo.name for einfo in einfos]
3013 self.assertEqual(names,
3014 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
3015
3016 def testExtractNoEntryPaths(self):
3017 """Test extracting some entries"""
3018 self._CheckLz4()
3019 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003020 image_fname = tools.get_output_filename('image.bin')
Simon Glass71ce0ba2019-07-08 14:25:52 -06003021 with self.assertRaises(ValueError) as e:
3022 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassbb5edc12019-07-20 12:24:14 -06003023 self.assertIn('Must specify an entry path to write with -f',
Simon Glass71ce0ba2019-07-08 14:25:52 -06003024 str(e.exception))
3025
3026 def testExtractTooManyEntryPaths(self):
3027 """Test extracting some entries"""
3028 self._CheckLz4()
3029 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003030 image_fname = tools.get_output_filename('image.bin')
Simon Glass71ce0ba2019-07-08 14:25:52 -06003031 with self.assertRaises(ValueError) as e:
3032 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassbb5edc12019-07-20 12:24:14 -06003033 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass71ce0ba2019-07-08 14:25:52 -06003034 str(e.exception))
3035
Simon Glasse2705fa2019-07-08 14:25:53 -06003036 def testPackAlignSection(self):
3037 """Test that sections can have alignment"""
3038 self._DoReadFile('131_pack_align_section.dts')
3039
3040 self.assertIn('image', control.images)
3041 image = control.images['image']
3042 entries = image.GetEntries()
3043 self.assertEqual(3, len(entries))
3044
3045 # First u-boot
3046 self.assertIn('u-boot', entries)
3047 entry = entries['u-boot']
3048 self.assertEqual(0, entry.offset)
3049 self.assertEqual(0, entry.image_pos)
3050 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3051 self.assertEqual(len(U_BOOT_DATA), entry.size)
3052
3053 # Section0
3054 self.assertIn('section0', entries)
3055 section0 = entries['section0']
3056 self.assertEqual(0x10, section0.offset)
3057 self.assertEqual(0x10, section0.image_pos)
3058 self.assertEqual(len(U_BOOT_DATA), section0.size)
3059
3060 # Second u-boot
3061 section_entries = section0.GetEntries()
3062 self.assertIn('u-boot', section_entries)
3063 entry = section_entries['u-boot']
3064 self.assertEqual(0, entry.offset)
3065 self.assertEqual(0x10, entry.image_pos)
3066 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3067 self.assertEqual(len(U_BOOT_DATA), entry.size)
3068
3069 # Section1
3070 self.assertIn('section1', entries)
3071 section1 = entries['section1']
3072 self.assertEqual(0x14, section1.offset)
3073 self.assertEqual(0x14, section1.image_pos)
3074 self.assertEqual(0x20, section1.size)
3075
3076 # Second u-boot
3077 section_entries = section1.GetEntries()
3078 self.assertIn('u-boot', section_entries)
3079 entry = section_entries['u-boot']
3080 self.assertEqual(0, entry.offset)
3081 self.assertEqual(0x14, entry.image_pos)
3082 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3083 self.assertEqual(len(U_BOOT_DATA), entry.size)
3084
3085 # Section2
3086 self.assertIn('section2', section_entries)
3087 section2 = section_entries['section2']
3088 self.assertEqual(0x4, section2.offset)
3089 self.assertEqual(0x18, section2.image_pos)
3090 self.assertEqual(4, section2.size)
3091
3092 # Third u-boot
3093 section_entries = section2.GetEntries()
3094 self.assertIn('u-boot', section_entries)
3095 entry = section_entries['u-boot']
3096 self.assertEqual(0, entry.offset)
3097 self.assertEqual(0x18, entry.image_pos)
3098 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3099 self.assertEqual(len(U_BOOT_DATA), entry.size)
3100
Simon Glass51014aa2019-07-20 12:23:56 -06003101 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3102 dts='132_replace.dts'):
Simon Glass10f9d002019-07-20 12:23:50 -06003103 """Replace an entry in an image
3104
3105 This writes the entry data to update it, then opens the updated file and
3106 returns the value that it now finds there.
3107
3108 Args:
3109 entry_name: Entry name to replace
3110 data: Data to replace it with
3111 decomp: True to compress the data if needed, False if data is
3112 already compressed so should be used as is
Simon Glass51014aa2019-07-20 12:23:56 -06003113 allow_resize: True to allow entries to change size, False to raise
3114 an exception
Simon Glass10f9d002019-07-20 12:23:50 -06003115
3116 Returns:
3117 Tuple:
3118 data from entry
3119 data from fdtmap (excluding header)
Simon Glass51014aa2019-07-20 12:23:56 -06003120 Image object that was modified
Simon Glass10f9d002019-07-20 12:23:50 -06003121 """
Simon Glass51014aa2019-07-20 12:23:56 -06003122 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass10f9d002019-07-20 12:23:50 -06003123 update_dtb=True)[1]
3124
3125 self.assertIn('image', control.images)
3126 image = control.images['image']
3127 entries = image.GetEntries()
3128 orig_dtb_data = entries['u-boot-dtb'].data
3129 orig_fdtmap_data = entries['fdtmap'].data
3130
Simon Glassc1aa66e2022-01-29 14:14:04 -07003131 image_fname = tools.get_output_filename('image.bin')
3132 updated_fname = tools.get_output_filename('image-updated.bin')
3133 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glass51014aa2019-07-20 12:23:56 -06003134 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3135 allow_resize)
Simon Glass10f9d002019-07-20 12:23:50 -06003136 data = control.ReadEntry(updated_fname, entry_name, decomp)
3137
Simon Glass51014aa2019-07-20 12:23:56 -06003138 # The DT data should not change unless resized:
3139 if not allow_resize:
3140 new_dtb_data = entries['u-boot-dtb'].data
3141 self.assertEqual(new_dtb_data, orig_dtb_data)
3142 new_fdtmap_data = entries['fdtmap'].data
3143 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass10f9d002019-07-20 12:23:50 -06003144
Simon Glass51014aa2019-07-20 12:23:56 -06003145 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass10f9d002019-07-20 12:23:50 -06003146
3147 def testReplaceSimple(self):
3148 """Test replacing a single file"""
3149 expected = b'x' * len(U_BOOT_DATA)
Simon Glass51014aa2019-07-20 12:23:56 -06003150 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3151 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06003152 self.assertEqual(expected, data)
3153
3154 # Test that the state looks right. There should be an FDT for the fdtmap
3155 # that we jsut read back in, and it should match what we find in the
3156 # 'control' tables. Checking for an FDT that does not exist should
3157 # return None.
3158 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glass51014aa2019-07-20 12:23:56 -06003159 self.assertIsNotNone(path)
Simon Glass10f9d002019-07-20 12:23:50 -06003160 self.assertEqual(expected_fdtmap, fdtmap)
3161
3162 dtb = state.GetFdtForEtype('fdtmap')
3163 self.assertEqual(dtb.GetContents(), fdtmap)
3164
3165 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3166 self.assertIsNone(missing_path)
3167 self.assertIsNone(missing_fdtmap)
3168
3169 missing_dtb = state.GetFdtForEtype('missing')
3170 self.assertIsNone(missing_dtb)
3171
3172 self.assertEqual('/binman', state.fdt_path_prefix)
3173
3174 def testReplaceResizeFail(self):
3175 """Test replacing a file by something larger"""
3176 expected = U_BOOT_DATA + b'x'
3177 with self.assertRaises(ValueError) as e:
Simon Glass51014aa2019-07-20 12:23:56 -06003178 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3179 dts='139_replace_repack.dts')
Simon Glass10f9d002019-07-20 12:23:50 -06003180 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3181 str(e.exception))
3182
3183 def testReplaceMulti(self):
3184 """Test replacing entry data where multiple images are generated"""
3185 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3186 update_dtb=True)[0]
3187 expected = b'x' * len(U_BOOT_DATA)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003188 updated_fname = tools.get_output_filename('image-updated.bin')
3189 tools.write_file(updated_fname, data)
Simon Glass10f9d002019-07-20 12:23:50 -06003190 entry_name = 'u-boot'
Simon Glass51014aa2019-07-20 12:23:56 -06003191 control.WriteEntry(updated_fname, entry_name, expected,
3192 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06003193 data = control.ReadEntry(updated_fname, entry_name)
3194 self.assertEqual(expected, data)
3195
3196 # Check the state looks right.
3197 self.assertEqual('/binman/image', state.fdt_path_prefix)
3198
3199 # Now check we can write the first image
Simon Glassc1aa66e2022-01-29 14:14:04 -07003200 image_fname = tools.get_output_filename('first-image.bin')
3201 updated_fname = tools.get_output_filename('first-updated.bin')
3202 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glass10f9d002019-07-20 12:23:50 -06003203 entry_name = 'u-boot'
Simon Glass51014aa2019-07-20 12:23:56 -06003204 control.WriteEntry(updated_fname, entry_name, expected,
3205 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06003206 data = control.ReadEntry(updated_fname, entry_name)
3207 self.assertEqual(expected, data)
3208
3209 # Check the state looks right.
3210 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass8beb11e2019-07-08 14:25:47 -06003211
Simon Glass12bb1a92019-07-20 12:23:51 -06003212 def testUpdateFdtAllRepack(self):
3213 """Test that all device trees are updated with offset/size info"""
3214 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3215 SECTION_SIZE = 0x300
3216 DTB_SIZE = 602
3217 FDTMAP_SIZE = 608
3218 base_expected = {
3219 'offset': 0,
3220 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3221 'image-pos': 0,
3222 'section:offset': 0,
3223 'section:size': SECTION_SIZE,
3224 'section:image-pos': 0,
3225 'section/u-boot-dtb:offset': 4,
3226 'section/u-boot-dtb:size': 636,
3227 'section/u-boot-dtb:image-pos': 4,
3228 'u-boot-spl-dtb:offset': SECTION_SIZE,
3229 'u-boot-spl-dtb:size': DTB_SIZE,
3230 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3231 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3232 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3233 'u-boot-tpl-dtb:size': DTB_SIZE,
3234 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3235 'fdtmap:size': FDTMAP_SIZE,
3236 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3237 }
3238 main_expected = {
3239 'section:orig-size': SECTION_SIZE,
3240 'section/u-boot-dtb:orig-offset': 4,
3241 }
3242
3243 # We expect three device-tree files in the output, with the first one
3244 # within a fixed-size section.
3245 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3246 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3247 # main U-Boot tree. All three should have the same positions and offset
3248 # except that the main tree should include the main_expected properties
3249 start = 4
3250 for item in ['', 'spl', 'tpl', None]:
3251 if item is None:
3252 start += 16 # Move past fdtmap header
3253 dtb = fdt.Fdt.FromData(data[start:])
3254 dtb.Scan()
3255 props = self._GetPropTree(dtb,
3256 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3257 prefix='/' if item is None else '/binman/')
3258 expected = dict(base_expected)
3259 if item:
3260 expected[item] = 0
3261 else:
3262 # Main DTB and fdtdec should include the 'orig-' properties
3263 expected.update(main_expected)
3264 # Helpful for debugging:
3265 #for prop in sorted(props):
3266 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3267 self.assertEqual(expected, props)
3268 if item == '':
3269 start = SECTION_SIZE
3270 else:
3271 start += dtb._fdt_obj.totalsize()
3272
Simon Glasseba1f0c2019-07-20 12:23:55 -06003273 def testFdtmapHeaderMiddle(self):
3274 """Test an FDT map in the middle of an image when it should be at end"""
3275 with self.assertRaises(ValueError) as e:
3276 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3277 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3278 str(e.exception))
3279
3280 def testFdtmapHeaderStartBad(self):
3281 """Test an FDT map in middle of an image when it should be at start"""
3282 with self.assertRaises(ValueError) as e:
3283 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3284 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3285 str(e.exception))
3286
3287 def testFdtmapHeaderEndBad(self):
3288 """Test an FDT map at the start of an image when it should be at end"""
3289 with self.assertRaises(ValueError) as e:
3290 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3291 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3292 str(e.exception))
3293
3294 def testFdtmapHeaderNoSize(self):
3295 """Test an image header at the end of an image with undefined size"""
3296 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3297
Simon Glass51014aa2019-07-20 12:23:56 -06003298 def testReplaceResize(self):
3299 """Test replacing a single file in an entry with a larger file"""
3300 expected = U_BOOT_DATA + b'x'
3301 data, _, image = self._RunReplaceCmd('u-boot', expected,
3302 dts='139_replace_repack.dts')
3303 self.assertEqual(expected, data)
3304
3305 entries = image.GetEntries()
3306 dtb_data = entries['u-boot-dtb'].data
3307 dtb = fdt.Fdt.FromData(dtb_data)
3308 dtb.Scan()
3309
3310 # The u-boot section should now be larger in the dtb
3311 node = dtb.GetNode('/binman/u-boot')
3312 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3313
3314 # Same for the fdtmap
3315 fdata = entries['fdtmap'].data
3316 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3317 fdtb.Scan()
3318 fnode = fdtb.GetNode('/u-boot')
3319 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3320
3321 def testReplaceResizeNoRepack(self):
3322 """Test replacing an entry with a larger file when not allowed"""
3323 expected = U_BOOT_DATA + b'x'
3324 with self.assertRaises(ValueError) as e:
3325 self._RunReplaceCmd('u-boot', expected)
3326 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3327 str(e.exception))
3328
Simon Glass61ec04f2019-07-20 12:23:58 -06003329 def testEntryShrink(self):
3330 """Test contracting an entry after it is packed"""
3331 try:
3332 state.SetAllowEntryContraction(True)
3333 data = self._DoReadFileDtb('140_entry_shrink.dts',
3334 update_dtb=True)[0]
3335 finally:
3336 state.SetAllowEntryContraction(False)
3337 self.assertEqual(b'a', data[:1])
3338 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3339 self.assertEqual(b'a', data[-1:])
3340
3341 def testEntryShrinkFail(self):
3342 """Test not being allowed to contract an entry after it is packed"""
3343 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3344
3345 # In this case there is a spare byte at the end of the data. The size of
3346 # the contents is only 1 byte but we still have the size before it
3347 # shrunk.
3348 self.assertEqual(b'a\0', data[:2])
3349 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3350 self.assertEqual(b'a\0', data[-2:])
3351
Simon Glass27145fd2019-07-20 12:24:01 -06003352 def testDescriptorOffset(self):
3353 """Test that the Intel descriptor is always placed at at the start"""
3354 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3355 image = control.images['image']
3356 entries = image.GetEntries()
3357 desc = entries['intel-descriptor']
3358 self.assertEqual(0xff800000, desc.offset);
3359 self.assertEqual(0xff800000, desc.image_pos);
3360
Simon Glasseb0f4a42019-07-20 12:24:06 -06003361 def testReplaceCbfs(self):
3362 """Test replacing a single file in CBFS without changing the size"""
3363 self._CheckLz4()
3364 expected = b'x' * len(U_BOOT_DATA)
3365 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003366 updated_fname = tools.get_output_filename('image-updated.bin')
3367 tools.write_file(updated_fname, data)
Simon Glasseb0f4a42019-07-20 12:24:06 -06003368 entry_name = 'section/cbfs/u-boot'
3369 control.WriteEntry(updated_fname, entry_name, expected,
3370 allow_resize=True)
3371 data = control.ReadEntry(updated_fname, entry_name)
3372 self.assertEqual(expected, data)
3373
3374 def testReplaceResizeCbfs(self):
3375 """Test replacing a single file in CBFS with one of a different size"""
3376 self._CheckLz4()
3377 expected = U_BOOT_DATA + b'x'
3378 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003379 updated_fname = tools.get_output_filename('image-updated.bin')
3380 tools.write_file(updated_fname, data)
Simon Glasseb0f4a42019-07-20 12:24:06 -06003381 entry_name = 'section/cbfs/u-boot'
3382 control.WriteEntry(updated_fname, entry_name, expected,
3383 allow_resize=True)
3384 data = control.ReadEntry(updated_fname, entry_name)
3385 self.assertEqual(expected, data)
3386
Simon Glassa6cb9952019-07-20 12:24:15 -06003387 def _SetupForReplace(self):
3388 """Set up some files to use to replace entries
3389
3390 This generates an image, copies it to a new file, extracts all the files
3391 in it and updates some of them
3392
3393 Returns:
3394 List
3395 Image filename
3396 Output directory
3397 Expected values for updated entries, each a string
3398 """
3399 data = self._DoReadFileRealDtb('143_replace_all.dts')
3400
Simon Glassc1aa66e2022-01-29 14:14:04 -07003401 updated_fname = tools.get_output_filename('image-updated.bin')
3402 tools.write_file(updated_fname, data)
Simon Glassa6cb9952019-07-20 12:24:15 -06003403
3404 outdir = os.path.join(self._indir, 'extract')
3405 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3406
3407 expected1 = b'x' + U_BOOT_DATA + b'y'
3408 u_boot_fname1 = os.path.join(outdir, 'u-boot')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003409 tools.write_file(u_boot_fname1, expected1)
Simon Glassa6cb9952019-07-20 12:24:15 -06003410
3411 expected2 = b'a' + U_BOOT_DATA + b'b'
3412 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003413 tools.write_file(u_boot_fname2, expected2)
Simon Glassa6cb9952019-07-20 12:24:15 -06003414
3415 expected_text = b'not the same text'
3416 text_fname = os.path.join(outdir, 'text')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003417 tools.write_file(text_fname, expected_text)
Simon Glassa6cb9952019-07-20 12:24:15 -06003418
3419 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3420 dtb = fdt.FdtScan(dtb_fname)
3421 node = dtb.GetNode('/binman/text')
3422 node.AddString('my-property', 'the value')
3423 dtb.Sync(auto_resize=True)
3424 dtb.Flush()
3425
3426 return updated_fname, outdir, expected1, expected2, expected_text
3427
3428 def _CheckReplaceMultiple(self, entry_paths):
3429 """Handle replacing the contents of multiple entries
3430
3431 Args:
3432 entry_paths: List of entry paths to replace
3433
3434 Returns:
3435 List
3436 Dict of entries in the image:
3437 key: Entry name
3438 Value: Entry object
3439 Expected values for updated entries, each a string
3440 """
3441 updated_fname, outdir, expected1, expected2, expected_text = (
3442 self._SetupForReplace())
3443 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3444
3445 image = Image.FromFile(updated_fname)
3446 image.LoadData()
3447 return image.GetEntries(), expected1, expected2, expected_text
3448
3449 def testReplaceAll(self):
3450 """Test replacing the contents of all entries"""
3451 entries, expected1, expected2, expected_text = (
3452 self._CheckReplaceMultiple([]))
3453 data = entries['u-boot'].data
3454 self.assertEqual(expected1, data)
3455
3456 data = entries['u-boot2'].data
3457 self.assertEqual(expected2, data)
3458
3459 data = entries['text'].data
3460 self.assertEqual(expected_text, data)
3461
3462 # Check that the device tree is updated
3463 data = entries['u-boot-dtb'].data
3464 dtb = fdt.Fdt.FromData(data)
3465 dtb.Scan()
3466 node = dtb.GetNode('/binman/text')
3467 self.assertEqual('the value', node.props['my-property'].value)
3468
3469 def testReplaceSome(self):
3470 """Test replacing the contents of a few entries"""
3471 entries, expected1, expected2, expected_text = (
3472 self._CheckReplaceMultiple(['u-boot2', 'text']))
3473
3474 # This one should not change
3475 data = entries['u-boot'].data
3476 self.assertEqual(U_BOOT_DATA, data)
3477
3478 data = entries['u-boot2'].data
3479 self.assertEqual(expected2, data)
3480
3481 data = entries['text'].data
3482 self.assertEqual(expected_text, data)
3483
3484 def testReplaceCmd(self):
3485 """Test replacing a file fron an image on the command line"""
3486 self._DoReadFileRealDtb('143_replace_all.dts')
3487
3488 try:
3489 tmpdir, updated_fname = self._SetupImageInTmpdir()
3490
3491 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3492 expected = b'x' * len(U_BOOT_DATA)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003493 tools.write_file(fname, expected)
Simon Glassa6cb9952019-07-20 12:24:15 -06003494
3495 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003496 data = tools.read_file(updated_fname)
Simon Glassa6cb9952019-07-20 12:24:15 -06003497 self.assertEqual(expected, data[:len(expected)])
3498 map_fname = os.path.join(tmpdir, 'image-updated.map')
3499 self.assertFalse(os.path.exists(map_fname))
3500 finally:
3501 shutil.rmtree(tmpdir)
3502
3503 def testReplaceCmdSome(self):
3504 """Test replacing some files fron an image on the command line"""
3505 updated_fname, outdir, expected1, expected2, expected_text = (
3506 self._SetupForReplace())
3507
3508 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3509 'u-boot2', 'text')
3510
Simon Glassc1aa66e2022-01-29 14:14:04 -07003511 tools.prepare_output_dir(None)
Simon Glassa6cb9952019-07-20 12:24:15 -06003512 image = Image.FromFile(updated_fname)
3513 image.LoadData()
3514 entries = image.GetEntries()
3515
3516 # This one should not change
3517 data = entries['u-boot'].data
3518 self.assertEqual(U_BOOT_DATA, data)
3519
3520 data = entries['u-boot2'].data
3521 self.assertEqual(expected2, data)
3522
3523 data = entries['text'].data
3524 self.assertEqual(expected_text, data)
3525
3526 def testReplaceMissing(self):
3527 """Test replacing entries where the file is missing"""
3528 updated_fname, outdir, expected1, expected2, expected_text = (
3529 self._SetupForReplace())
3530
3531 # Remove one of the files, to generate a warning
3532 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3533 os.remove(u_boot_fname1)
3534
3535 with test_util.capture_sys_output() as (stdout, stderr):
3536 control.ReplaceEntries(updated_fname, None, outdir, [])
3537 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass38fdb4c2020-07-09 18:39:39 -06003538 stderr.getvalue())
Simon Glassa6cb9952019-07-20 12:24:15 -06003539
3540 def testReplaceCmdMap(self):
3541 """Test replacing a file fron an image on the command line"""
3542 self._DoReadFileRealDtb('143_replace_all.dts')
3543
3544 try:
3545 tmpdir, updated_fname = self._SetupImageInTmpdir()
3546
3547 fname = os.path.join(self._indir, 'update-u-boot.bin')
3548 expected = b'x' * len(U_BOOT_DATA)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003549 tools.write_file(fname, expected)
Simon Glassa6cb9952019-07-20 12:24:15 -06003550
3551 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3552 '-f', fname, '-m')
3553 map_fname = os.path.join(tmpdir, 'image-updated.map')
3554 self.assertTrue(os.path.exists(map_fname))
3555 finally:
3556 shutil.rmtree(tmpdir)
3557
3558 def testReplaceNoEntryPaths(self):
3559 """Test replacing an entry without an entry path"""
3560 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003561 image_fname = tools.get_output_filename('image.bin')
Simon Glassa6cb9952019-07-20 12:24:15 -06003562 with self.assertRaises(ValueError) as e:
3563 control.ReplaceEntries(image_fname, 'fname', None, [])
3564 self.assertIn('Must specify an entry path to read with -f',
3565 str(e.exception))
3566
3567 def testReplaceTooManyEntryPaths(self):
3568 """Test extracting some entries"""
3569 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003570 image_fname = tools.get_output_filename('image.bin')
Simon Glassa6cb9952019-07-20 12:24:15 -06003571 with self.assertRaises(ValueError) as e:
3572 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3573 self.assertIn('Must specify exactly one entry path to write with -f',
3574 str(e.exception))
3575
Simon Glass2250ee62019-08-24 07:22:48 -06003576 def testPackReset16(self):
3577 """Test that an image with an x86 reset16 region can be created"""
3578 data = self._DoReadFile('144_x86_reset16.dts')
3579 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3580
3581 def testPackReset16Spl(self):
3582 """Test that an image with an x86 reset16-spl region can be created"""
3583 data = self._DoReadFile('145_x86_reset16_spl.dts')
3584 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3585
3586 def testPackReset16Tpl(self):
3587 """Test that an image with an x86 reset16-tpl region can be created"""
3588 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3589 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3590
Simon Glass5af12072019-08-24 07:22:50 -06003591 def testPackIntelFit(self):
3592 """Test that an image with an Intel FIT and pointer can be created"""
3593 data = self._DoReadFile('147_intel_fit.dts')
3594 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3595 fit = data[16:32];
3596 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3597 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3598
3599 image = control.images['image']
3600 entries = image.GetEntries()
3601 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3602 self.assertEqual(expected_ptr, ptr)
3603
3604 def testPackIntelFitMissing(self):
3605 """Test detection of a FIT pointer with not FIT region"""
3606 with self.assertRaises(ValueError) as e:
3607 self._DoReadFile('148_intel_fit_missing.dts')
3608 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3609 str(e.exception))
3610
Simon Glass7c150132019-11-06 17:22:44 -07003611 def _CheckSymbolsTplSection(self, dts, expected_vals):
3612 data = self._DoReadFile(dts)
3613 sym_values = struct.pack('<LQLL', *expected_vals)
Simon Glass2090f1e2019-08-24 07:23:00 -06003614 upto1 = 4 + len(U_BOOT_SPL_DATA)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003615 expected1 = tools.get_bytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[20:]
Simon Glass2090f1e2019-08-24 07:23:00 -06003616 self.assertEqual(expected1, data[:upto1])
3617
3618 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003619 expected2 = tools.get_bytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[20:]
Simon Glass2090f1e2019-08-24 07:23:00 -06003620 self.assertEqual(expected2, data[upto1:upto2])
3621
Simon Glasseb0086f2019-08-24 07:23:04 -06003622 upto3 = 0x34 + len(U_BOOT_DATA)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003623 expected3 = tools.get_bytes(0xff, 1) + U_BOOT_DATA
Simon Glass2090f1e2019-08-24 07:23:00 -06003624 self.assertEqual(expected3, data[upto2:upto3])
3625
Simon Glassb87064c2019-08-24 07:23:05 -06003626 expected4 = sym_values + U_BOOT_TPL_DATA[20:]
Simon Glass7c150132019-11-06 17:22:44 -07003627 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3628
3629 def testSymbolsTplSection(self):
3630 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3631 self._SetupSplElf('u_boot_binman_syms')
3632 self._SetupTplElf('u_boot_binman_syms')
3633 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
3634 [0x04, 0x1c, 0x10 + 0x34, 0x04])
3635
3636 def testSymbolsTplSectionX86(self):
3637 """Test binman can assign symbols in a section with end-at-4gb"""
3638 self._SetupSplElf('u_boot_binman_syms_x86')
3639 self._SetupTplElf('u_boot_binman_syms_x86')
3640 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
3641 [0xffffff04, 0xffffff1c, 0xffffff34,
3642 0x04])
Simon Glass2090f1e2019-08-24 07:23:00 -06003643
Simon Glassbf4d0e22019-08-24 07:23:03 -06003644 def testPackX86RomIfwiSectiom(self):
3645 """Test that a section can be placed in an IFWI region"""
3646 self._SetupIfwi('fitimage.bin')
3647 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3648 self._CheckIfwi(data)
3649
Simon Glassea0fff92019-08-24 07:23:07 -06003650 def testPackFspM(self):
3651 """Test that an image with a FSP memory-init binary can be created"""
3652 data = self._DoReadFile('152_intel_fsp_m.dts')
3653 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3654
Simon Glassbc6a88f2019-10-20 21:31:35 -06003655 def testPackFspS(self):
3656 """Test that an image with a FSP silicon-init binary can be created"""
3657 data = self._DoReadFile('153_intel_fsp_s.dts')
3658 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassea0fff92019-08-24 07:23:07 -06003659
Simon Glass998d1482019-10-20 21:31:36 -06003660 def testPackFspT(self):
3661 """Test that an image with a FSP temp-ram-init binary can be created"""
3662 data = self._DoReadFile('154_intel_fsp_t.dts')
3663 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3664
Simon Glass0dc706f2020-07-09 18:39:31 -06003665 def testMkimage(self):
3666 """Test using mkimage to build an image"""
3667 data = self._DoReadFile('156_mkimage.dts')
3668
3669 # Just check that the data appears in the file somewhere
3670 self.assertIn(U_BOOT_SPL_DATA, data)
3671
Simon Glass4f9ee832022-01-09 20:14:09 -07003672 def testMkimageMissing(self):
3673 """Test that binman still produces an image if mkimage is missing"""
3674 with test_util.capture_sys_output() as (_, stderr):
3675 self._DoTestFile('156_mkimage.dts',
3676 force_missing_bintools='mkimage')
3677 err = stderr.getvalue()
3678 self.assertRegex(err,
3679 "Image 'main-section'.*missing bintools.*: mkimage")
3680
Simon Glassce867ad2020-07-09 18:39:36 -06003681 def testExtblob(self):
3682 """Test an image with an external blob"""
3683 data = self._DoReadFile('157_blob_ext.dts')
3684 self.assertEqual(REFCODE_DATA, data)
3685
3686 def testExtblobMissing(self):
3687 """Test an image with a missing external blob"""
3688 with self.assertRaises(ValueError) as e:
3689 self._DoReadFile('158_blob_ext_missing.dts')
3690 self.assertIn("Filename 'missing-file' not found in input path",
3691 str(e.exception))
3692
Simon Glass4f9f1052020-07-09 18:39:38 -06003693 def testExtblobMissingOk(self):
3694 """Test an image with an missing external blob that is allowed"""
Simon Glassb1cca952020-07-09 18:39:40 -06003695 with test_util.capture_sys_output() as (stdout, stderr):
3696 self._DoTestFile('158_blob_ext_missing.dts', allow_missing=True)
3697 err = stderr.getvalue()
3698 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
3699
3700 def testExtblobMissingOkSect(self):
3701 """Test an image with an missing external blob that is allowed"""
3702 with test_util.capture_sys_output() as (stdout, stderr):
3703 self._DoTestFile('159_blob_ext_missing_sect.dts',
3704 allow_missing=True)
3705 err = stderr.getvalue()
3706 self.assertRegex(err, "Image 'main-section'.*missing.*: "
3707 "blob-ext blob-ext2")
Simon Glass4f9f1052020-07-09 18:39:38 -06003708
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003709 def testPackX86RomMeMissingDesc(self):
3710 """Test that an missing Intel descriptor entry is allowed"""
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003711 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass52b10dd2020-07-25 15:11:19 -06003712 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003713 err = stderr.getvalue()
3714 self.assertRegex(err,
3715 "Image 'main-section'.*missing.*: intel-descriptor")
3716
3717 def testPackX86RomMissingIfwi(self):
3718 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3719 self._SetupIfwi('fitimage.bin')
3720 pathname = os.path.join(self._indir, 'fitimage.bin')
3721 os.remove(pathname)
3722 with test_util.capture_sys_output() as (stdout, stderr):
3723 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3724 err = stderr.getvalue()
3725 self.assertRegex(err, "Image 'main-section'.*missing.*: intel-ifwi")
3726
Simon Glass8d2ef3e2022-02-11 13:23:21 -07003727 def testPackOverlapZero(self):
Simon Glassb3295fd2020-07-09 18:39:42 -06003728 """Test that zero-size overlapping regions are ignored"""
3729 self._DoTestFile('160_pack_overlap_zero.dts')
3730
Alper Nebi Yasak21353312022-02-08 01:08:04 +03003731 def _CheckSimpleFitData(self, fit_data, kernel_data, fdt1_data):
Simon Glassfdc34362020-07-09 18:39:45 -06003732 # The data should be inside the FIT
3733 dtb = fdt.Fdt.FromData(fit_data)
3734 dtb.Scan()
3735 fnode = dtb.GetNode('/images/kernel')
3736 self.assertIn('data', fnode.props)
3737
3738 fname = os.path.join(self._indir, 'fit_data.fit')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003739 tools.write_file(fname, fit_data)
3740 out = tools.run('dumpimage', '-l', fname)
Simon Glassfdc34362020-07-09 18:39:45 -06003741
3742 # Check a few features to make sure the plumbing works. We don't need
3743 # to test the operation of mkimage or dumpimage here. First convert the
3744 # output into a dict where the keys are the fields printed by dumpimage
3745 # and the values are a list of values for each field
3746 lines = out.splitlines()
3747
3748 # Converts "Compression: gzip compressed" into two groups:
3749 # 'Compression' and 'gzip compressed'
3750 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3751 vals = collections.defaultdict(list)
3752 for line in lines:
3753 mat = re_line.match(line)
3754 vals[mat.group(1)].append(mat.group(2))
3755
3756 self.assertEquals('FIT description: test-desc', lines[0])
3757 self.assertIn('Created:', lines[1])
3758 self.assertIn('Image 0 (kernel)', vals)
3759 self.assertIn('Hash value', vals)
3760 data_sizes = vals.get('Data Size')
3761 self.assertIsNotNone(data_sizes)
3762 self.assertEqual(2, len(data_sizes))
3763 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
Alper Nebi Yasak21353312022-02-08 01:08:04 +03003764 self.assertEqual(len(kernel_data), int(data_sizes[0].split()[0]))
3765 self.assertEqual(len(fdt1_data), int(data_sizes[1].split()[0]))
3766
Alper Nebi Yasake7368782022-03-27 18:31:47 +03003767 # Check if entry listing correctly omits /images/
3768 image = control.images['image']
3769 fit_entry = image.GetEntries()['fit']
3770 subentries = list(fit_entry.GetEntries().keys())
3771 expected = ['kernel', 'fdt-1']
3772 self.assertEqual(expected, subentries)
3773
Alper Nebi Yasak21353312022-02-08 01:08:04 +03003774 def testSimpleFit(self):
3775 """Test an image with a FIT inside"""
3776 data = self._DoReadFile('161_fit.dts')
3777 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3778 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3779 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3780
3781 self._CheckSimpleFitData(fit_data, U_BOOT_DATA, U_BOOT_SPL_DTB_DATA)
3782
3783 def testSimpleFitExpandsSubentries(self):
3784 """Test that FIT images expand their subentries"""
3785 data = self._DoReadFileDtb('161_fit.dts', use_expanded=True)[0]
3786 self.assertEqual(U_BOOT_EXP_DATA, data[:len(U_BOOT_EXP_DATA)])
3787 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3788 fit_data = data[len(U_BOOT_EXP_DATA):-len(U_BOOT_NODTB_DATA)]
3789
3790 self._CheckSimpleFitData(fit_data, U_BOOT_EXP_DATA, U_BOOT_SPL_DTB_DATA)
Simon Glassfdc34362020-07-09 18:39:45 -06003791
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003792 def testSimpleFitImagePos(self):
3793 """Test that we have correct image-pos for FIT subentries"""
3794 data, _, _, out_dtb_fname = self._DoReadFileDtb('161_fit.dts',
3795 update_dtb=True)
3796 dtb = fdt.Fdt(out_dtb_fname)
3797 dtb.Scan()
3798 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3799
Simon Glass38397d02022-03-05 20:19:01 -07003800 self.maxDiff = None
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003801 self.assertEqual({
3802 'image-pos': 0,
3803 'offset': 0,
3804 'size': 1890,
3805
3806 'u-boot:image-pos': 0,
3807 'u-boot:offset': 0,
3808 'u-boot:size': 4,
3809
3810 'fit:image-pos': 4,
3811 'fit:offset': 4,
3812 'fit:size': 1840,
3813
Simon Glass38397d02022-03-05 20:19:01 -07003814 'fit/images/kernel:image-pos': 304,
3815 'fit/images/kernel:offset': 300,
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003816 'fit/images/kernel:size': 4,
3817
Simon Glass38397d02022-03-05 20:19:01 -07003818 'fit/images/kernel/u-boot:image-pos': 304,
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003819 'fit/images/kernel/u-boot:offset': 0,
3820 'fit/images/kernel/u-boot:size': 4,
3821
Simon Glass38397d02022-03-05 20:19:01 -07003822 'fit/images/fdt-1:image-pos': 552,
3823 'fit/images/fdt-1:offset': 548,
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003824 'fit/images/fdt-1:size': 6,
3825
Simon Glass38397d02022-03-05 20:19:01 -07003826 'fit/images/fdt-1/u-boot-spl-dtb:image-pos': 552,
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003827 'fit/images/fdt-1/u-boot-spl-dtb:offset': 0,
3828 'fit/images/fdt-1/u-boot-spl-dtb:size': 6,
3829
3830 'u-boot-nodtb:image-pos': 1844,
3831 'u-boot-nodtb:offset': 1844,
3832 'u-boot-nodtb:size': 46,
3833 }, props)
3834
3835 # Actually check the data is where we think it is
3836 for node, expected in [
3837 ("u-boot", U_BOOT_DATA),
3838 ("fit/images/kernel", U_BOOT_DATA),
3839 ("fit/images/kernel/u-boot", U_BOOT_DATA),
3840 ("fit/images/fdt-1", U_BOOT_SPL_DTB_DATA),
3841 ("fit/images/fdt-1/u-boot-spl-dtb", U_BOOT_SPL_DTB_DATA),
3842 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
3843 ]:
3844 image_pos = props[f"{node}:image-pos"]
3845 size = props[f"{node}:size"]
3846 self.assertEqual(len(expected), size)
3847 self.assertEqual(expected, data[image_pos:image_pos+size])
3848
Simon Glassfdc34362020-07-09 18:39:45 -06003849 def testFitExternal(self):
Simon Glasse9d336d2020-09-01 05:13:55 -06003850 """Test an image with an FIT with external images"""
Simon Glassfdc34362020-07-09 18:39:45 -06003851 data = self._DoReadFile('162_fit_external.dts')
3852 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3853
Simon Glass8bc78b72022-01-09 20:13:39 -07003854 # Size of the external-data region as set up by mkimage
3855 external_data_size = len(U_BOOT_DATA) + 2
3856 expected_size = (len(U_BOOT_DATA) + 0x400 +
Simon Glassc1aa66e2022-01-29 14:14:04 -07003857 tools.align(external_data_size, 4) +
Simon Glass8bc78b72022-01-09 20:13:39 -07003858 len(U_BOOT_NODTB_DATA))
3859
Simon Glassfdc34362020-07-09 18:39:45 -06003860 # The data should be outside the FIT
3861 dtb = fdt.Fdt.FromData(fit_data)
3862 dtb.Scan()
3863 fnode = dtb.GetNode('/images/kernel')
3864 self.assertNotIn('data', fnode.props)
Simon Glass8bc78b72022-01-09 20:13:39 -07003865 self.assertEqual(len(U_BOOT_DATA),
3866 fdt_util.fdt32_to_cpu(fnode.props['data-size'].value))
3867 fit_pos = 0x400;
3868 self.assertEqual(
3869 fit_pos,
3870 fdt_util.fdt32_to_cpu(fnode.props['data-position'].value))
3871
3872 self.assertEquals(expected_size, len(data))
3873 actual_pos = len(U_BOOT_DATA) + fit_pos
3874 self.assertEqual(U_BOOT_DATA + b'aa',
3875 data[actual_pos:actual_pos + external_data_size])
Simon Glass12bb1a92019-07-20 12:23:51 -06003876
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003877 def testFitExternalImagePos(self):
3878 """Test that we have correct image-pos for external FIT subentries"""
3879 data, _, _, out_dtb_fname = self._DoReadFileDtb('162_fit_external.dts',
3880 update_dtb=True)
3881 dtb = fdt.Fdt(out_dtb_fname)
3882 dtb.Scan()
3883 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3884
3885 self.assertEqual({
3886 'image-pos': 0,
3887 'offset': 0,
3888 'size': 1082,
3889
3890 'u-boot:image-pos': 0,
3891 'u-boot:offset': 0,
3892 'u-boot:size': 4,
3893
3894 'fit:size': 1032,
3895 'fit:offset': 4,
3896 'fit:image-pos': 4,
3897
3898 'fit/images/kernel:size': 4,
3899 'fit/images/kernel:offset': 1024,
3900 'fit/images/kernel:image-pos': 1028,
3901
3902 'fit/images/kernel/u-boot:size': 4,
3903 'fit/images/kernel/u-boot:offset': 0,
3904 'fit/images/kernel/u-boot:image-pos': 1028,
3905
3906 'fit/images/fdt-1:size': 2,
3907 'fit/images/fdt-1:offset': 1028,
3908 'fit/images/fdt-1:image-pos': 1032,
3909
3910 'fit/images/fdt-1/_testing:size': 2,
3911 'fit/images/fdt-1/_testing:offset': 0,
3912 'fit/images/fdt-1/_testing:image-pos': 1032,
3913
3914 'u-boot-nodtb:image-pos': 1036,
3915 'u-boot-nodtb:offset': 1036,
3916 'u-boot-nodtb:size': 46,
3917 }, props)
3918
3919 # Actually check the data is where we think it is
3920 for node, expected in [
3921 ("u-boot", U_BOOT_DATA),
3922 ("fit/images/kernel", U_BOOT_DATA),
3923 ("fit/images/kernel/u-boot", U_BOOT_DATA),
3924 ("fit/images/fdt-1", b'aa'),
3925 ("fit/images/fdt-1/_testing", b'aa'),
3926 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
3927 ]:
3928 image_pos = props[f"{node}:image-pos"]
3929 size = props[f"{node}:size"]
3930 self.assertEqual(len(expected), size)
3931 self.assertEqual(expected, data[image_pos:image_pos+size])
3932
Simon Glass4f9ee832022-01-09 20:14:09 -07003933 def testFitMissing(self):
3934 """Test that binman still produces a FIT image if mkimage is missing"""
3935 with test_util.capture_sys_output() as (_, stderr):
3936 self._DoTestFile('162_fit_external.dts',
3937 force_missing_bintools='mkimage')
3938 err = stderr.getvalue()
3939 self.assertRegex(err,
3940 "Image 'main-section'.*missing bintools.*: mkimage")
3941
Alper Nebi Yasak8001d0b2020-08-31 12:58:18 +03003942 def testSectionIgnoreHashSignature(self):
3943 """Test that sections ignore hash, signature nodes for its data"""
3944 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
3945 expected = (U_BOOT_DATA + U_BOOT_DATA)
3946 self.assertEqual(expected, data)
3947
Alper Nebi Yasak3fdeb142020-08-31 12:58:19 +03003948 def testPadInSections(self):
3949 """Test pad-before, pad-after for entries in sections"""
Simon Glassf90d9062020-10-26 17:40:09 -06003950 data, _, _, out_dtb_fname = self._DoReadFileDtb(
3951 '166_pad_in_sections.dts', update_dtb=True)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003952 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
3953 U_BOOT_DATA + tools.get_bytes(ord('!'), 6) +
Alper Nebi Yasak3fdeb142020-08-31 12:58:19 +03003954 U_BOOT_DATA)
3955 self.assertEqual(expected, data)
3956
Simon Glassf90d9062020-10-26 17:40:09 -06003957 dtb = fdt.Fdt(out_dtb_fname)
3958 dtb.Scan()
3959 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
3960 expected = {
3961 'image-pos': 0,
3962 'offset': 0,
3963 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
3964
3965 'section:image-pos': 0,
3966 'section:offset': 0,
3967 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
3968
3969 'section/before:image-pos': 0,
3970 'section/before:offset': 0,
3971 'section/before:size': len(U_BOOT_DATA),
3972
3973 'section/u-boot:image-pos': 4,
3974 'section/u-boot:offset': 4,
3975 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
3976
3977 'section/after:image-pos': 26,
3978 'section/after:offset': 26,
3979 'section/after:size': len(U_BOOT_DATA),
3980 }
3981 self.assertEqual(expected, props)
3982
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03003983 def testFitImageSubentryAlignment(self):
3984 """Test relative alignability of FIT image subentries"""
Alper Nebi Yasakf3078d42022-02-08 01:08:07 +03003985 self._SetupSplElf()
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03003986 entry_args = {
3987 'test-id': TEXT_DATA,
3988 }
3989 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
3990 entry_args=entry_args)
3991 dtb = fdt.Fdt.FromData(data)
3992 dtb.Scan()
3993
3994 node = dtb.GetNode('/images/kernel')
3995 data = dtb.GetProps(node)["data"].bytes
3996 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003997 expected = (tools.get_bytes(0, 0x20) + U_BOOT_SPL_DATA +
3998 tools.get_bytes(0, align_pad) + U_BOOT_DATA)
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03003999 self.assertEqual(expected, data)
4000
4001 node = dtb.GetNode('/images/fdt-1')
4002 data = dtb.GetProps(node)["data"].bytes
Simon Glassc1aa66e2022-01-29 14:14:04 -07004003 expected = (U_BOOT_SPL_DTB_DATA + tools.get_bytes(0, 20) +
4004 tools.to_bytes(TEXT_DATA) + tools.get_bytes(0, 30) +
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03004005 U_BOOT_DTB_DATA)
4006 self.assertEqual(expected, data)
4007
4008 def testFitExtblobMissingOk(self):
4009 """Test a FIT with a missing external blob that is allowed"""
4010 with test_util.capture_sys_output() as (stdout, stderr):
4011 self._DoTestFile('168_fit_missing_blob.dts',
4012 allow_missing=True)
4013 err = stderr.getvalue()
Simon Glassb2381432020-09-06 10:39:09 -06004014 self.assertRegex(err, "Image 'main-section'.*missing.*: atf-bl31")
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03004015
Simon Glass3decfa32020-09-01 05:13:54 -06004016 def testBlobNamedByArgMissing(self):
4017 """Test handling of a missing entry arg"""
4018 with self.assertRaises(ValueError) as e:
4019 self._DoReadFile('068_blob_named_by_arg.dts')
4020 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
4021 str(e.exception))
4022
Simon Glassdc2f81a2020-09-01 05:13:58 -06004023 def testPackBl31(self):
4024 """Test that an image with an ATF BL31 binary can be created"""
4025 data = self._DoReadFile('169_atf_bl31.dts')
4026 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
4027
Samuel Holland18bd4552020-10-21 21:12:15 -05004028 def testPackScp(self):
4029 """Test that an image with an SCP binary can be created"""
4030 data = self._DoReadFile('172_scp.dts')
4031 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
4032
Simon Glass6cf99532020-09-01 05:13:59 -06004033 def testFitFdt(self):
4034 """Test an image with an FIT with multiple FDT images"""
4035 def _CheckFdt(seq, expected_data):
4036 """Check the FDT nodes
4037
4038 Args:
4039 seq: Sequence number to check (0 or 1)
4040 expected_data: Expected contents of 'data' property
4041 """
4042 name = 'fdt-%d' % seq
4043 fnode = dtb.GetNode('/images/%s' % name)
4044 self.assertIsNotNone(fnode)
4045 self.assertEqual({'description','type', 'compression', 'data'},
4046 set(fnode.props.keys()))
4047 self.assertEqual(expected_data, fnode.props['data'].bytes)
4048 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
4049 fnode.props['description'].value)
Jan Kiszkab2106612022-02-28 17:06:20 +01004050 self.assertEqual(fnode.subnodes[0].name, 'hash')
Simon Glass6cf99532020-09-01 05:13:59 -06004051
4052 def _CheckConfig(seq, expected_data):
4053 """Check the configuration nodes
4054
4055 Args:
4056 seq: Sequence number to check (0 or 1)
4057 expected_data: Expected contents of 'data' property
4058 """
4059 cnode = dtb.GetNode('/configurations')
4060 self.assertIn('default', cnode.props)
Simon Glassc0f1ebe2020-09-06 10:39:08 -06004061 self.assertEqual('config-2', cnode.props['default'].value)
Simon Glass6cf99532020-09-01 05:13:59 -06004062
4063 name = 'config-%d' % seq
4064 fnode = dtb.GetNode('/configurations/%s' % name)
4065 self.assertIsNotNone(fnode)
4066 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
4067 set(fnode.props.keys()))
4068 self.assertEqual('conf-test-fdt%d.dtb' % seq,
4069 fnode.props['description'].value)
4070 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
4071
4072 entry_args = {
4073 'of-list': 'test-fdt1 test-fdt2',
Simon Glassc0f1ebe2020-09-06 10:39:08 -06004074 'default-dt': 'test-fdt2',
Simon Glass6cf99532020-09-01 05:13:59 -06004075 }
4076 data = self._DoReadFileDtb(
Bin Mengaa75ce92021-05-10 20:23:32 +08004077 '170_fit_fdt.dts',
Simon Glass6cf99532020-09-01 05:13:59 -06004078 entry_args=entry_args,
4079 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4080 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4081 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4082
4083 dtb = fdt.Fdt.FromData(fit_data)
4084 dtb.Scan()
4085 fnode = dtb.GetNode('/images/kernel')
4086 self.assertIn('data', fnode.props)
4087
4088 # Check all the properties in fdt-1 and fdt-2
4089 _CheckFdt(1, TEST_FDT1_DATA)
4090 _CheckFdt(2, TEST_FDT2_DATA)
4091
4092 # Check configurations
4093 _CheckConfig(1, TEST_FDT1_DATA)
4094 _CheckConfig(2, TEST_FDT2_DATA)
4095
4096 def testFitFdtMissingList(self):
4097 """Test handling of a missing 'of-list' entry arg"""
4098 with self.assertRaises(ValueError) as e:
Bin Mengaa75ce92021-05-10 20:23:32 +08004099 self._DoReadFile('170_fit_fdt.dts')
Simon Glass6cf99532020-09-01 05:13:59 -06004100 self.assertIn("Generator node requires 'of-list' entry argument",
4101 str(e.exception))
4102
4103 def testFitFdtEmptyList(self):
4104 """Test handling of an empty 'of-list' entry arg"""
4105 entry_args = {
4106 'of-list': '',
4107 }
4108 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
4109
4110 def testFitFdtMissingProp(self):
4111 """Test handling of a missing 'fit,fdt-list' property"""
4112 with self.assertRaises(ValueError) as e:
4113 self._DoReadFile('171_fit_fdt_missing_prop.dts')
4114 self.assertIn("Generator node requires 'fit,fdt-list' property",
4115 str(e.exception))
Simon Glassdc2f81a2020-09-01 05:13:58 -06004116
Simon Glassc0f1ebe2020-09-06 10:39:08 -06004117 def testFitFdtMissing(self):
4118 """Test handling of a missing 'default-dt' entry arg"""
4119 entry_args = {
4120 'of-list': 'test-fdt1 test-fdt2',
4121 }
4122 with self.assertRaises(ValueError) as e:
4123 self._DoReadFileDtb(
Bin Mengaa75ce92021-05-10 20:23:32 +08004124 '170_fit_fdt.dts',
Simon Glassc0f1ebe2020-09-06 10:39:08 -06004125 entry_args=entry_args,
4126 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4127 self.assertIn("Generated 'default' node requires default-dt entry argument",
4128 str(e.exception))
4129
4130 def testFitFdtNotInList(self):
4131 """Test handling of a default-dt that is not in the of-list"""
4132 entry_args = {
4133 'of-list': 'test-fdt1 test-fdt2',
4134 'default-dt': 'test-fdt3',
4135 }
4136 with self.assertRaises(ValueError) as e:
4137 self._DoReadFileDtb(
Bin Mengaa75ce92021-05-10 20:23:32 +08004138 '170_fit_fdt.dts',
Simon Glassc0f1ebe2020-09-06 10:39:08 -06004139 entry_args=entry_args,
4140 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4141 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
4142 str(e.exception))
4143
Simon Glassb2381432020-09-06 10:39:09 -06004144 def testFitExtblobMissingHelp(self):
4145 """Test display of help messages when an external blob is missing"""
4146 control.missing_blob_help = control._ReadMissingBlobHelp()
4147 control.missing_blob_help['wibble'] = 'Wibble test'
4148 control.missing_blob_help['another'] = 'Another test'
4149 with test_util.capture_sys_output() as (stdout, stderr):
4150 self._DoTestFile('168_fit_missing_blob.dts',
4151 allow_missing=True)
4152 err = stderr.getvalue()
4153
4154 # We can get the tag from the name, the type or the missing-msg
4155 # property. Check all three.
4156 self.assertIn('You may need to build ARM Trusted', err)
4157 self.assertIn('Wibble test', err)
4158 self.assertIn('Another test', err)
4159
Simon Glass204aa782020-09-06 10:35:32 -06004160 def testMissingBlob(self):
4161 """Test handling of a blob containing a missing file"""
4162 with self.assertRaises(ValueError) as e:
4163 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
4164 self.assertIn("Filename 'missing' not found in input path",
4165 str(e.exception))
4166
Simon Glassfb91d562020-09-06 10:35:33 -06004167 def testEnvironment(self):
4168 """Test adding a U-Boot environment"""
4169 data = self._DoReadFile('174_env.dts')
4170 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
4171 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4172 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4173 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
4174 env)
4175
4176 def testEnvironmentNoSize(self):
4177 """Test that a missing 'size' property is detected"""
4178 with self.assertRaises(ValueError) as e:
Simon Glassa4dfe3e2020-10-26 17:40:00 -06004179 self._DoTestFile('175_env_no_size.dts')
Simon Glassfb91d562020-09-06 10:35:33 -06004180 self.assertIn("'u-boot-env' entry must have a size property",
4181 str(e.exception))
4182
4183 def testEnvironmentTooSmall(self):
4184 """Test handling of an environment that does not fit"""
4185 with self.assertRaises(ValueError) as e:
Simon Glassa4dfe3e2020-10-26 17:40:00 -06004186 self._DoTestFile('176_env_too_small.dts')
Simon Glassfb91d562020-09-06 10:35:33 -06004187
4188 # checksum, start byte, environment with \0 terminator, final \0
4189 need = 4 + 1 + len(ENV_DATA) + 1 + 1
4190 short = need - 0x8
4191 self.assertIn("too small to hold data (need %#x more bytes)" % short,
4192 str(e.exception))
4193
Simon Glassf2c0dd82020-10-26 17:40:01 -06004194 def testSkipAtStart(self):
4195 """Test handling of skip-at-start section"""
4196 data = self._DoReadFile('177_skip_at_start.dts')
4197 self.assertEqual(U_BOOT_DATA, data)
4198
4199 image = control.images['image']
4200 entries = image.GetEntries()
4201 section = entries['section']
4202 self.assertEqual(0, section.offset)
4203 self.assertEqual(len(U_BOOT_DATA), section.size)
4204 self.assertEqual(U_BOOT_DATA, section.GetData())
4205
4206 entry = section.GetEntries()['u-boot']
4207 self.assertEqual(16, entry.offset)
4208 self.assertEqual(len(U_BOOT_DATA), entry.size)
4209 self.assertEqual(U_BOOT_DATA, entry.data)
4210
4211 def testSkipAtStartPad(self):
4212 """Test handling of skip-at-start section with padded entry"""
4213 data = self._DoReadFile('178_skip_at_start_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004214 before = tools.get_bytes(0, 8)
4215 after = tools.get_bytes(0, 4)
Simon Glassf2c0dd82020-10-26 17:40:01 -06004216 all = before + U_BOOT_DATA + after
4217 self.assertEqual(all, data)
4218
4219 image = control.images['image']
4220 entries = image.GetEntries()
4221 section = entries['section']
4222 self.assertEqual(0, section.offset)
4223 self.assertEqual(len(all), section.size)
4224 self.assertEqual(all, section.GetData())
4225
4226 entry = section.GetEntries()['u-boot']
4227 self.assertEqual(16, entry.offset)
4228 self.assertEqual(len(all), entry.size)
4229 self.assertEqual(U_BOOT_DATA, entry.data)
4230
4231 def testSkipAtStartSectionPad(self):
4232 """Test handling of skip-at-start section with padding"""
4233 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004234 before = tools.get_bytes(0, 8)
4235 after = tools.get_bytes(0, 4)
Simon Glassf2c0dd82020-10-26 17:40:01 -06004236 all = before + U_BOOT_DATA + after
Simon Glassd1d3ad72020-10-26 17:40:13 -06004237 self.assertEqual(all, data)
Simon Glassf2c0dd82020-10-26 17:40:01 -06004238
4239 image = control.images['image']
4240 entries = image.GetEntries()
4241 section = entries['section']
4242 self.assertEqual(0, section.offset)
4243 self.assertEqual(len(all), section.size)
Simon Glass63e7ba62020-10-26 17:40:16 -06004244 self.assertEqual(U_BOOT_DATA, section.data)
Simon Glassd1d3ad72020-10-26 17:40:13 -06004245 self.assertEqual(all, section.GetPaddedData())
Simon Glassf2c0dd82020-10-26 17:40:01 -06004246
4247 entry = section.GetEntries()['u-boot']
4248 self.assertEqual(16, entry.offset)
4249 self.assertEqual(len(U_BOOT_DATA), entry.size)
4250 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassfb91d562020-09-06 10:35:33 -06004251
Simon Glass7d398bb2020-10-26 17:40:14 -06004252 def testSectionPad(self):
4253 """Testing padding with sections"""
4254 data = self._DoReadFile('180_section_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004255 expected = (tools.get_bytes(ord('&'), 3) +
4256 tools.get_bytes(ord('!'), 5) +
Simon Glass7d398bb2020-10-26 17:40:14 -06004257 U_BOOT_DATA +
Simon Glassc1aa66e2022-01-29 14:14:04 -07004258 tools.get_bytes(ord('!'), 1) +
4259 tools.get_bytes(ord('&'), 2))
Simon Glass7d398bb2020-10-26 17:40:14 -06004260 self.assertEqual(expected, data)
4261
4262 def testSectionAlign(self):
4263 """Testing alignment with sections"""
4264 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4265 expected = (b'\0' + # fill section
Simon Glassc1aa66e2022-01-29 14:14:04 -07004266 tools.get_bytes(ord('&'), 1) + # padding to section align
Simon Glass7d398bb2020-10-26 17:40:14 -06004267 b'\0' + # fill section
Simon Glassc1aa66e2022-01-29 14:14:04 -07004268 tools.get_bytes(ord('!'), 3) + # padding to u-boot align
Simon Glass7d398bb2020-10-26 17:40:14 -06004269 U_BOOT_DATA +
Simon Glassc1aa66e2022-01-29 14:14:04 -07004270 tools.get_bytes(ord('!'), 4) + # padding to u-boot size
4271 tools.get_bytes(ord('!'), 4)) # padding to section size
Simon Glass7d398bb2020-10-26 17:40:14 -06004272 self.assertEqual(expected, data)
4273
Simon Glass8f5ef892020-10-26 17:40:25 -06004274 def testCompressImage(self):
4275 """Test compression of the entire image"""
4276 self._CheckLz4()
4277 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4278 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4279 dtb = fdt.Fdt(out_dtb_fname)
4280 dtb.Scan()
4281 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4282 'uncomp-size'])
4283 orig = self._decompress(data)
4284 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4285
4286 # Do a sanity check on various fields
4287 image = control.images['image']
4288 entries = image.GetEntries()
4289 self.assertEqual(2, len(entries))
4290
4291 entry = entries['blob']
4292 self.assertEqual(COMPRESS_DATA, entry.data)
4293 self.assertEqual(len(COMPRESS_DATA), entry.size)
4294
4295 entry = entries['u-boot']
4296 self.assertEqual(U_BOOT_DATA, entry.data)
4297 self.assertEqual(len(U_BOOT_DATA), entry.size)
4298
4299 self.assertEqual(len(data), image.size)
4300 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4301 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4302 orig = self._decompress(image.data)
4303 self.assertEqual(orig, image.uncomp_data)
4304
4305 expected = {
4306 'blob:offset': 0,
4307 'blob:size': len(COMPRESS_DATA),
4308 'u-boot:offset': len(COMPRESS_DATA),
4309 'u-boot:size': len(U_BOOT_DATA),
4310 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4311 'offset': 0,
4312 'image-pos': 0,
4313 'size': len(data),
4314 }
4315 self.assertEqual(expected, props)
4316
4317 def testCompressImageLess(self):
4318 """Test compression where compression reduces the image size"""
4319 self._CheckLz4()
4320 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4321 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4322 dtb = fdt.Fdt(out_dtb_fname)
4323 dtb.Scan()
4324 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4325 'uncomp-size'])
4326 orig = self._decompress(data)
4327
4328 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
4329
4330 # Do a sanity check on various fields
4331 image = control.images['image']
4332 entries = image.GetEntries()
4333 self.assertEqual(2, len(entries))
4334
4335 entry = entries['blob']
4336 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4337 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4338
4339 entry = entries['u-boot']
4340 self.assertEqual(U_BOOT_DATA, entry.data)
4341 self.assertEqual(len(U_BOOT_DATA), entry.size)
4342
4343 self.assertEqual(len(data), image.size)
4344 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4345 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4346 image.uncomp_size)
4347 orig = self._decompress(image.data)
4348 self.assertEqual(orig, image.uncomp_data)
4349
4350 expected = {
4351 'blob:offset': 0,
4352 'blob:size': len(COMPRESS_DATA_BIG),
4353 'u-boot:offset': len(COMPRESS_DATA_BIG),
4354 'u-boot:size': len(U_BOOT_DATA),
4355 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4356 'offset': 0,
4357 'image-pos': 0,
4358 'size': len(data),
4359 }
4360 self.assertEqual(expected, props)
4361
4362 def testCompressSectionSize(self):
4363 """Test compression of a section with a fixed size"""
4364 self._CheckLz4()
4365 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4366 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4367 dtb = fdt.Fdt(out_dtb_fname)
4368 dtb.Scan()
4369 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4370 'uncomp-size'])
4371 orig = self._decompress(data)
4372 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4373 expected = {
4374 'section/blob:offset': 0,
4375 'section/blob:size': len(COMPRESS_DATA),
4376 'section/u-boot:offset': len(COMPRESS_DATA),
4377 'section/u-boot:size': len(U_BOOT_DATA),
4378 'section:offset': 0,
4379 'section:image-pos': 0,
4380 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4381 'section:size': 0x30,
4382 'offset': 0,
4383 'image-pos': 0,
4384 'size': 0x30,
4385 }
4386 self.assertEqual(expected, props)
4387
4388 def testCompressSection(self):
4389 """Test compression of a section with no fixed size"""
4390 self._CheckLz4()
4391 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4392 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4393 dtb = fdt.Fdt(out_dtb_fname)
4394 dtb.Scan()
4395 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4396 'uncomp-size'])
4397 orig = self._decompress(data)
4398 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4399 expected = {
4400 'section/blob:offset': 0,
4401 'section/blob:size': len(COMPRESS_DATA),
4402 'section/u-boot:offset': len(COMPRESS_DATA),
4403 'section/u-boot:size': len(U_BOOT_DATA),
4404 'section:offset': 0,
4405 'section:image-pos': 0,
4406 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4407 'section:size': len(data),
4408 'offset': 0,
4409 'image-pos': 0,
4410 'size': len(data),
4411 }
4412 self.assertEqual(expected, props)
4413
4414 def testCompressExtra(self):
4415 """Test compression of a section with no fixed size"""
4416 self._CheckLz4()
4417 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4418 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4419 dtb = fdt.Fdt(out_dtb_fname)
4420 dtb.Scan()
4421 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4422 'uncomp-size'])
4423
4424 base = data[len(U_BOOT_DATA):]
4425 self.assertEquals(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
4426 rest = base[len(U_BOOT_DATA):]
4427
4428 # Check compressed data
4429 section1 = self._decompress(rest)
Simon Glass0d1e95a2022-01-09 20:14:04 -07004430 expect1 = comp_util.compress(COMPRESS_DATA + U_BOOT_DATA, 'lz4')
Simon Glass8f5ef892020-10-26 17:40:25 -06004431 self.assertEquals(expect1, rest[:len(expect1)])
4432 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, section1)
4433 rest1 = rest[len(expect1):]
4434
4435 section2 = self._decompress(rest1)
Simon Glass0d1e95a2022-01-09 20:14:04 -07004436 expect2 = comp_util.compress(COMPRESS_DATA + COMPRESS_DATA, 'lz4')
Simon Glass8f5ef892020-10-26 17:40:25 -06004437 self.assertEquals(expect2, rest1[:len(expect2)])
4438 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA, section2)
4439 rest2 = rest1[len(expect2):]
4440
4441 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4442 len(expect2) + len(U_BOOT_DATA))
4443 #self.assertEquals(expect_size, len(data))
4444
4445 #self.assertEquals(U_BOOT_DATA, rest2)
4446
4447 self.maxDiff = None
4448 expected = {
4449 'u-boot:offset': 0,
4450 'u-boot:image-pos': 0,
4451 'u-boot:size': len(U_BOOT_DATA),
4452
4453 'base:offset': len(U_BOOT_DATA),
4454 'base:image-pos': len(U_BOOT_DATA),
4455 'base:size': len(data) - len(U_BOOT_DATA),
4456 'base/u-boot:offset': 0,
4457 'base/u-boot:image-pos': len(U_BOOT_DATA),
4458 'base/u-boot:size': len(U_BOOT_DATA),
4459 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4460 len(expect2),
4461 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4462 len(expect2),
4463 'base/u-boot2:size': len(U_BOOT_DATA),
4464
4465 'base/section:offset': len(U_BOOT_DATA),
4466 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4467 'base/section:size': len(expect1),
4468 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4469 'base/section/blob:offset': 0,
4470 'base/section/blob:size': len(COMPRESS_DATA),
4471 'base/section/u-boot:offset': len(COMPRESS_DATA),
4472 'base/section/u-boot:size': len(U_BOOT_DATA),
4473
4474 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4475 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4476 'base/section2:size': len(expect2),
4477 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4478 'base/section2/blob:offset': 0,
4479 'base/section2/blob:size': len(COMPRESS_DATA),
4480 'base/section2/blob2:offset': len(COMPRESS_DATA),
4481 'base/section2/blob2:size': len(COMPRESS_DATA),
4482
4483 'offset': 0,
4484 'image-pos': 0,
4485 'size': len(data),
4486 }
4487 self.assertEqual(expected, props)
4488
Simon Glass870a9ea2021-01-06 21:35:15 -07004489 def testSymbolsSubsection(self):
4490 """Test binman can assign symbols from a subsection"""
Simon Glassf5898822021-03-18 20:24:56 +13004491 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x18)
Simon Glass870a9ea2021-01-06 21:35:15 -07004492
Simon Glass939d1062021-01-06 21:35:16 -07004493 def testReadImageEntryArg(self):
4494 """Test reading an image that would need an entry arg to generate"""
4495 entry_args = {
4496 'cros-ec-rw-path': 'ecrw.bin',
4497 }
4498 data = self.data = self._DoReadFileDtb(
4499 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4500 entry_args=entry_args)
4501
Simon Glassc1aa66e2022-01-29 14:14:04 -07004502 image_fname = tools.get_output_filename('image.bin')
Simon Glass939d1062021-01-06 21:35:16 -07004503 orig_image = control.images['image']
4504
4505 # This should not generate an error about the missing 'cros-ec-rw-path'
4506 # since we are reading the image from a file. Compare with
4507 # testEntryArgsRequired()
4508 image = Image.FromFile(image_fname)
4509 self.assertEqual(orig_image.GetEntries().keys(),
4510 image.GetEntries().keys())
4511
Simon Glass6eb99322021-01-06 21:35:18 -07004512 def testFilesAlign(self):
4513 """Test alignment with files"""
4514 data = self._DoReadFile('190_files_align.dts')
4515
4516 # The first string is 15 bytes so will align to 16
4517 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4518 self.assertEqual(expect, data)
4519
Simon Glass5c6ba712021-01-06 21:35:19 -07004520 def testReadImageSkip(self):
4521 """Test reading an image and accessing its FDT map"""
4522 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004523 image_fname = tools.get_output_filename('image.bin')
Simon Glass5c6ba712021-01-06 21:35:19 -07004524 orig_image = control.images['image']
4525 image = Image.FromFile(image_fname)
4526 self.assertEqual(orig_image.GetEntries().keys(),
4527 image.GetEntries().keys())
4528
4529 orig_entry = orig_image.GetEntries()['fdtmap']
4530 entry = image.GetEntries()['fdtmap']
4531 self.assertEqual(orig_entry.offset, entry.offset)
4532 self.assertEqual(orig_entry.size, entry.size)
4533 self.assertEqual(16, entry.image_pos)
4534
4535 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4536
4537 self.assertEquals(U_BOOT_DATA, u_boot.ReadData())
4538
Simon Glass77a64e02021-03-18 20:24:57 +13004539 def testTplNoDtb(self):
4540 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
Simon Glass0fe44dc2021-04-25 08:39:32 +12004541 self._SetupTplElf()
Simon Glass77a64e02021-03-18 20:24:57 +13004542 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4543 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4544 data[:len(U_BOOT_TPL_NODTB_DATA)])
4545
Simon Glassd26efc82021-03-18 20:24:58 +13004546 def testTplBssPad(self):
4547 """Test that we can pad TPL's BSS with zeros"""
4548 # ELF file with a '__bss_size' symbol
4549 self._SetupTplElf()
4550 data = self._DoReadFile('193_tpl_bss_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004551 self.assertEqual(U_BOOT_TPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glassd26efc82021-03-18 20:24:58 +13004552 data)
4553
4554 def testTplBssPadMissing(self):
4555 """Test that a missing symbol is detected"""
4556 self._SetupTplElf('u_boot_ucode_ptr')
4557 with self.assertRaises(ValueError) as e:
4558 self._DoReadFile('193_tpl_bss_pad.dts')
4559 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4560 str(e.exception))
4561
Simon Glass06684922021-03-18 20:25:07 +13004562 def checkDtbSizes(self, data, pad_len, start):
4563 """Check the size arguments in a dtb embedded in an image
4564
4565 Args:
4566 data: The image data
4567 pad_len: Length of the pad section in the image, in bytes
4568 start: Start offset of the devicetree to examine, within the image
4569
4570 Returns:
4571 Size of the devicetree in bytes
4572 """
4573 dtb_data = data[start:]
4574 dtb = fdt.Fdt.FromData(dtb_data)
4575 fdt_size = dtb.GetFdtObj().totalsize()
4576 dtb.Scan()
4577 props = self._GetPropTree(dtb, 'size')
4578 self.assertEqual({
4579 'size': len(data),
4580 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4581 'u-boot-spl/u-boot-spl-dtb:size': 801,
4582 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4583 'u-boot-spl:size': 860,
4584 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4585 'u-boot/u-boot-dtb:size': 781,
4586 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4587 'u-boot:size': 827,
4588 }, props)
4589 return fdt_size
4590
4591 def testExpanded(self):
4592 """Test that an expanded entry type is selected when needed"""
4593 self._SetupSplElf()
4594 self._SetupTplElf()
4595
4596 # SPL has a devicetree, TPL does not
4597 entry_args = {
4598 'spl-dtb': '1',
4599 'spl-bss-pad': 'y',
4600 'tpl-dtb': '',
4601 }
4602 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4603 entry_args=entry_args)
4604 image = control.images['image']
4605 entries = image.GetEntries()
4606 self.assertEqual(3, len(entries))
4607
4608 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4609 self.assertIn('u-boot', entries)
4610 entry = entries['u-boot']
4611 self.assertEqual('u-boot-expanded', entry.etype)
4612 subent = entry.GetEntries()
4613 self.assertEqual(2, len(subent))
4614 self.assertIn('u-boot-nodtb', subent)
4615 self.assertIn('u-boot-dtb', subent)
4616
4617 # Second, u-boot-spl, which should be expanded into three parts
4618 self.assertIn('u-boot-spl', entries)
4619 entry = entries['u-boot-spl']
4620 self.assertEqual('u-boot-spl-expanded', entry.etype)
4621 subent = entry.GetEntries()
4622 self.assertEqual(3, len(subent))
4623 self.assertIn('u-boot-spl-nodtb', subent)
4624 self.assertIn('u-boot-spl-bss-pad', subent)
4625 self.assertIn('u-boot-spl-dtb', subent)
4626
4627 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4628 # devicetree
4629 self.assertIn('u-boot-tpl', entries)
4630 entry = entries['u-boot-tpl']
4631 self.assertEqual('u-boot-tpl', entry.etype)
4632 self.assertEqual(None, entry.GetEntries())
4633
4634 def testExpandedTpl(self):
4635 """Test that an expanded entry type is selected for TPL when needed"""
4636 self._SetupTplElf()
4637
4638 entry_args = {
4639 'tpl-bss-pad': 'y',
4640 'tpl-dtb': 'y',
4641 }
4642 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4643 entry_args=entry_args)
4644 image = control.images['image']
4645 entries = image.GetEntries()
4646 self.assertEqual(1, len(entries))
4647
4648 # We only have u-boot-tpl, which be expanded
4649 self.assertIn('u-boot-tpl', entries)
4650 entry = entries['u-boot-tpl']
4651 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4652 subent = entry.GetEntries()
4653 self.assertEqual(3, len(subent))
4654 self.assertIn('u-boot-tpl-nodtb', subent)
4655 self.assertIn('u-boot-tpl-bss-pad', subent)
4656 self.assertIn('u-boot-tpl-dtb', subent)
4657
4658 def testExpandedNoPad(self):
4659 """Test an expanded entry without BSS pad enabled"""
4660 self._SetupSplElf()
4661 self._SetupTplElf()
4662
4663 # SPL has a devicetree, TPL does not
4664 entry_args = {
4665 'spl-dtb': 'something',
4666 'spl-bss-pad': 'n',
4667 'tpl-dtb': '',
4668 }
4669 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4670 entry_args=entry_args)
4671 image = control.images['image']
4672 entries = image.GetEntries()
4673
4674 # Just check u-boot-spl, which should be expanded into two parts
4675 self.assertIn('u-boot-spl', entries)
4676 entry = entries['u-boot-spl']
4677 self.assertEqual('u-boot-spl-expanded', entry.etype)
4678 subent = entry.GetEntries()
4679 self.assertEqual(2, len(subent))
4680 self.assertIn('u-boot-spl-nodtb', subent)
4681 self.assertIn('u-boot-spl-dtb', subent)
4682
4683 def testExpandedTplNoPad(self):
4684 """Test that an expanded entry type with padding disabled in TPL"""
4685 self._SetupTplElf()
4686
4687 entry_args = {
4688 'tpl-bss-pad': '',
4689 'tpl-dtb': 'y',
4690 }
4691 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4692 entry_args=entry_args)
4693 image = control.images['image']
4694 entries = image.GetEntries()
4695 self.assertEqual(1, len(entries))
4696
4697 # We only have u-boot-tpl, which be expanded
4698 self.assertIn('u-boot-tpl', entries)
4699 entry = entries['u-boot-tpl']
4700 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4701 subent = entry.GetEntries()
4702 self.assertEqual(2, len(subent))
4703 self.assertIn('u-boot-tpl-nodtb', subent)
4704 self.assertIn('u-boot-tpl-dtb', subent)
4705
4706 def testFdtInclude(self):
4707 """Test that an Fdt is update within all binaries"""
4708 self._SetupSplElf()
4709 self._SetupTplElf()
4710
4711 # SPL has a devicetree, TPL does not
4712 self.maxDiff = None
4713 entry_args = {
4714 'spl-dtb': '1',
4715 'spl-bss-pad': 'y',
4716 'tpl-dtb': '',
4717 }
4718 # Build the image. It includes two separate devicetree binaries, each
4719 # with their own contents, but all contain the binman definition.
4720 data = self._DoReadFileDtb(
4721 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4722 update_dtb=True, entry_args=entry_args)[0]
4723 pad_len = 10
4724
4725 # Check the U-Boot dtb
4726 start = len(U_BOOT_NODTB_DATA)
4727 fdt_size = self.checkDtbSizes(data, pad_len, start)
4728
4729 # Now check SPL
4730 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4731 fdt_size = self.checkDtbSizes(data, pad_len, start)
4732
4733 # TPL has no devicetree
4734 start += fdt_size + len(U_BOOT_TPL_DATA)
4735 self.assertEqual(len(data), start)
Simon Glass7d398bb2020-10-26 17:40:14 -06004736
Simon Glass3d433382021-03-21 18:24:30 +13004737 def testSymbolsExpanded(self):
4738 """Test binman can assign symbols in expanded entries"""
4739 entry_args = {
4740 'spl-dtb': '1',
4741 }
4742 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4743 U_BOOT_SPL_DTB_DATA, 0x38,
4744 entry_args=entry_args, use_expanded=True)
4745
Simon Glass189f2912021-03-21 18:24:31 +13004746 def testCollection(self):
4747 """Test a collection"""
4748 data = self._DoReadFile('198_collection.dts')
4749 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
Simon Glassc1aa66e2022-01-29 14:14:04 -07004750 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
4751 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
Simon Glass189f2912021-03-21 18:24:31 +13004752 data)
4753
Simon Glass631f7522021-03-21 18:24:32 +13004754 def testCollectionSection(self):
4755 """Test a collection where a section must be built first"""
4756 # Sections never have their contents when GetData() is called, but when
Simon Glassd34bcdd2021-11-23 11:03:47 -07004757 # BuildSectionData() is called with required=True, a section will force
Simon Glass631f7522021-03-21 18:24:32 +13004758 # building the contents, producing an error is anything is still
4759 # missing.
4760 data = self._DoReadFile('199_collection_section.dts')
4761 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
Simon Glassc1aa66e2022-01-29 14:14:04 -07004762 self.assertEqual(section + U_BOOT_DATA + tools.get_bytes(0xff, 2) +
4763 section + tools.get_bytes(0xfe, 3) + U_BOOT_DATA,
Simon Glass631f7522021-03-21 18:24:32 +13004764 data)
4765
Simon Glass5ff9fed2021-03-21 18:24:33 +13004766 def testAlignDefault(self):
4767 """Test that default alignment works on sections"""
4768 data = self._DoReadFile('200_align_default.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004769 expected = (U_BOOT_DATA + tools.get_bytes(0, 8 - len(U_BOOT_DATA)) +
Simon Glass5ff9fed2021-03-21 18:24:33 +13004770 U_BOOT_DATA)
4771 # Special alignment for section
Simon Glassc1aa66e2022-01-29 14:14:04 -07004772 expected += tools.get_bytes(0, 32 - len(expected))
Simon Glass5ff9fed2021-03-21 18:24:33 +13004773 # No alignment within the nested section
4774 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
4775 # Now the final piece, which should be default-aligned
Simon Glassc1aa66e2022-01-29 14:14:04 -07004776 expected += tools.get_bytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
Simon Glass5ff9fed2021-03-21 18:24:33 +13004777 self.assertEqual(expected, data)
Simon Glass631f7522021-03-21 18:24:32 +13004778
Bin Meng4c4d6072021-05-10 20:23:33 +08004779 def testPackOpenSBI(self):
4780 """Test that an image with an OpenSBI binary can be created"""
4781 data = self._DoReadFile('201_opensbi.dts')
4782 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
4783
Simon Glassc69d19c2021-07-06 10:36:37 -06004784 def testSectionsSingleThread(self):
4785 """Test sections without multithreading"""
4786 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
Simon Glassc1aa66e2022-01-29 14:14:04 -07004787 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4788 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
4789 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glassc69d19c2021-07-06 10:36:37 -06004790 self.assertEqual(expected, data)
4791
4792 def testThreadTimeout(self):
4793 """Test handling a thread that takes too long"""
4794 with self.assertRaises(ValueError) as e:
4795 self._DoTestFile('202_section_timeout.dts',
4796 test_section_timeout=True)
Simon Glassb2dfe832021-10-18 12:13:15 -06004797 self.assertIn("Timed out obtaining contents", str(e.exception))
Simon Glassc69d19c2021-07-06 10:36:37 -06004798
Simon Glass03ebc202021-07-06 10:36:41 -06004799 def testTiming(self):
4800 """Test output of timing information"""
4801 data = self._DoReadFile('055_sections.dts')
4802 with test_util.capture_sys_output() as (stdout, stderr):
4803 state.TimingShow()
4804 self.assertIn('read:', stdout.getvalue())
4805 self.assertIn('compress:', stdout.getvalue())
4806
Simon Glass0427bed2021-11-03 21:09:18 -06004807 def testUpdateFdtInElf(self):
4808 """Test that we can update the devicetree in an ELF file"""
4809 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4810 outfile = os.path.join(self._indir, 'u-boot.out')
4811 begin_sym = 'dtb_embed_begin'
4812 end_sym = 'dtb_embed_end'
4813 retcode = self._DoTestFile(
4814 '060_fdt_update.dts', update_dtb=True,
4815 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4816 self.assertEqual(0, retcode)
4817
4818 # Check that the output file does in fact contact a dtb with the binman
4819 # definition in the correct place
4820 syms = elf.GetSymbolFileOffset(infile,
4821 ['dtb_embed_begin', 'dtb_embed_end'])
Simon Glassc1aa66e2022-01-29 14:14:04 -07004822 data = tools.read_file(outfile)
Simon Glass0427bed2021-11-03 21:09:18 -06004823 dtb_data = data[syms['dtb_embed_begin'].offset:
4824 syms['dtb_embed_end'].offset]
4825
4826 dtb = fdt.Fdt.FromData(dtb_data)
4827 dtb.Scan()
4828 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4829 self.assertEqual({
4830 'image-pos': 0,
4831 'offset': 0,
4832 '_testing:offset': 32,
4833 '_testing:size': 2,
4834 '_testing:image-pos': 32,
4835 'section@0/u-boot:offset': 0,
4836 'section@0/u-boot:size': len(U_BOOT_DATA),
4837 'section@0/u-boot:image-pos': 0,
4838 'section@0:offset': 0,
4839 'section@0:size': 16,
4840 'section@0:image-pos': 0,
4841
4842 'section@1/u-boot:offset': 0,
4843 'section@1/u-boot:size': len(U_BOOT_DATA),
4844 'section@1/u-boot:image-pos': 16,
4845 'section@1:offset': 16,
4846 'section@1:size': 16,
4847 'section@1:image-pos': 16,
4848 'size': 40
4849 }, props)
4850
4851 def testUpdateFdtInElfInvalid(self):
4852 """Test that invalid args are detected with --update-fdt-in-elf"""
4853 with self.assertRaises(ValueError) as e:
4854 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
4855 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
4856 str(e.exception))
4857
4858 def testUpdateFdtInElfNoSyms(self):
4859 """Test that missing symbols are detected with --update-fdt-in-elf"""
4860 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4861 outfile = ''
4862 begin_sym = 'wrong_begin'
4863 end_sym = 'wrong_end'
4864 with self.assertRaises(ValueError) as e:
4865 self._DoTestFile(
4866 '060_fdt_update.dts',
4867 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4868 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
4869 str(e.exception))
4870
4871 def testUpdateFdtInElfTooSmall(self):
4872 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
4873 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
4874 outfile = os.path.join(self._indir, 'u-boot.out')
4875 begin_sym = 'dtb_embed_begin'
4876 end_sym = 'dtb_embed_end'
4877 with self.assertRaises(ValueError) as e:
4878 self._DoTestFile(
4879 '060_fdt_update.dts', update_dtb=True,
4880 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4881 self.assertRegex(
4882 str(e.exception),
4883 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
4884
Simon Glassc475dec2021-11-23 11:03:42 -07004885 def testVersion(self):
4886 """Test we can get the binman version"""
4887 version = '(unreleased)'
4888 self.assertEqual(version, state.GetVersion(self._indir))
4889
4890 with self.assertRaises(SystemExit):
4891 with test_util.capture_sys_output() as (_, stderr):
4892 self._DoBinman('-V')
4893 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
4894
4895 # Try running the tool too, just to be safe
4896 result = self._RunBinman('-V')
4897 self.assertEqual('Binman %s\n' % version, result.stderr)
4898
4899 # Set up a version file to make sure that works
4900 version = 'v2025.01-rc2'
Simon Glassc1aa66e2022-01-29 14:14:04 -07004901 tools.write_file(os.path.join(self._indir, 'version'), version,
Simon Glassc475dec2021-11-23 11:03:42 -07004902 binary=False)
4903 self.assertEqual(version, state.GetVersion(self._indir))
4904
Simon Glass943bf782021-11-23 21:09:50 -07004905 def testAltFormat(self):
4906 """Test that alternative formats can be used to extract"""
4907 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
4908
4909 try:
4910 tmpdir, updated_fname = self._SetupImageInTmpdir()
4911 with test_util.capture_sys_output() as (stdout, _):
4912 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
4913 self.assertEqual(
4914 '''Flag (-F) Entry type Description
4915fdt fdtmap Extract the devicetree blob from the fdtmap
4916''',
4917 stdout.getvalue())
4918
4919 dtb = os.path.join(tmpdir, 'fdt.dtb')
4920 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
4921 dtb, 'fdtmap')
4922
4923 # Check that we can read it and it can be scanning, meaning it does
4924 # not have a 16-byte fdtmap header
Simon Glassc1aa66e2022-01-29 14:14:04 -07004925 data = tools.read_file(dtb)
Simon Glass943bf782021-11-23 21:09:50 -07004926 dtb = fdt.Fdt.FromData(data)
4927 dtb.Scan()
4928
4929 # Now check u-boot which has no alt_format
4930 fname = os.path.join(tmpdir, 'fdt.dtb')
4931 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
4932 '-f', fname, 'u-boot')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004933 data = tools.read_file(fname)
Simon Glass943bf782021-11-23 21:09:50 -07004934 self.assertEqual(U_BOOT_DATA, data)
4935
4936 finally:
4937 shutil.rmtree(tmpdir)
4938
Simon Glasscc2c5002021-11-23 21:09:52 -07004939 def testExtblobList(self):
4940 """Test an image with an external blob list"""
4941 data = self._DoReadFile('215_blob_ext_list.dts')
4942 self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
4943
4944 def testExtblobListMissing(self):
4945 """Test an image with a missing external blob"""
4946 with self.assertRaises(ValueError) as e:
4947 self._DoReadFile('216_blob_ext_list_missing.dts')
4948 self.assertIn("Filename 'missing-file' not found in input path",
4949 str(e.exception))
4950
4951 def testExtblobListMissingOk(self):
4952 """Test an image with an missing external blob that is allowed"""
4953 with test_util.capture_sys_output() as (stdout, stderr):
4954 self._DoTestFile('216_blob_ext_list_missing.dts',
4955 allow_missing=True)
4956 err = stderr.getvalue()
4957 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
4958
Simon Glass75989722021-11-23 21:08:59 -07004959 def testFip(self):
4960 """Basic test of generation of an ARM Firmware Image Package (FIP)"""
4961 data = self._DoReadFile('203_fip.dts')
4962 hdr, fents = fip_util.decode_fip(data)
4963 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
4964 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
4965 self.assertEqual(0x123, hdr.flags)
4966
4967 self.assertEqual(2, len(fents))
4968
4969 fent = fents[0]
4970 self.assertEqual(
4971 bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
4972 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
4973 self.assertEqual('soc-fw', fent.fip_type)
4974 self.assertEqual(0x88, fent.offset)
4975 self.assertEqual(len(ATF_BL31_DATA), fent.size)
4976 self.assertEqual(0x123456789abcdef, fent.flags)
4977 self.assertEqual(ATF_BL31_DATA, fent.data)
4978 self.assertEqual(True, fent.valid)
4979
4980 fent = fents[1]
4981 self.assertEqual(
4982 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
4983 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
4984 self.assertEqual('scp-fwu-cfg', fent.fip_type)
4985 self.assertEqual(0x8c, fent.offset)
4986 self.assertEqual(len(ATF_BL31_DATA), fent.size)
4987 self.assertEqual(0, fent.flags)
4988 self.assertEqual(ATF_BL2U_DATA, fent.data)
4989 self.assertEqual(True, fent.valid)
4990
4991 def testFipOther(self):
4992 """Basic FIP with something that isn't a external blob"""
4993 data = self._DoReadFile('204_fip_other.dts')
4994 hdr, fents = fip_util.decode_fip(data)
4995
4996 self.assertEqual(2, len(fents))
4997 fent = fents[1]
4998 self.assertEqual('rot-cert', fent.fip_type)
4999 self.assertEqual(b'aa', fent.data)
5000
Simon Glass75989722021-11-23 21:08:59 -07005001 def testFipNoType(self):
5002 """FIP with an entry of an unknown type"""
5003 with self.assertRaises(ValueError) as e:
5004 self._DoReadFile('205_fip_no_type.dts')
5005 self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
5006 str(e.exception))
5007
5008 def testFipUuid(self):
5009 """Basic FIP with a manual uuid"""
5010 data = self._DoReadFile('206_fip_uuid.dts')
5011 hdr, fents = fip_util.decode_fip(data)
5012
5013 self.assertEqual(2, len(fents))
5014 fent = fents[1]
5015 self.assertEqual(None, fent.fip_type)
5016 self.assertEqual(
5017 bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
5018 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
5019 fent.uuid)
5020 self.assertEqual(U_BOOT_DATA, fent.data)
5021
5022 def testFipLs(self):
5023 """Test listing a FIP"""
5024 data = self._DoReadFileRealDtb('207_fip_ls.dts')
5025 hdr, fents = fip_util.decode_fip(data)
5026
5027 try:
5028 tmpdir, updated_fname = self._SetupImageInTmpdir()
5029 with test_util.capture_sys_output() as (stdout, stderr):
5030 self._DoBinman('ls', '-i', updated_fname)
5031 finally:
5032 shutil.rmtree(tmpdir)
5033 lines = stdout.getvalue().splitlines()
5034 expected = [
5035'Name Image-pos Size Entry-type Offset Uncomp-size',
5036'----------------------------------------------------------------',
5037'main-section 0 2d3 section 0',
5038' atf-fip 0 90 atf-fip 0',
5039' soc-fw 88 4 blob-ext 88',
5040' u-boot 8c 4 u-boot 8c',
5041' fdtmap 90 243 fdtmap 90',
5042]
5043 self.assertEqual(expected, lines)
5044
5045 image = control.images['image']
5046 entries = image.GetEntries()
5047 fdtmap = entries['fdtmap']
5048
5049 fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
5050 magic = fdtmap_data[:8]
5051 self.assertEqual(b'_FDTMAP_', magic)
Simon Glassc1aa66e2022-01-29 14:14:04 -07005052 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass75989722021-11-23 21:08:59 -07005053
5054 fdt_data = fdtmap_data[16:]
5055 dtb = fdt.Fdt.FromData(fdt_data)
5056 dtb.Scan()
5057 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
5058 self.assertEqual({
5059 'atf-fip/soc-fw:image-pos': 136,
5060 'atf-fip/soc-fw:offset': 136,
5061 'atf-fip/soc-fw:size': 4,
5062 'atf-fip/u-boot:image-pos': 140,
5063 'atf-fip/u-boot:offset': 140,
5064 'atf-fip/u-boot:size': 4,
5065 'atf-fip:image-pos': 0,
5066 'atf-fip:offset': 0,
5067 'atf-fip:size': 144,
5068 'image-pos': 0,
5069 'offset': 0,
5070 'fdtmap:image-pos': fdtmap.image_pos,
5071 'fdtmap:offset': fdtmap.offset,
5072 'fdtmap:size': len(fdtmap_data),
5073 'size': len(data),
5074 }, props)
5075
5076 def testFipExtractOneEntry(self):
5077 """Test extracting a single entry fron an FIP"""
5078 self._DoReadFileRealDtb('207_fip_ls.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07005079 image_fname = tools.get_output_filename('image.bin')
Simon Glass75989722021-11-23 21:08:59 -07005080 fname = os.path.join(self._indir, 'output.extact')
5081 control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
Simon Glassc1aa66e2022-01-29 14:14:04 -07005082 data = tools.read_file(fname)
Simon Glass75989722021-11-23 21:08:59 -07005083 self.assertEqual(U_BOOT_DATA, data)
5084
5085 def testFipReplace(self):
5086 """Test replacing a single file in a FIP"""
Simon Glassc1aa66e2022-01-29 14:14:04 -07005087 expected = U_BOOT_DATA + tools.get_bytes(0x78, 50)
Simon Glass75989722021-11-23 21:08:59 -07005088 data = self._DoReadFileRealDtb('208_fip_replace.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07005089 updated_fname = tools.get_output_filename('image-updated.bin')
5090 tools.write_file(updated_fname, data)
Simon Glass75989722021-11-23 21:08:59 -07005091 entry_name = 'atf-fip/u-boot'
5092 control.WriteEntry(updated_fname, entry_name, expected,
5093 allow_resize=True)
5094 actual = control.ReadEntry(updated_fname, entry_name)
5095 self.assertEqual(expected, actual)
5096
Simon Glassc1aa66e2022-01-29 14:14:04 -07005097 new_data = tools.read_file(updated_fname)
Simon Glass75989722021-11-23 21:08:59 -07005098 hdr, fents = fip_util.decode_fip(new_data)
5099
5100 self.assertEqual(2, len(fents))
5101
5102 # Check that the FIP entry is updated
5103 fent = fents[1]
5104 self.assertEqual(0x8c, fent.offset)
5105 self.assertEqual(len(expected), fent.size)
5106 self.assertEqual(0, fent.flags)
5107 self.assertEqual(expected, fent.data)
5108 self.assertEqual(True, fent.valid)
5109
5110 def testFipMissing(self):
5111 with test_util.capture_sys_output() as (stdout, stderr):
5112 self._DoTestFile('209_fip_missing.dts', allow_missing=True)
5113 err = stderr.getvalue()
5114 self.assertRegex(err, "Image 'main-section'.*missing.*: rmm-fw")
5115
5116 def testFipSize(self):
5117 """Test a FIP with a size property"""
5118 data = self._DoReadFile('210_fip_size.dts')
5119 self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
5120 hdr, fents = fip_util.decode_fip(data)
5121 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5122 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5123
5124 self.assertEqual(1, len(fents))
5125
5126 fent = fents[0]
5127 self.assertEqual('soc-fw', fent.fip_type)
5128 self.assertEqual(0x60, fent.offset)
5129 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5130 self.assertEqual(ATF_BL31_DATA, fent.data)
5131 self.assertEqual(True, fent.valid)
5132
5133 rest = data[0x60 + len(ATF_BL31_DATA):0x100]
Simon Glassc1aa66e2022-01-29 14:14:04 -07005134 self.assertEqual(tools.get_bytes(0xff, len(rest)), rest)
Simon Glass75989722021-11-23 21:08:59 -07005135
5136 def testFipBadAlign(self):
5137 """Test that an invalid alignment value in a FIP is detected"""
5138 with self.assertRaises(ValueError) as e:
5139 self._DoTestFile('211_fip_bad_align.dts')
5140 self.assertIn(
5141 "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
5142 str(e.exception))
5143
5144 def testFipCollection(self):
5145 """Test using a FIP in a collection"""
5146 data = self._DoReadFile('212_fip_collection.dts')
5147 entry1 = control.images['image'].GetEntries()['collection']
5148 data1 = data[:entry1.size]
5149 hdr1, fents2 = fip_util.decode_fip(data1)
5150
5151 entry2 = control.images['image'].GetEntries()['atf-fip']
5152 data2 = data[entry2.offset:entry2.offset + entry2.size]
5153 hdr1, fents2 = fip_util.decode_fip(data2)
5154
5155 # The 'collection' entry should have U-Boot included at the end
5156 self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
5157 self.assertEqual(data1, data2 + U_BOOT_DATA)
5158 self.assertEqual(U_BOOT_DATA, data1[-4:])
5159
5160 # There should be a U-Boot after the final FIP
5161 self.assertEqual(U_BOOT_DATA, data[-4:])
Simon Glassc69d19c2021-07-06 10:36:37 -06005162
Simon Glass32d4f102022-01-12 13:10:35 -07005163 def testFakeBlob(self):
5164 """Test handling of faking an external blob"""
5165 with test_util.capture_sys_output() as (stdout, stderr):
5166 self._DoTestFile('217_fake_blob.dts', allow_missing=True,
5167 allow_fake_blobs=True)
5168 err = stderr.getvalue()
5169 self.assertRegex(
5170 err,
5171 "Image '.*' has faked external blobs and is non-functional: .*")
Simon Glass32d4f102022-01-12 13:10:35 -07005172
Simon Glassf4590e02022-01-09 20:13:46 -07005173 def testExtblobListFaked(self):
5174 """Test an extblob with missing external blob that are faked"""
5175 with test_util.capture_sys_output() as (stdout, stderr):
5176 self._DoTestFile('216_blob_ext_list_missing.dts',
5177 allow_fake_blobs=True)
5178 err = stderr.getvalue()
5179 self.assertRegex(err, "Image 'main-section'.*faked.*: blob-ext-list")
5180
Simon Glass56ee85e2022-01-09 20:13:57 -07005181 def testListBintools(self):
5182 args = ['tool', '--list']
5183 with test_util.capture_sys_output() as (stdout, _):
5184 self._DoBinman(*args)
5185 out = stdout.getvalue().splitlines()
5186 self.assertTrue(len(out) >= 2)
5187
5188 def testFetchBintools(self):
5189 def fail_download(url):
Simon Glassc1aa66e2022-01-29 14:14:04 -07005190 """Take the tools.download() function by raising an exception"""
Simon Glass56ee85e2022-01-09 20:13:57 -07005191 raise urllib.error.URLError('my error')
5192
5193 args = ['tool']
5194 with self.assertRaises(ValueError) as e:
5195 self._DoBinman(*args)
5196 self.assertIn("Invalid arguments to 'tool' subcommand",
5197 str(e.exception))
5198
5199 args = ['tool', '--fetch']
5200 with self.assertRaises(ValueError) as e:
5201 self._DoBinman(*args)
5202 self.assertIn('Please specify bintools to fetch', str(e.exception))
5203
5204 args = ['tool', '--fetch', '_testing']
Simon Glassc1aa66e2022-01-29 14:14:04 -07005205 with unittest.mock.patch.object(tools, 'download',
Simon Glass56ee85e2022-01-09 20:13:57 -07005206 side_effect=fail_download):
5207 with test_util.capture_sys_output() as (stdout, _):
5208 self._DoBinman(*args)
5209 self.assertIn('failed to fetch with all methods', stdout.getvalue())
5210
Simon Glassa00d9712022-01-09 20:14:10 -07005211 def testInvalidCompress(self):
5212 with self.assertRaises(ValueError) as e:
5213 comp_util.compress(b'', 'invalid')
5214 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
5215
5216 with self.assertRaises(ValueError) as e:
5217 comp_util.decompress(b'1234', 'invalid')
5218 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
5219
Simon Glassbc570642022-01-09 20:14:11 -07005220 def testBintoolDocs(self):
5221 """Test for creation of bintool documentation"""
5222 with test_util.capture_sys_output() as (stdout, stderr):
5223 control.write_bintool_docs(control.bintool.Bintool.get_tool_list())
5224 self.assertTrue(len(stdout.getvalue()) > 0)
5225
5226 def testBintoolDocsMissing(self):
5227 """Test handling of missing bintool documentation"""
5228 with self.assertRaises(ValueError) as e:
5229 with test_util.capture_sys_output() as (stdout, stderr):
5230 control.write_bintool_docs(
5231 control.bintool.Bintool.get_tool_list(), 'mkimage')
5232 self.assertIn('Documentation is missing for modules: mkimage',
5233 str(e.exception))
5234
Jan Kiszkafcc87ef2022-01-28 20:37:53 +01005235 def testListWithGenNode(self):
5236 """Check handling of an FDT map when the section cannot be found"""
5237 entry_args = {
5238 'of-list': 'test-fdt1 test-fdt2',
5239 }
5240 data = self._DoReadFileDtb(
5241 '219_fit_gennode.dts',
5242 entry_args=entry_args,
5243 use_real_dtb=True,
5244 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])
5245
5246 try:
5247 tmpdir, updated_fname = self._SetupImageInTmpdir()
5248 with test_util.capture_sys_output() as (stdout, stderr):
5249 self._RunBinman('ls', '-i', updated_fname)
5250 finally:
5251 shutil.rmtree(tmpdir)
5252
Alper Nebi Yasaked293c32022-02-08 01:08:05 +03005253 def testFitSubentryUsesBintool(self):
5254 """Test that binman FIT subentries can use bintools"""
5255 command.test_result = self._HandleGbbCommand
5256 entry_args = {
5257 'keydir': 'devkeys',
5258 'bmpblk': 'bmpblk.bin',
5259 }
5260 data, _, _, _ = self._DoReadFileDtb('220_fit_subentry_bintool.dts',
5261 entry_args=entry_args)
5262
Alper Nebi Yasakf3078d42022-02-08 01:08:07 +03005263 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
5264 tools.get_bytes(0, 0x2180 - 16))
Alper Nebi Yasaked293c32022-02-08 01:08:05 +03005265 self.assertIn(expected, data)
5266
5267 def testFitSubentryMissingBintool(self):
5268 """Test that binman reports missing bintools for FIT subentries"""
5269 entry_args = {
5270 'keydir': 'devkeys',
5271 }
5272 with test_util.capture_sys_output() as (_, stderr):
5273 self._DoTestFile('220_fit_subentry_bintool.dts',
5274 force_missing_bintools='futility', entry_args=entry_args)
5275 err = stderr.getvalue()
5276 self.assertRegex(err,
5277 "Image 'main-section'.*missing bintools.*: futility")
Simon Glass32d4f102022-01-12 13:10:35 -07005278
Alper Nebi Yasakee813c82022-02-09 22:02:35 +03005279 def testFitSubentryHashSubnode(self):
5280 """Test an image with a FIT inside"""
5281 data, _, _, out_dtb_name = self._DoReadFileDtb(
5282 '221_fit_subentry_hash.dts', use_real_dtb=True, update_dtb=True)
5283
5284 mkimage_dtb = fdt.Fdt.FromData(data)
5285 mkimage_dtb.Scan()
5286 binman_dtb = fdt.Fdt(out_dtb_name)
5287 binman_dtb.Scan()
5288
5289 # Check that binman didn't add hash values
5290 fnode = binman_dtb.GetNode('/binman/fit/images/kernel/hash')
5291 self.assertNotIn('value', fnode.props)
5292
5293 fnode = binman_dtb.GetNode('/binman/fit/images/fdt-1/hash')
5294 self.assertNotIn('value', fnode.props)
5295
5296 # Check that mkimage added hash values
5297 fnode = mkimage_dtb.GetNode('/images/kernel/hash')
5298 self.assertIn('value', fnode.props)
5299
5300 fnode = mkimage_dtb.GetNode('/images/fdt-1/hash')
5301 self.assertIn('value', fnode.props)
5302
Roger Quadros47f420a2022-02-19 20:50:04 +02005303 def testPackTeeOs(self):
5304 """Test that an image with an TEE binary can be created"""
5305 data = self._DoReadFile('222_tee_os.dts')
5306 self.assertEqual(TEE_OS_DATA, data[:len(TEE_OS_DATA)])
5307
Simon Glass6a0b5f82022-02-08 11:50:03 -07005308 def testFitFdtOper(self):
5309 """Check handling of a specified FIT operation"""
5310 entry_args = {
5311 'of-list': 'test-fdt1 test-fdt2',
5312 'default-dt': 'test-fdt2',
5313 }
5314 self._DoReadFileDtb(
5315 '223_fit_fdt_oper.dts',
5316 entry_args=entry_args,
5317 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
5318
5319 def testFitFdtBadOper(self):
5320 """Check handling of an FDT map when the section cannot be found"""
5321 with self.assertRaises(ValueError) as exc:
5322 self._DoReadFileDtb('224_fit_bad_oper.dts')
Simon Glassce4e4022022-03-05 20:19:09 -07005323 self.assertIn("Node '/binman/fit': subnode 'images/@fdt-SEQ': Unknown operation 'unknown'",
Simon Glass6a0b5f82022-02-08 11:50:03 -07005324 str(exc.exception))
5325
Simon Glass80a66ae2022-03-05 20:18:59 -07005326 def test_uses_expand_size(self):
5327 """Test that the 'expand-size' property cannot be used anymore"""
5328 with self.assertRaises(ValueError) as e:
5329 data = self._DoReadFile('225_expand_size_bad.dts')
5330 self.assertIn(
5331 "Node '/binman/u-boot': Please use 'extend-size' instead of 'expand-size'",
5332 str(e.exception))
5333
Simon Glass72e423c2022-03-05 20:19:05 -07005334 def testMkimageMissingBlob(self):
5335 """Test using mkimage to build an image"""
5336 with test_util.capture_sys_output() as (stdout, stderr):
5337 self._DoTestFile('229_mkimage_missing.dts', allow_missing=True,
5338 allow_fake_blobs=True)
5339 err = stderr.getvalue()
5340 self.assertRegex(
5341 err,
5342 "Image '.*' has faked external blobs and is non-functional: .*")
5343
Simon Glass40c8bdd2022-03-05 20:19:12 -07005344 def testFitSplitElf(self):
5345 """Test an image with an FIT with an split-elf operation"""
5346 entry_args = {
5347 'of-list': 'test-fdt1 test-fdt2',
5348 'default-dt': 'test-fdt2',
5349 'atf-bl31-path': 'bl31.elf',
5350 'tee-os-path': 'tee.elf',
5351 }
5352 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5353 data = self._DoReadFileDtb(
5354 '226_fit_split_elf.dts',
5355 entry_args=entry_args,
5356 extra_indirs=[test_subdir])[0]
5357
5358 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
5359 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
5360
5361 base_keys = {'description', 'type', 'arch', 'os', 'compression',
5362 'data', 'load'}
5363 dtb = fdt.Fdt.FromData(fit_data)
5364 dtb.Scan()
5365
5366 elf_data = tools.read_file(os.path.join(self._indir, 'bl31.elf'))
5367 segments, entry = elf.read_loadable_segments(elf_data)
5368
5369 # We assume there are two segments
5370 self.assertEquals(2, len(segments))
5371
5372 atf1 = dtb.GetNode('/images/atf-1')
5373 _, start, data = segments[0]
5374 self.assertEqual(base_keys | {'entry'}, atf1.props.keys())
5375 self.assertEqual(entry,
5376 fdt_util.fdt32_to_cpu(atf1.props['entry'].value))
5377 self.assertEqual(start,
5378 fdt_util.fdt32_to_cpu(atf1.props['load'].value))
5379 self.assertEqual(data, atf1.props['data'].bytes)
5380
5381 atf2 = dtb.GetNode('/images/atf-2')
5382 self.assertEqual(base_keys, atf2.props.keys())
5383 _, start, data = segments[1]
5384 self.assertEqual(start,
5385 fdt_util.fdt32_to_cpu(atf2.props['load'].value))
5386 self.assertEqual(data, atf2.props['data'].bytes)
5387
5388 conf = dtb.GetNode('/configurations')
5389 self.assertEqual({'default'}, conf.props.keys())
5390
5391 for subnode in conf.subnodes:
5392 self.assertEqual({'description', 'fdt', 'loadables'},
5393 subnode.props.keys())
5394 self.assertEqual(
5395 ['atf-1', 'atf-2', 'tee-1', 'tee-2'],
5396 fdt_util.GetStringList(subnode, 'loadables'))
5397
5398 def _check_bad_fit(self, dts):
5399 """Check a bad FIT
5400
5401 This runs with the given dts and returns the assertion raised
5402
5403 Args:
5404 dts (str): dts filename to use
5405
5406 Returns:
5407 str: Assertion string raised
5408 """
5409 entry_args = {
5410 'of-list': 'test-fdt1 test-fdt2',
5411 'default-dt': 'test-fdt2',
5412 'atf-bl31-path': 'bl31.elf',
5413 'tee-os-path': 'tee.elf',
5414 }
5415 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5416 with self.assertRaises(ValueError) as exc:
5417 self._DoReadFileDtb(dts, entry_args=entry_args,
5418 extra_indirs=[test_subdir])[0]
5419 return str(exc.exception)
5420
5421 def testFitSplitElfBadElf(self):
5422 """Test a FIT split-elf operation with an invalid ELF file"""
5423 TestFunctional._MakeInputFile('bad.elf', tools.get_bytes(100, 100))
5424 entry_args = {
5425 'of-list': 'test-fdt1 test-fdt2',
5426 'default-dt': 'test-fdt2',
5427 'atf-bl31-path': 'bad.elf',
5428 'tee-os-path': 'tee.elf',
5429 }
5430 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5431 with self.assertRaises(ValueError) as exc:
5432 self._DoReadFileDtb(
5433 '226_fit_split_elf.dts',
5434 entry_args=entry_args,
5435 extra_indirs=[test_subdir])[0]
5436 self.assertIn(
5437 "Node '/binman/fit': subnode 'images/@atf-SEQ': Failed to read ELF file: Magic number does not match",
5438 str(exc.exception))
5439
5440 def testFitSplitElfBadDirective(self):
5441 """Test a FIT split-elf invalid fit,xxx directive in an image node"""
5442 err = self._check_bad_fit('227_fit_bad_dir.dts')
5443 self.assertIn(
5444 "Node '/binman/fit': subnode 'images/@atf-SEQ': Unknown directive 'fit,something'",
5445 err)
5446
5447 def testFitSplitElfBadDirectiveConfig(self):
5448 """Test a FIT split-elf with invalid fit,xxx directive in config"""
5449 err = self._check_bad_fit('228_fit_bad_dir_config.dts')
5450 self.assertEqual(
5451 "Node '/binman/fit': subnode 'configurations/@config-SEQ': Unknown directive 'fit,config'",
5452 err)
5453
5454 def checkFitSplitElf(self, **kwargs):
5455 """Test an split-elf FIT with a missing ELF file"""
5456 entry_args = {
5457 'of-list': 'test-fdt1 test-fdt2',
5458 'default-dt': 'test-fdt2',
5459 'atf-bl31-path': 'bl31.elf',
5460 'tee-os-path': 'missing.elf',
5461 }
5462 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5463 with test_util.capture_sys_output() as (stdout, stderr):
5464 self._DoTestFile(
5465 '226_fit_split_elf.dts', entry_args=entry_args,
5466 extra_indirs=[test_subdir], **kwargs)
5467 err = stderr.getvalue()
5468 return err
5469
5470 def testFitSplitElfMissing(self):
5471 """Test an split-elf FIT with a missing ELF file"""
5472 err = self.checkFitSplitElf(allow_missing=True)
5473 self.assertRegex(
5474 err,
5475 "Image '.*' is missing external blobs and is non-functional: .*")
5476
5477 def testFitSplitElfFaked(self):
5478 """Test an split-elf FIT with faked ELF file"""
5479 err = self.checkFitSplitElf(allow_missing=True, allow_fake_blobs=True)
5480 self.assertRegex(
5481 err,
5482 "Image '.*' is missing external blobs and is non-functional: .*")
5483
Philippe Reynesb1c50932022-03-28 22:57:04 +02005484 def testPreLoad(self):
5485 """Test an image with a pre-load header"""
5486 entry_args = {
5487 'pre-load-key-path': '.',
5488 }
5489 data, _, _, _ = self._DoReadFileDtb('225_pre_load.dts',
5490 entry_args=entry_args)
5491 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5492 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5493 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5494 data = self._DoReadFile('225_pre_load.dts')
5495 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5496 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5497 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5498
5499 def testPreLoadPkcs(self):
5500 """Test an image with a pre-load header with padding pkcs"""
5501 data = self._DoReadFile('226_pre_load_pkcs.dts')
5502 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5503 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5504 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5505
5506 def testPreLoadPss(self):
5507 """Test an image with a pre-load header with padding pss"""
5508 data = self._DoReadFile('227_pre_load_pss.dts')
5509 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5510 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5511 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5512
5513 def testPreLoadInvalidPadding(self):
5514 """Test an image with a pre-load header with an invalid padding"""
5515 with self.assertRaises(ValueError) as e:
5516 data = self._DoReadFile('228_pre_load_invalid_padding.dts')
5517
5518 def testPreLoadInvalidSha(self):
5519 """Test an image with a pre-load header with an invalid hash"""
5520 with self.assertRaises(ValueError) as e:
5521 data = self._DoReadFile('229_pre_load_invalid_sha.dts')
5522
5523 def testPreLoadInvalidAlgo(self):
5524 """Test an image with a pre-load header with an invalid algo"""
5525 with self.assertRaises(ValueError) as e:
5526 data = self._DoReadFile('230_pre_load_invalid_algo.dts')
5527
5528 def testPreLoadInvalidKey(self):
5529 """Test an image with a pre-load header with an invalid key"""
5530 with self.assertRaises(ValueError) as e:
5531 data = self._DoReadFile('231_pre_load_invalid_key.dts')
Roger Quadros47f420a2022-02-19 20:50:04 +02005532
Alper Nebi Yasak67bf2c82022-03-27 18:31:44 +03005533 def _CheckSafeUniqueNames(self, *images):
5534 """Check all entries of given images for unsafe unique names"""
5535 for image in images:
5536 entries = {}
5537 image._CollectEntries(entries, {}, image)
5538 for entry in entries.values():
5539 uniq = entry.GetUniqueName()
5540
5541 # Used as part of a filename, so must not be absolute paths.
5542 self.assertFalse(os.path.isabs(uniq))
5543
5544 def testSafeUniqueNames(self):
5545 """Test entry unique names are safe in single image configuration"""
5546 data = self._DoReadFileRealDtb('230_unique_names.dts')
5547
5548 orig_image = control.images['image']
5549 image_fname = tools.get_output_filename('image.bin')
5550 image = Image.FromFile(image_fname)
5551
5552 self._CheckSafeUniqueNames(orig_image, image)
5553
5554 def testSafeUniqueNamesMulti(self):
5555 """Test entry unique names are safe with multiple images"""
5556 data = self._DoReadFileRealDtb('231_unique_names_multi.dts')
5557
5558 orig_image = control.images['image']
5559 image_fname = tools.get_output_filename('image.bin')
5560 image = Image.FromFile(image_fname)
5561
5562 self._CheckSafeUniqueNames(orig_image, image)
5563
Alper Nebi Yasak8ee4ec92022-03-27 18:31:45 +03005564 def testReplaceCmdWithBintool(self):
5565 """Test replacing an entry that needs a bintool to pack"""
5566 data = self._DoReadFileRealDtb('232_replace_with_bintool.dts')
5567 expected = U_BOOT_DATA + b'aa'
5568 self.assertEqual(expected, data[:len(expected)])
5569
5570 try:
5571 tmpdir, updated_fname = self._SetupImageInTmpdir()
5572 fname = os.path.join(tmpdir, 'update-testing.bin')
5573 tools.write_file(fname, b'zz')
5574 self._DoBinman('replace', '-i', updated_fname,
5575 '_testing', '-f', fname)
5576
5577 data = tools.read_file(updated_fname)
5578 expected = U_BOOT_DATA + b'zz'
5579 self.assertEqual(expected, data[:len(expected)])
5580 finally:
5581 shutil.rmtree(tmpdir)
5582
5583 def testReplaceCmdOtherWithBintool(self):
5584 """Test replacing an entry when another needs a bintool to pack"""
5585 data = self._DoReadFileRealDtb('232_replace_with_bintool.dts')
5586 expected = U_BOOT_DATA + b'aa'
5587 self.assertEqual(expected, data[:len(expected)])
5588
5589 try:
5590 tmpdir, updated_fname = self._SetupImageInTmpdir()
5591 fname = os.path.join(tmpdir, 'update-u-boot.bin')
5592 tools.write_file(fname, b'x' * len(U_BOOT_DATA))
5593 self._DoBinman('replace', '-i', updated_fname,
5594 'u-boot', '-f', fname)
5595
5596 data = tools.read_file(updated_fname)
5597 expected = b'x' * len(U_BOOT_DATA) + b'aa'
5598 self.assertEqual(expected, data[:len(expected)])
5599 finally:
5600 shutil.rmtree(tmpdir)
5601
Alper Nebi Yasake2ce4fb2022-03-27 18:31:46 +03005602 def testReplaceResizeNoRepackSameSize(self):
5603 """Test replacing entries with same-size data without repacking"""
5604 expected = b'x' * len(U_BOOT_DATA)
5605 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected)
5606 self.assertEqual(expected, data)
5607
5608 path, fdtmap = state.GetFdtContents('fdtmap')
5609 self.assertIsNotNone(path)
5610 self.assertEqual(expected_fdtmap, fdtmap)
5611
5612 def testReplaceResizeNoRepackSmallerSize(self):
5613 """Test replacing entries with smaller-size data without repacking"""
5614 new_data = b'x'
5615 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', new_data)
5616 expected = new_data.ljust(len(U_BOOT_DATA), b'\0')
5617 self.assertEqual(expected, data)
5618
5619 path, fdtmap = state.GetFdtContents('fdtmap')
5620 self.assertIsNotNone(path)
5621 self.assertEqual(expected_fdtmap, fdtmap)
5622
Alper Nebi Yasak74d3b232022-03-27 18:31:48 +03005623 def testExtractFit(self):
5624 """Test extracting a FIT section"""
5625 self._DoReadFileRealDtb('233_fit_extract_replace.dts')
5626 image_fname = tools.get_output_filename('image.bin')
5627
5628 fit_data = control.ReadEntry(image_fname, 'fit')
5629 fit = fdt.Fdt.FromData(fit_data)
5630 fit.Scan()
5631
5632 # Check subentry data inside the extracted fit
5633 for node_path, expected in [
5634 ('/images/kernel', U_BOOT_DATA),
5635 ('/images/fdt-1', U_BOOT_NODTB_DATA),
5636 ('/images/scr-1', COMPRESS_DATA),
5637 ]:
5638 node = fit.GetNode(node_path)
5639 data = fit.GetProps(node)['data'].bytes
5640 self.assertEqual(expected, data)
5641
5642 def testExtractFitSubentries(self):
5643 """Test extracting FIT section subentries"""
5644 self._DoReadFileRealDtb('233_fit_extract_replace.dts')
5645 image_fname = tools.get_output_filename('image.bin')
5646
5647 for entry_path, expected in [
5648 ('fit/kernel', U_BOOT_DATA),
5649 ('fit/kernel/u-boot', U_BOOT_DATA),
5650 ('fit/fdt-1', U_BOOT_NODTB_DATA),
5651 ('fit/fdt-1/u-boot-nodtb', U_BOOT_NODTB_DATA),
5652 ('fit/scr-1', COMPRESS_DATA),
5653 ('fit/scr-1/blob', COMPRESS_DATA),
5654 ]:
5655 data = control.ReadEntry(image_fname, entry_path)
5656 self.assertEqual(expected, data)
5657
Alper Nebi Yasak99283e52022-03-27 18:31:49 +03005658 def testReplaceFitSubentryLeafSameSize(self):
5659 """Test replacing a FIT leaf subentry with same-size data"""
5660 new_data = b'x' * len(U_BOOT_DATA)
5661 data, expected_fdtmap, _ = self._RunReplaceCmd(
5662 'fit/kernel/u-boot', new_data,
5663 dts='233_fit_extract_replace.dts')
5664 self.assertEqual(new_data, data)
5665
5666 path, fdtmap = state.GetFdtContents('fdtmap')
5667 self.assertIsNotNone(path)
5668 self.assertEqual(expected_fdtmap, fdtmap)
5669
5670 def testReplaceFitSubentryLeafBiggerSize(self):
5671 """Test replacing a FIT leaf subentry with bigger-size data"""
5672 new_data = b'ub' * len(U_BOOT_NODTB_DATA)
5673 data, expected_fdtmap, _ = self._RunReplaceCmd(
5674 'fit/fdt-1/u-boot-nodtb', new_data,
5675 dts='233_fit_extract_replace.dts')
5676 self.assertEqual(new_data, data)
5677
5678 # Will be repacked, so fdtmap must change
5679 path, fdtmap = state.GetFdtContents('fdtmap')
5680 self.assertIsNotNone(path)
5681 self.assertNotEqual(expected_fdtmap, fdtmap)
5682
5683 def testReplaceFitSubentryLeafSmallerSize(self):
5684 """Test replacing a FIT leaf subentry with smaller-size data"""
5685 new_data = b'x'
5686 expected = new_data.ljust(len(U_BOOT_NODTB_DATA), b'\0')
5687 data, expected_fdtmap, _ = self._RunReplaceCmd(
5688 'fit/fdt-1/u-boot-nodtb', new_data,
5689 dts='233_fit_extract_replace.dts')
5690 self.assertEqual(expected, data)
5691
5692 path, fdtmap = state.GetFdtContents('fdtmap')
5693 self.assertIsNotNone(path)
5694 self.assertEqual(expected_fdtmap, fdtmap)
5695
Alper Nebi Yasak82337bb2022-03-27 18:31:50 +03005696 @unittest.expectedFailure
5697 def testReplaceSectionSimple(self):
5698 """Test replacing a simple section with arbitrary data"""
5699 new_data = b'w' * len(COMPRESS_DATA + U_BOOT_DATA)
5700 data, expected_fdtmap, _ = self._RunReplaceCmd(
5701 'section', new_data,
5702 dts='234_replace_section_simple.dts')
5703 self.assertEqual(new_data, data)
5704
Alper Nebi Yasak8ee4ec92022-03-27 18:31:45 +03005705
Simon Glass9fc60b42017-11-12 21:52:22 -07005706if __name__ == "__main__":
5707 unittest.main()