blob: 179326c42a3eefc6e40df04adb0ceadd9cc22408 [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
20
Simon Glass386c63c2022-01-09 20:13:50 -070021from binman import bintool
Simon Glass16287932020-04-17 18:09:03 -060022from binman import cbfs_util
23from binman import cmdline
24from binman import control
25from binman import elf
26from binman import elf_test
Simon Glass75989722021-11-23 21:08:59 -070027from binman import fip_util
Simon Glass16287932020-04-17 18:09:03 -060028from binman import fmap_util
Simon Glass16287932020-04-17 18:09:03 -060029from binman import state
30from dtoc import fdt
31from dtoc import fdt_util
32from binman.etype import fdtmap
33from binman.etype import image_header
Simon Glass07237982020-08-05 13:27:47 -060034from binman.image import Image
Simon Glassbf776672020-04-17 18:09:04 -060035from patman import command
36from patman import test_util
37from patman import tools
38from patman import tout
Simon Glass4f443042016-11-25 20:15:52 -070039
40# Contents of test files, corresponding to different entry types
Simon Glassc6c10e72019-05-17 22:00:46 -060041U_BOOT_DATA = b'1234'
42U_BOOT_IMG_DATA = b'img'
Simon Glasseb0086f2019-08-24 07:23:04 -060043U_BOOT_SPL_DATA = b'56780123456789abcdefghi'
44U_BOOT_TPL_DATA = b'tpl9876543210fedcbazyw'
Simon Glassc6c10e72019-05-17 22:00:46 -060045BLOB_DATA = b'89'
46ME_DATA = b'0abcd'
47VGA_DATA = b'vga'
48U_BOOT_DTB_DATA = b'udtb'
49U_BOOT_SPL_DTB_DATA = b'spldtb'
50U_BOOT_TPL_DTB_DATA = b'tpldtb'
51X86_START16_DATA = b'start16'
52X86_START16_SPL_DATA = b'start16spl'
53X86_START16_TPL_DATA = b'start16tpl'
Simon Glass2250ee62019-08-24 07:22:48 -060054X86_RESET16_DATA = b'reset16'
55X86_RESET16_SPL_DATA = b'reset16spl'
56X86_RESET16_TPL_DATA = b'reset16tpl'
Simon Glassc6c10e72019-05-17 22:00:46 -060057PPC_MPC85XX_BR_DATA = b'ppcmpc85xxbr'
58U_BOOT_NODTB_DATA = b'nodtb with microcode pointer somewhere in here'
59U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here'
60U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here'
61FSP_DATA = b'fsp'
62CMC_DATA = b'cmc'
63VBT_DATA = b'vbt'
64MRC_DATA = b'mrc'
Simon Glassbb748372018-07-17 13:25:33 -060065TEXT_DATA = 'text'
66TEXT_DATA2 = 'text2'
67TEXT_DATA3 = 'text3'
Simon Glassc6c10e72019-05-17 22:00:46 -060068CROS_EC_RW_DATA = b'ecrw'
69GBB_DATA = b'gbbd'
70BMPBLK_DATA = b'bmp'
71VBLOCK_DATA = b'vblk'
72FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
73 b"sorry you're alive\n")
Simon Glassff5c7e32019-07-08 13:18:42 -060074COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
Simon Glass8f5ef892020-10-26 17:40:25 -060075COMPRESS_DATA_BIG = COMPRESS_DATA * 2
Simon Glassc6c10e72019-05-17 22:00:46 -060076REFCODE_DATA = b'refcode'
Simon Glassea0fff92019-08-24 07:23:07 -060077FSP_M_DATA = b'fsp_m'
Simon Glassbc6a88f2019-10-20 21:31:35 -060078FSP_S_DATA = b'fsp_s'
Simon Glass998d1482019-10-20 21:31:36 -060079FSP_T_DATA = b'fsp_t'
Simon Glassdc2f81a2020-09-01 05:13:58 -060080ATF_BL31_DATA = b'bl31'
Simon Glass75989722021-11-23 21:08:59 -070081ATF_BL2U_DATA = b'bl2u'
Bin Meng4c4d6072021-05-10 20:23:33 +080082OPENSBI_DATA = b'opensbi'
Samuel Holland18bd4552020-10-21 21:12:15 -050083SCP_DATA = b'scp'
Simon Glass6cf99532020-09-01 05:13:59 -060084TEST_FDT1_DATA = b'fdt1'
85TEST_FDT2_DATA = b'test-fdt2'
Simon Glassfb91d562020-09-06 10:35:33 -060086ENV_DATA = b'var1=1\nvar2="2"'
Simon Glass6cf99532020-09-01 05:13:59 -060087
88# Subdirectory of the input dir to use to put test FDTs
89TEST_FDT_SUBDIR = 'fdts'
Simon Glassec127af2018-07-17 13:25:39 -060090
Simon Glass6ccbfcd2019-07-20 12:23:47 -060091# The expected size for the device tree in some tests
Simon Glassf667e452019-07-08 14:25:50 -060092EXTRACT_DTB_SIZE = 0x3c9
93
Simon Glass6ccbfcd2019-07-20 12:23:47 -060094# Properties expected to be in the device tree when update_dtb is used
95BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
96
Simon Glass12bb1a92019-07-20 12:23:51 -060097# Extra properties expected to be in the device tree when allow-repack is used
98REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
99
Simon Glass4f443042016-11-25 20:15:52 -0700100
101class TestFunctional(unittest.TestCase):
102 """Functional tests for binman
103
104 Most of these use a sample .dts file to build an image and then check
105 that it looks correct. The sample files are in the test/ subdirectory
106 and are numbered.
107
108 For each entry type a very small test file is created using fixed
109 string contents. This makes it easy to test that things look right, and
110 debug problems.
111
112 In some cases a 'real' file must be used - these are also supplied in
113 the test/ diurectory.
114 """
115 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600116 def setUpClass(cls):
Simon Glass4d5994f2017-11-12 21:52:20 -0700117 global entry
Simon Glass16287932020-04-17 18:09:03 -0600118 from binman import entry
Simon Glass4d5994f2017-11-12 21:52:20 -0700119
Simon Glass4f443042016-11-25 20:15:52 -0700120 # Handle the case where argv[0] is 'python'
Simon Glassb986b3b2019-08-24 07:22:43 -0600121 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
122 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
Simon Glass4f443042016-11-25 20:15:52 -0700123
124 # Create a temporary directory for input files
Simon Glassb986b3b2019-08-24 07:22:43 -0600125 cls._indir = tempfile.mkdtemp(prefix='binmant.')
Simon Glass4f443042016-11-25 20:15:52 -0700126
127 # Create some test files
128 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
129 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
130 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glassb8ef5b62018-07-17 13:25:48 -0600131 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700132 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -0700133 TestFunctional._MakeInputFile('me.bin', ME_DATA)
134 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glassb986b3b2019-08-24 07:22:43 -0600135 cls._ResetDtbs()
Simon Glass2250ee62019-08-24 07:22:48 -0600136
Jagdish Gediya9d368f32018-09-03 21:35:08 +0530137 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glass2250ee62019-08-24 07:22:48 -0600138
Simon Glass5e239182019-08-24 07:22:49 -0600139 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
140 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
Simon Glass87722132017-11-12 21:52:26 -0700141 X86_START16_SPL_DATA)
Simon Glass5e239182019-08-24 07:22:49 -0600142 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
Simon Glass35b384c2018-09-14 04:57:10 -0600143 X86_START16_TPL_DATA)
Simon Glass2250ee62019-08-24 07:22:48 -0600144
145 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
146 X86_RESET16_DATA)
147 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
148 X86_RESET16_SPL_DATA)
149 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
150 X86_RESET16_TPL_DATA)
151
Simon Glass4f443042016-11-25 20:15:52 -0700152 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass6b187df2017-11-12 21:52:27 -0700153 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
154 U_BOOT_SPL_NODTB_DATA)
Simon Glassf0253632018-09-14 04:57:32 -0600155 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
156 U_BOOT_TPL_NODTB_DATA)
Simon Glassda229092016-11-25 20:15:56 -0700157 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
158 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Meng59ea8c22017-08-15 22:41:54 -0700159 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassca4f4ff2017-11-12 21:52:28 -0700160 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassec127af2018-07-17 13:25:39 -0600161 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glass0ef87aa2018-07-17 13:25:44 -0600162 TestFunctional._MakeInputDir('devkeys')
163 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass3ae192c2018-10-01 12:22:31 -0600164 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glassea0fff92019-08-24 07:23:07 -0600165 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
Simon Glassbc6a88f2019-10-20 21:31:35 -0600166 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
Simon Glass998d1482019-10-20 21:31:36 -0600167 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700168
Simon Glass53e22bf2019-08-24 07:22:53 -0600169 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
170 elf_test.BuildElfTestFiles(cls._elf_testdir)
171
Simon Glasse0ff8552016-11-25 20:15:53 -0700172 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glassf514d8f2019-08-24 07:22:54 -0600173 TestFunctional._MakeInputFile('u-boot',
174 tools.ReadFile(cls.ElfTestFile('u_boot_ucode_ptr')))
Simon Glasse0ff8552016-11-25 20:15:53 -0700175
176 # Intel flash descriptor file
Simon Glass0ba4b3d2020-07-09 18:39:41 -0600177 cls._SetupDescriptor()
Simon Glasse0ff8552016-11-25 20:15:53 -0700178
Simon Glassb986b3b2019-08-24 07:22:43 -0600179 shutil.copytree(cls.TestFile('files'),
180 os.path.join(cls._indir, 'files'))
Simon Glass0a98b282018-09-14 04:57:28 -0600181
Simon Glass83d73c22018-09-14 04:57:26 -0600182 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
Simon Glass8f5ef892020-10-26 17:40:25 -0600183 TestFunctional._MakeInputFile('compress_big', COMPRESS_DATA_BIG)
Simon Glassdc2f81a2020-09-01 05:13:58 -0600184 TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
Simon Glass75989722021-11-23 21:08:59 -0700185 TestFunctional._MakeInputFile('bl2u.bin', ATF_BL2U_DATA)
Bin Meng4c4d6072021-05-10 20:23:33 +0800186 TestFunctional._MakeInputFile('fw_dynamic.bin', OPENSBI_DATA)
Samuel Holland18bd4552020-10-21 21:12:15 -0500187 TestFunctional._MakeInputFile('scp.bin', SCP_DATA)
Simon Glass83d73c22018-09-14 04:57:26 -0600188
Simon Glass6cf99532020-09-01 05:13:59 -0600189 # Add a few .dtb files for testing
190 TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR,
191 TEST_FDT1_DATA)
192 TestFunctional._MakeInputFile('%s/test-fdt2.dtb' % TEST_FDT_SUBDIR,
193 TEST_FDT2_DATA)
194
Simon Glassfb91d562020-09-06 10:35:33 -0600195 TestFunctional._MakeInputFile('env.txt', ENV_DATA)
196
Simon Glassac62fba2019-07-08 13:18:53 -0600197 # Travis-CI may have an old lz4
Simon Glassb986b3b2019-08-24 07:22:43 -0600198 cls.have_lz4 = True
Simon Glassac62fba2019-07-08 13:18:53 -0600199 try:
200 tools.Run('lz4', '--no-frame-crc', '-c',
Simon Glass3b3e3c02019-10-31 07:42:50 -0600201 os.path.join(cls._indir, 'u-boot.bin'), binary=True)
Simon Glassac62fba2019-07-08 13:18:53 -0600202 except:
Simon Glassb986b3b2019-08-24 07:22:43 -0600203 cls.have_lz4 = False
Simon Glassac62fba2019-07-08 13:18:53 -0600204
Simon Glass4f443042016-11-25 20:15:52 -0700205 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600206 def tearDownClass(cls):
Simon Glass4f443042016-11-25 20:15:52 -0700207 """Remove the temporary input directory and its contents"""
Simon Glassb986b3b2019-08-24 07:22:43 -0600208 if cls.preserve_indir:
209 print('Preserving input dir: %s' % cls._indir)
Simon Glassd5164a72019-07-08 13:18:49 -0600210 else:
Simon Glassb986b3b2019-08-24 07:22:43 -0600211 if cls._indir:
212 shutil.rmtree(cls._indir)
213 cls._indir = None
Simon Glass4f443042016-11-25 20:15:52 -0700214
Simon Glassd5164a72019-07-08 13:18:49 -0600215 @classmethod
Simon Glass8acce602019-07-08 13:18:50 -0600216 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
Simon Glass53cd5d92019-07-08 14:25:29 -0600217 toolpath=None, verbosity=None):
Simon Glassd5164a72019-07-08 13:18:49 -0600218 """Accept arguments controlling test execution
219
220 Args:
221 preserve_indir: Preserve the shared input directory used by all
222 tests in this class.
223 preserve_outdir: Preserve the output directories used by tests. Each
224 test has its own, so this is normally only useful when running a
225 single test.
Simon Glass8acce602019-07-08 13:18:50 -0600226 toolpath: ist of paths to use for tools
Simon Glassd5164a72019-07-08 13:18:49 -0600227 """
228 cls.preserve_indir = preserve_indir
229 cls.preserve_outdirs = preserve_outdirs
Simon Glass8acce602019-07-08 13:18:50 -0600230 cls.toolpath = toolpath
Simon Glass53cd5d92019-07-08 14:25:29 -0600231 cls.verbosity = verbosity
Simon Glassd5164a72019-07-08 13:18:49 -0600232
Simon Glassac62fba2019-07-08 13:18:53 -0600233 def _CheckLz4(self):
234 if not self.have_lz4:
235 self.skipTest('lz4 --no-frame-crc not available')
236
Simon Glassbf574f12019-07-20 12:24:09 -0600237 def _CleanupOutputDir(self):
238 """Remove the temporary output directory"""
239 if self.preserve_outdirs:
240 print('Preserving output dir: %s' % tools.outdir)
241 else:
242 tools._FinaliseForTest()
243
Simon Glass4f443042016-11-25 20:15:52 -0700244 def setUp(self):
245 # Enable this to turn on debugging output
246 # tout.Init(tout.DEBUG)
247 command.test_result = None
248
249 def tearDown(self):
250 """Remove the temporary output directory"""
Simon Glassbf574f12019-07-20 12:24:09 -0600251 self._CleanupOutputDir()
Simon Glass4f443042016-11-25 20:15:52 -0700252
Simon Glassf86a7362019-07-20 12:24:10 -0600253 def _SetupImageInTmpdir(self):
254 """Set up the output image in a new temporary directory
255
256 This is used when an image has been generated in the output directory,
257 but we want to run binman again. This will create a new output
258 directory and fail to delete the original one.
259
260 This creates a new temporary directory, copies the image to it (with a
261 new name) and removes the old output directory.
262
263 Returns:
264 Tuple:
265 Temporary directory to use
266 New image filename
267 """
268 image_fname = tools.GetOutputFilename('image.bin')
269 tmpdir = tempfile.mkdtemp(prefix='binman.')
270 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
271 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
272 self._CleanupOutputDir()
273 return tmpdir, updated_fname
274
Simon Glassb8ef5b62018-07-17 13:25:48 -0600275 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600276 def _ResetDtbs(cls):
Simon Glassb8ef5b62018-07-17 13:25:48 -0600277 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
278 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
279 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
280
Simon Glass4f443042016-11-25 20:15:52 -0700281 def _RunBinman(self, *args, **kwargs):
282 """Run binman using the command line
283
284 Args:
285 Arguments to pass, as a list of strings
286 kwargs: Arguments to pass to Command.RunPipe()
287 """
288 result = command.RunPipe([[self._binman_pathname] + list(args)],
289 capture=True, capture_stderr=True, raise_on_error=False)
290 if result.return_code and kwargs.get('raise_on_error', True):
291 raise Exception("Error running '%s': %s" % (' '.join(args),
292 result.stdout + result.stderr))
293 return result
294
Simon Glass53cd5d92019-07-08 14:25:29 -0600295 def _DoBinman(self, *argv):
Simon Glass4f443042016-11-25 20:15:52 -0700296 """Run binman using directly (in the same process)
297
298 Args:
299 Arguments to pass, as a list of strings
300 Returns:
301 Return value (0 for success)
302 """
Simon Glass53cd5d92019-07-08 14:25:29 -0600303 argv = list(argv)
304 args = cmdline.ParseArgs(argv)
305 args.pager = 'binman-invalid-pager'
306 args.build_dir = self._indir
Simon Glass4f443042016-11-25 20:15:52 -0700307
308 # For testing, you can force an increase in verbosity here
Simon Glass53cd5d92019-07-08 14:25:29 -0600309 # args.verbosity = tout.DEBUG
310 return control.Binman(args)
Simon Glass4f443042016-11-25 20:15:52 -0700311
Simon Glass53af22a2018-07-17 13:25:32 -0600312 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glasseb833d82019-04-25 21:58:34 -0600313 entry_args=None, images=None, use_real_dtb=False,
Simon Glass63aeaeb2021-03-18 20:25:05 +1300314 use_expanded=False, verbosity=None, allow_missing=False,
Heiko Thierya89c8f22022-01-06 11:49:41 +0100315 allow_fake_blobs=False, extra_indirs=None, threads=None,
Simon Glass0427bed2021-11-03 21:09:18 -0600316 test_section_timeout=False, update_fdt_in_elf=None):
Simon Glass4f443042016-11-25 20:15:52 -0700317 """Run binman with a given test file
318
319 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600320 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600321 debug: True to enable debugging output
Simon Glass3b0c3822018-06-01 09:38:20 -0600322 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600323 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600324 tree before packing it into the image
Simon Glass0bfa7b02018-09-14 04:57:12 -0600325 entry_args: Dict of entry args to supply to binman
326 key: arg name
327 value: value of that arg
328 images: List of image names to build
Simon Glasse9d336d2020-09-01 05:13:55 -0600329 use_real_dtb: True to use the test file as the contents of
330 the u-boot-dtb entry. Normally this is not needed and the
331 test contents (the U_BOOT_DTB_DATA string) can be used.
332 But in some test we need the real contents.
Simon Glass63aeaeb2021-03-18 20:25:05 +1300333 use_expanded: True to use expanded entries where available, e.g.
334 'u-boot-expanded' instead of 'u-boot'
Simon Glasse9d336d2020-09-01 05:13:55 -0600335 verbosity: Verbosity level to use (0-3, None=don't set it)
336 allow_missing: Set the '--allow-missing' flag so that missing
337 external binaries just produce a warning instead of an error
Heiko Thierya89c8f22022-01-06 11:49:41 +0100338 allow_fake_blobs: Set the '--fake-ext-blobs' flag
Simon Glass6cf99532020-09-01 05:13:59 -0600339 extra_indirs: Extra input directories to add using -I
Simon Glassc69d19c2021-07-06 10:36:37 -0600340 threads: Number of threads to use (None for default, 0 for
341 single-threaded)
Simon Glass7115f002021-11-03 21:09:17 -0600342 test_section_timeout: True to force the first time to timeout, as
343 used in testThreadTimeout()
Simon Glass0427bed2021-11-03 21:09:18 -0600344 update_fdt_in_elf: Value to pass with --update-fdt-in-elf=xxx
Simon Glass7115f002021-11-03 21:09:17 -0600345
346 Returns:
347 int return code, 0 on success
Simon Glass4f443042016-11-25 20:15:52 -0700348 """
Simon Glass53cd5d92019-07-08 14:25:29 -0600349 args = []
Simon Glass7fe91732017-11-13 18:55:00 -0700350 if debug:
351 args.append('-D')
Simon Glass53cd5d92019-07-08 14:25:29 -0600352 if verbosity is not None:
353 args.append('-v%d' % verbosity)
354 elif self.verbosity:
355 args.append('-v%d' % self.verbosity)
356 if self.toolpath:
357 for path in self.toolpath:
358 args += ['--toolpath', path]
Simon Glassc69d19c2021-07-06 10:36:37 -0600359 if threads is not None:
360 args.append('-T%d' % threads)
361 if test_section_timeout:
362 args.append('--test-section-timeout')
Simon Glass53cd5d92019-07-08 14:25:29 -0600363 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass3b0c3822018-06-01 09:38:20 -0600364 if map:
365 args.append('-m')
Simon Glass16b8d6b2018-07-06 10:27:42 -0600366 if update_dtb:
Simon Glass2569e102019-07-08 13:18:47 -0600367 args.append('-u')
Simon Glass93d17412018-09-14 04:57:23 -0600368 if not use_real_dtb:
369 args.append('--fake-dtb')
Simon Glass63aeaeb2021-03-18 20:25:05 +1300370 if not use_expanded:
371 args.append('--no-expanded')
Simon Glass53af22a2018-07-17 13:25:32 -0600372 if entry_args:
Simon Glass50979152019-05-14 15:53:41 -0600373 for arg, value in entry_args.items():
Simon Glass53af22a2018-07-17 13:25:32 -0600374 args.append('-a%s=%s' % (arg, value))
Simon Glass4f9f1052020-07-09 18:39:38 -0600375 if allow_missing:
376 args.append('-M')
Heiko Thierya89c8f22022-01-06 11:49:41 +0100377 if allow_fake_blobs:
378 args.append('--fake-ext-blobs')
Simon Glass0427bed2021-11-03 21:09:18 -0600379 if update_fdt_in_elf:
380 args += ['--update-fdt-in-elf', update_fdt_in_elf]
Simon Glass0bfa7b02018-09-14 04:57:12 -0600381 if images:
382 for image in images:
383 args += ['-i', image]
Simon Glass6cf99532020-09-01 05:13:59 -0600384 if extra_indirs:
385 for indir in extra_indirs:
386 args += ['-I', indir]
Simon Glass7fe91732017-11-13 18:55:00 -0700387 return self._DoBinman(*args)
Simon Glass4f443042016-11-25 20:15:52 -0700388
389 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glasse0ff8552016-11-25 20:15:53 -0700390 """Set up a new test device-tree file
391
392 The given file is compiled and set up as the device tree to be used
393 for ths test.
394
395 Args:
396 fname: Filename of .dts file to read
Simon Glass7ae5f312018-06-01 09:38:19 -0600397 outfile: Output filename for compiled device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700398
399 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600400 Contents of device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700401 """
Simon Glassa004f292019-07-20 12:23:49 -0600402 tmpdir = tempfile.mkdtemp(prefix='binmant.')
403 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
Simon Glass1d0ebf72019-05-14 15:53:42 -0600404 with open(dtb, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700405 data = fd.read()
406 TestFunctional._MakeInputFile(outfile, data)
Simon Glassa004f292019-07-20 12:23:49 -0600407 shutil.rmtree(tmpdir)
Simon Glasse0e62752018-10-01 21:12:41 -0600408 return data
Simon Glass4f443042016-11-25 20:15:52 -0700409
Simon Glass6ed45ba2018-09-14 04:57:24 -0600410 def _GetDtbContentsForSplTpl(self, dtb_data, name):
411 """Create a version of the main DTB for SPL or SPL
412
413 For testing we don't actually have different versions of the DTB. With
414 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
415 we don't normally have any unwanted nodes.
416
417 We still want the DTBs for SPL and TPL to be different though, since
418 otherwise it is confusing to know which one we are looking at. So add
419 an 'spl' or 'tpl' property to the top-level node.
Simon Glasse9d336d2020-09-01 05:13:55 -0600420
421 Args:
422 dtb_data: dtb data to modify (this should be a value devicetree)
423 name: Name of a new property to add
424
425 Returns:
426 New dtb data with the property added
Simon Glass6ed45ba2018-09-14 04:57:24 -0600427 """
428 dtb = fdt.Fdt.FromData(dtb_data)
429 dtb.Scan()
430 dtb.GetNode('/binman').AddZeroProp(name)
431 dtb.Sync(auto_resize=True)
432 dtb.Pack()
433 return dtb.GetContents()
434
Simon Glass63aeaeb2021-03-18 20:25:05 +1300435 def _DoReadFileDtb(self, fname, use_real_dtb=False, use_expanded=False,
436 map=False, update_dtb=False, entry_args=None,
Simon Glassc69d19c2021-07-06 10:36:37 -0600437 reset_dtbs=True, extra_indirs=None, threads=None):
Simon Glass4f443042016-11-25 20:15:52 -0700438 """Run binman and return the resulting image
439
440 This runs binman with a given test file and then reads the resulting
441 output file. It is a shortcut function since most tests need to do
442 these steps.
443
444 Raises an assertion failure if binman returns a non-zero exit code.
445
446 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600447 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass4f443042016-11-25 20:15:52 -0700448 use_real_dtb: True to use the test file as the contents of
449 the u-boot-dtb entry. Normally this is not needed and the
450 test contents (the U_BOOT_DTB_DATA string) can be used.
451 But in some test we need the real contents.
Simon Glass63aeaeb2021-03-18 20:25:05 +1300452 use_expanded: True to use expanded entries where available, e.g.
453 'u-boot-expanded' instead of 'u-boot'
Simon Glass3b0c3822018-06-01 09:38:20 -0600454 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600455 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600456 tree before packing it into the image
Simon Glasse9d336d2020-09-01 05:13:55 -0600457 entry_args: Dict of entry args to supply to binman
458 key: arg name
459 value: value of that arg
460 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
461 function. If reset_dtbs is True, then the original test dtb
462 is written back before this function finishes
Simon Glass6cf99532020-09-01 05:13:59 -0600463 extra_indirs: Extra input directories to add using -I
Simon Glassc69d19c2021-07-06 10:36:37 -0600464 threads: Number of threads to use (None for default, 0 for
465 single-threaded)
Simon Glasse0ff8552016-11-25 20:15:53 -0700466
467 Returns:
468 Tuple:
469 Resulting image contents
470 Device tree contents
Simon Glass3b0c3822018-06-01 09:38:20 -0600471 Map data showing contents of image (or None if none)
Simon Glassea6922e2018-07-17 13:25:27 -0600472 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass4f443042016-11-25 20:15:52 -0700473 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700474 dtb_data = None
Simon Glass4f443042016-11-25 20:15:52 -0700475 # Use the compiled test file as the u-boot-dtb input
476 if use_real_dtb:
Simon Glasse0ff8552016-11-25 20:15:53 -0700477 dtb_data = self._SetupDtb(fname)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600478
479 # For testing purposes, make a copy of the DT for SPL and TPL. Add
480 # a node indicating which it is, so aid verification.
481 for name in ['spl', 'tpl']:
482 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
483 outfile = os.path.join(self._indir, dtb_fname)
484 TestFunctional._MakeInputFile(dtb_fname,
485 self._GetDtbContentsForSplTpl(dtb_data, name))
Simon Glass4f443042016-11-25 20:15:52 -0700486
487 try:
Simon Glass53af22a2018-07-17 13:25:32 -0600488 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glass6cf99532020-09-01 05:13:59 -0600489 entry_args=entry_args, use_real_dtb=use_real_dtb,
Simon Glassc69d19c2021-07-06 10:36:37 -0600490 use_expanded=use_expanded, extra_indirs=extra_indirs,
491 threads=threads)
Simon Glass4f443042016-11-25 20:15:52 -0700492 self.assertEqual(0, retcode)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600493 out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
Simon Glass4f443042016-11-25 20:15:52 -0700494
495 # Find the (only) image, read it and return its contents
496 image = control.images['image']
Simon Glass16b8d6b2018-07-06 10:27:42 -0600497 image_fname = tools.GetOutputFilename('image.bin')
498 self.assertTrue(os.path.exists(image_fname))
Simon Glass3b0c3822018-06-01 09:38:20 -0600499 if map:
500 map_fname = tools.GetOutputFilename('image.map')
501 with open(map_fname) as fd:
502 map_data = fd.read()
503 else:
504 map_data = None
Simon Glass1d0ebf72019-05-14 15:53:42 -0600505 with open(image_fname, 'rb') as fd:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600506 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass4f443042016-11-25 20:15:52 -0700507 finally:
508 # Put the test file back
Simon Glass6ed45ba2018-09-14 04:57:24 -0600509 if reset_dtbs and use_real_dtb:
Simon Glassb8ef5b62018-07-17 13:25:48 -0600510 self._ResetDtbs()
Simon Glass4f443042016-11-25 20:15:52 -0700511
Simon Glass3c081312019-07-08 14:25:26 -0600512 def _DoReadFileRealDtb(self, fname):
513 """Run binman with a real .dtb file and return the resulting data
514
515 Args:
516 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
517
518 Returns:
519 Resulting image contents
520 """
521 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
522
Simon Glasse0ff8552016-11-25 20:15:53 -0700523 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass7ae5f312018-06-01 09:38:19 -0600524 """Helper function which discards the device-tree binary
525
526 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600527 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600528 use_real_dtb: True to use the test file as the contents of
529 the u-boot-dtb entry. Normally this is not needed and the
530 test contents (the U_BOOT_DTB_DATA string) can be used.
531 But in some test we need the real contents.
Simon Glassea6922e2018-07-17 13:25:27 -0600532
533 Returns:
534 Resulting image contents
Simon Glass7ae5f312018-06-01 09:38:19 -0600535 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700536 return self._DoReadFileDtb(fname, use_real_dtb)[0]
537
Simon Glass4f443042016-11-25 20:15:52 -0700538 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600539 def _MakeInputFile(cls, fname, contents):
Simon Glass4f443042016-11-25 20:15:52 -0700540 """Create a new test input file, creating directories as needed
541
542 Args:
Simon Glass3ab95982018-08-01 15:22:37 -0600543 fname: Filename to create
Simon Glass4f443042016-11-25 20:15:52 -0700544 contents: File contents to write in to the file
545 Returns:
546 Full pathname of file created
547 """
Simon Glassb986b3b2019-08-24 07:22:43 -0600548 pathname = os.path.join(cls._indir, fname)
Simon Glass4f443042016-11-25 20:15:52 -0700549 dirname = os.path.dirname(pathname)
550 if dirname and not os.path.exists(dirname):
551 os.makedirs(dirname)
552 with open(pathname, 'wb') as fd:
553 fd.write(contents)
554 return pathname
555
556 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600557 def _MakeInputDir(cls, dirname):
Simon Glass0ef87aa2018-07-17 13:25:44 -0600558 """Create a new test input directory, creating directories as needed
559
560 Args:
561 dirname: Directory name to create
562
563 Returns:
564 Full pathname of directory created
565 """
Simon Glassb986b3b2019-08-24 07:22:43 -0600566 pathname = os.path.join(cls._indir, dirname)
Simon Glass0ef87aa2018-07-17 13:25:44 -0600567 if not os.path.exists(pathname):
568 os.makedirs(pathname)
569 return pathname
570
571 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600572 def _SetupSplElf(cls, src_fname='bss_data'):
Simon Glass11ae93e2018-10-01 21:12:47 -0600573 """Set up an ELF file with a '_dt_ucode_base_size' symbol
574
575 Args:
576 Filename of ELF file to use as SPL
577 """
Simon Glassc9a0b272019-08-24 07:22:59 -0600578 TestFunctional._MakeInputFile('spl/u-boot-spl',
579 tools.ReadFile(cls.ElfTestFile(src_fname)))
Simon Glass11ae93e2018-10-01 21:12:47 -0600580
581 @classmethod
Simon Glass2090f1e2019-08-24 07:23:00 -0600582 def _SetupTplElf(cls, src_fname='bss_data'):
583 """Set up an ELF file with a '_dt_ucode_base_size' symbol
584
585 Args:
586 Filename of ELF file to use as TPL
587 """
588 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
589 tools.ReadFile(cls.ElfTestFile(src_fname)))
590
591 @classmethod
Simon Glass0ba4b3d2020-07-09 18:39:41 -0600592 def _SetupDescriptor(cls):
593 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
594 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
595
596 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600597 def TestFile(cls, fname):
598 return os.path.join(cls._binman_dir, 'test', fname)
Simon Glass4f443042016-11-25 20:15:52 -0700599
Simon Glass53e22bf2019-08-24 07:22:53 -0600600 @classmethod
601 def ElfTestFile(cls, fname):
602 return os.path.join(cls._elf_testdir, fname)
603
Simon Glass4f443042016-11-25 20:15:52 -0700604 def AssertInList(self, grep_list, target):
605 """Assert that at least one of a list of things is in a target
606
607 Args:
608 grep_list: List of strings to check
609 target: Target string
610 """
611 for grep in grep_list:
612 if grep in target:
613 return
Simon Glass1fc62de2019-05-17 22:00:50 -0600614 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass4f443042016-11-25 20:15:52 -0700615
616 def CheckNoGaps(self, entries):
617 """Check that all entries fit together without gaps
618
619 Args:
620 entries: List of entries to check
621 """
Simon Glass3ab95982018-08-01 15:22:37 -0600622 offset = 0
Simon Glass4f443042016-11-25 20:15:52 -0700623 for entry in entries.values():
Simon Glass3ab95982018-08-01 15:22:37 -0600624 self.assertEqual(offset, entry.offset)
625 offset += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700626
Simon Glasse0ff8552016-11-25 20:15:53 -0700627 def GetFdtLen(self, dtb):
Simon Glass7ae5f312018-06-01 09:38:19 -0600628 """Get the totalsize field from a device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700629
630 Args:
Simon Glass7ae5f312018-06-01 09:38:19 -0600631 dtb: Device-tree binary contents
Simon Glasse0ff8552016-11-25 20:15:53 -0700632
633 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600634 Total size of device-tree binary, from the header
Simon Glasse0ff8552016-11-25 20:15:53 -0700635 """
636 return struct.unpack('>L', dtb[4:8])[0]
637
Simon Glass086cec92019-07-08 14:25:27 -0600638 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glass16b8d6b2018-07-06 10:27:42 -0600639 def AddNode(node, path):
640 if node.name != '/':
641 path += '/' + node.name
Simon Glass086cec92019-07-08 14:25:27 -0600642 for prop in node.props.values():
643 if prop.name in prop_names:
644 prop_path = path + ':' + prop.name
645 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
646 prop.value)
Simon Glass16b8d6b2018-07-06 10:27:42 -0600647 for subnode in node.subnodes:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600648 AddNode(subnode, path)
649
650 tree = {}
Simon Glass16b8d6b2018-07-06 10:27:42 -0600651 AddNode(dtb.GetRoot(), '')
652 return tree
653
Simon Glass4f443042016-11-25 20:15:52 -0700654 def testRun(self):
655 """Test a basic run with valid args"""
656 result = self._RunBinman('-h')
657
658 def testFullHelp(self):
659 """Test that the full help is displayed with -H"""
660 result = self._RunBinman('-H')
Simon Glass61adb2d2021-03-18 20:25:13 +1300661 help_file = os.path.join(self._binman_dir, 'README.rst')
Tom Rini3759df02018-01-16 15:29:50 -0500662 # Remove possible extraneous strings
663 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
664 gothelp = result.stdout.replace(extra, '')
665 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass4f443042016-11-25 20:15:52 -0700666 self.assertEqual(0, len(result.stderr))
667 self.assertEqual(0, result.return_code)
668
669 def testFullHelpInternal(self):
670 """Test that the full help is displayed with -H"""
671 try:
672 command.test_result = command.CommandResult()
673 result = self._DoBinman('-H')
Simon Glass61adb2d2021-03-18 20:25:13 +1300674 help_file = os.path.join(self._binman_dir, 'README.rst')
Simon Glass4f443042016-11-25 20:15:52 -0700675 finally:
676 command.test_result = None
677
678 def testHelp(self):
679 """Test that the basic help is displayed with -h"""
680 result = self._RunBinman('-h')
681 self.assertTrue(len(result.stdout) > 200)
682 self.assertEqual(0, len(result.stderr))
683 self.assertEqual(0, result.return_code)
684
Simon Glass4f443042016-11-25 20:15:52 -0700685 def testBoard(self):
686 """Test that we can run it with a specific board"""
Simon Glass741f2d62018-10-01 12:22:30 -0600687 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass4f443042016-11-25 20:15:52 -0700688 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glass63aeaeb2021-03-18 20:25:05 +1300689 result = self._DoBinman('build', '-n', '-b', 'sandbox')
Simon Glass4f443042016-11-25 20:15:52 -0700690 self.assertEqual(0, result)
691
692 def testNeedBoard(self):
693 """Test that we get an error when no board ius supplied"""
694 with self.assertRaises(ValueError) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600695 result = self._DoBinman('build')
Simon Glass4f443042016-11-25 20:15:52 -0700696 self.assertIn("Must provide a board to process (use -b <board>)",
697 str(e.exception))
698
699 def testMissingDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600700 """Test that an invalid device-tree file generates an error"""
Simon Glass4f443042016-11-25 20:15:52 -0700701 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600702 self._RunBinman('build', '-d', 'missing_file')
Simon Glass4f443042016-11-25 20:15:52 -0700703 # We get one error from libfdt, and a different one from fdtget.
704 self.AssertInList(["Couldn't open blob from 'missing_file'",
705 'No such file or directory'], str(e.exception))
706
707 def testBrokenDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600708 """Test that an invalid device-tree source file generates an error
Simon Glass4f443042016-11-25 20:15:52 -0700709
710 Since this is a source file it should be compiled and the error
711 will come from the device-tree compiler (dtc).
712 """
713 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600714 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700715 self.assertIn("FATAL ERROR: Unable to parse input tree",
716 str(e.exception))
717
718 def testMissingNode(self):
719 """Test that a device tree without a 'binman' node generates an error"""
720 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600721 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700722 self.assertIn("does not have a 'binman' node", str(e.exception))
723
724 def testEmpty(self):
725 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glass53cd5d92019-07-08 14:25:29 -0600726 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700727 self.assertEqual(0, len(result.stderr))
728 self.assertEqual(0, result.return_code)
729
730 def testInvalidEntry(self):
731 """Test that an invalid entry is flagged"""
732 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600733 result = self._RunBinman('build', '-d',
Simon Glass741f2d62018-10-01 12:22:30 -0600734 self.TestFile('004_invalid_entry.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700735 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
736 "'/binman/not-a-valid-type'", str(e.exception))
737
738 def testSimple(self):
739 """Test a simple binman with a single file"""
Simon Glass741f2d62018-10-01 12:22:30 -0600740 data = self._DoReadFile('005_simple.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700741 self.assertEqual(U_BOOT_DATA, data)
742
Simon Glass7fe91732017-11-13 18:55:00 -0700743 def testSimpleDebug(self):
744 """Test a simple binman run with debugging enabled"""
Simon Glasse2705fa2019-07-08 14:25:53 -0600745 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass7fe91732017-11-13 18:55:00 -0700746
Simon Glass4f443042016-11-25 20:15:52 -0700747 def testDual(self):
748 """Test that we can handle creating two images
749
750 This also tests image padding.
751 """
Simon Glass741f2d62018-10-01 12:22:30 -0600752 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700753 self.assertEqual(0, retcode)
754
755 image = control.images['image1']
Simon Glass8beb11e2019-07-08 14:25:47 -0600756 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700757 fname = tools.GetOutputFilename('image1.bin')
758 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600759 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700760 data = fd.read()
761 self.assertEqual(U_BOOT_DATA, data)
762
763 image = control.images['image2']
Simon Glass8beb11e2019-07-08 14:25:47 -0600764 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700765 fname = tools.GetOutputFilename('image2.bin')
766 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600767 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700768 data = fd.read()
769 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glasse6d85ff2019-05-14 15:53:47 -0600770 self.assertEqual(tools.GetBytes(0, 3), data[:3])
771 self.assertEqual(tools.GetBytes(0, 5), data[7:])
Simon Glass4f443042016-11-25 20:15:52 -0700772
773 def testBadAlign(self):
774 """Test that an invalid alignment value is detected"""
775 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600776 self._DoTestFile('007_bad_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700777 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
778 "of two", str(e.exception))
779
780 def testPackSimple(self):
781 """Test that packing works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600782 retcode = self._DoTestFile('008_pack.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700783 self.assertEqual(0, retcode)
784 self.assertIn('image', control.images)
785 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600786 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700787 self.assertEqual(5, len(entries))
788
789 # First u-boot
790 self.assertIn('u-boot', entries)
791 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600792 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700793 self.assertEqual(len(U_BOOT_DATA), entry.size)
794
795 # Second u-boot, aligned to 16-byte boundary
796 self.assertIn('u-boot-align', entries)
797 entry = entries['u-boot-align']
Simon Glass3ab95982018-08-01 15:22:37 -0600798 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700799 self.assertEqual(len(U_BOOT_DATA), entry.size)
800
801 # Third u-boot, size 23 bytes
802 self.assertIn('u-boot-size', entries)
803 entry = entries['u-boot-size']
Simon Glass3ab95982018-08-01 15:22:37 -0600804 self.assertEqual(20, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700805 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
806 self.assertEqual(23, entry.size)
807
808 # Fourth u-boot, placed immediate after the above
809 self.assertIn('u-boot-next', entries)
810 entry = entries['u-boot-next']
Simon Glass3ab95982018-08-01 15:22:37 -0600811 self.assertEqual(43, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700812 self.assertEqual(len(U_BOOT_DATA), entry.size)
813
Simon Glass3ab95982018-08-01 15:22:37 -0600814 # Fifth u-boot, placed at a fixed offset
Simon Glass4f443042016-11-25 20:15:52 -0700815 self.assertIn('u-boot-fixed', entries)
816 entry = entries['u-boot-fixed']
Simon Glass3ab95982018-08-01 15:22:37 -0600817 self.assertEqual(61, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700818 self.assertEqual(len(U_BOOT_DATA), entry.size)
819
Simon Glass8beb11e2019-07-08 14:25:47 -0600820 self.assertEqual(65, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700821
822 def testPackExtra(self):
823 """Test that extra packing feature works as expected"""
Simon Glass4eec34c2020-10-26 17:40:10 -0600824 data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
825 update_dtb=True)
Simon Glass4f443042016-11-25 20:15:52 -0700826
Simon Glass4f443042016-11-25 20:15:52 -0700827 self.assertIn('image', control.images)
828 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600829 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700830 self.assertEqual(5, len(entries))
831
832 # First u-boot with padding before and after
833 self.assertIn('u-boot', entries)
834 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600835 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700836 self.assertEqual(3, entry.pad_before)
837 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600838 self.assertEqual(U_BOOT_DATA, entry.data)
839 self.assertEqual(tools.GetBytes(0, 3) + U_BOOT_DATA +
840 tools.GetBytes(0, 5), data[:entry.size])
841 pos = entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700842
843 # Second u-boot has an aligned size, but it has no effect
844 self.assertIn('u-boot-align-size-nop', entries)
845 entry = entries['u-boot-align-size-nop']
Simon Glassef439ed2020-10-26 17:40:08 -0600846 self.assertEqual(pos, entry.offset)
847 self.assertEqual(len(U_BOOT_DATA), entry.size)
848 self.assertEqual(U_BOOT_DATA, entry.data)
849 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
850 pos += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700851
852 # Third u-boot has an aligned size too
853 self.assertIn('u-boot-align-size', entries)
854 entry = entries['u-boot-align-size']
Simon Glassef439ed2020-10-26 17:40:08 -0600855 self.assertEqual(pos, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700856 self.assertEqual(32, entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600857 self.assertEqual(U_BOOT_DATA, entry.data)
858 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 32 - len(U_BOOT_DATA)),
859 data[pos:pos + entry.size])
860 pos += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700861
862 # Fourth u-boot has an aligned end
863 self.assertIn('u-boot-align-end', entries)
864 entry = entries['u-boot-align-end']
Simon Glass3ab95982018-08-01 15:22:37 -0600865 self.assertEqual(48, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700866 self.assertEqual(16, entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600867 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
868 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 16 - len(U_BOOT_DATA)),
869 data[pos:pos + entry.size])
870 pos += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700871
872 # Fifth u-boot immediately afterwards
873 self.assertIn('u-boot-align-both', entries)
874 entry = entries['u-boot-align-both']
Simon Glass3ab95982018-08-01 15:22:37 -0600875 self.assertEqual(64, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700876 self.assertEqual(64, entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600877 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
878 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 64 - len(U_BOOT_DATA)),
879 data[pos:pos + entry.size])
Simon Glass4f443042016-11-25 20:15:52 -0700880
881 self.CheckNoGaps(entries)
Simon Glass8beb11e2019-07-08 14:25:47 -0600882 self.assertEqual(128, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700883
Simon Glass4eec34c2020-10-26 17:40:10 -0600884 dtb = fdt.Fdt(out_dtb_fname)
885 dtb.Scan()
886 props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
887 expected = {
888 'image-pos': 0,
889 'offset': 0,
890 'size': 128,
891
892 'u-boot:image-pos': 0,
893 'u-boot:offset': 0,
894 'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
895
896 'u-boot-align-size-nop:image-pos': 12,
897 'u-boot-align-size-nop:offset': 12,
898 'u-boot-align-size-nop:size': 4,
899
900 'u-boot-align-size:image-pos': 16,
901 'u-boot-align-size:offset': 16,
902 'u-boot-align-size:size': 32,
903
904 'u-boot-align-end:image-pos': 48,
905 'u-boot-align-end:offset': 48,
906 'u-boot-align-end:size': 16,
907
908 'u-boot-align-both:image-pos': 64,
909 'u-boot-align-both:offset': 64,
910 'u-boot-align-both:size': 64,
911 }
912 self.assertEqual(expected, props)
913
Simon Glass4f443042016-11-25 20:15:52 -0700914 def testPackAlignPowerOf2(self):
915 """Test that invalid entry alignment is detected"""
916 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600917 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700918 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
919 "of two", str(e.exception))
920
921 def testPackAlignSizePowerOf2(self):
922 """Test that invalid entry size alignment is detected"""
923 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600924 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700925 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
926 "power of two", str(e.exception))
927
928 def testPackInvalidAlign(self):
Simon Glass3ab95982018-08-01 15:22:37 -0600929 """Test detection of an offset that does not match its alignment"""
Simon Glass4f443042016-11-25 20:15:52 -0700930 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600931 self._DoTestFile('012_pack_inv_align.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600932 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700933 "align 0x4 (4)", str(e.exception))
934
935 def testPackInvalidSizeAlign(self):
936 """Test that invalid entry size alignment is detected"""
937 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600938 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700939 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
940 "align-size 0x4 (4)", str(e.exception))
941
942 def testPackOverlap(self):
943 """Test that overlapping regions are detected"""
944 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600945 self._DoTestFile('014_pack_overlap.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600946 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -0700947 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
948 str(e.exception))
949
950 def testPackEntryOverflow(self):
951 """Test that entries that overflow their size are detected"""
952 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600953 self._DoTestFile('015_pack_overflow.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700954 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
955 "but entry size is 0x3 (3)", str(e.exception))
956
957 def testPackImageOverflow(self):
958 """Test that entries which overflow the image size are detected"""
959 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600960 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600961 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass4f443042016-11-25 20:15:52 -0700962 "size 0x3 (3)", str(e.exception))
963
964 def testPackImageSize(self):
965 """Test that the image size can be set"""
Simon Glass741f2d62018-10-01 12:22:30 -0600966 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700967 self.assertEqual(0, retcode)
968 self.assertIn('image', control.images)
969 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -0600970 self.assertEqual(7, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700971
972 def testPackImageSizeAlign(self):
973 """Test that image size alignemnt works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600974 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700975 self.assertEqual(0, retcode)
976 self.assertIn('image', control.images)
977 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -0600978 self.assertEqual(16, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700979
980 def testPackInvalidImageAlign(self):
981 """Test that invalid image alignment is detected"""
982 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600983 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600984 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700985 "align-size 0x8 (8)", str(e.exception))
986
987 def testPackAlignPowerOf2(self):
988 """Test that invalid image alignment is detected"""
989 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600990 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -0600991 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass4f443042016-11-25 20:15:52 -0700992 "two", str(e.exception))
993
994 def testImagePadByte(self):
995 """Test that the image pad byte can be specified"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600996 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600997 data = self._DoReadFile('021_image_pad.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -0600998 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0xff, 1) +
999 U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -07001000
1001 def testImageName(self):
1002 """Test that image files can be named"""
Simon Glass741f2d62018-10-01 12:22:30 -06001003 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001004 self.assertEqual(0, retcode)
1005 image = control.images['image1']
1006 fname = tools.GetOutputFilename('test-name')
1007 self.assertTrue(os.path.exists(fname))
1008
1009 image = control.images['image2']
1010 fname = tools.GetOutputFilename('test-name.xx')
1011 self.assertTrue(os.path.exists(fname))
1012
1013 def testBlobFilename(self):
1014 """Test that generic blobs can be provided by filename"""
Simon Glass741f2d62018-10-01 12:22:30 -06001015 data = self._DoReadFile('023_blob.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001016 self.assertEqual(BLOB_DATA, data)
1017
1018 def testPackSorted(self):
1019 """Test that entries can be sorted"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001020 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001021 data = self._DoReadFile('024_sorted.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001022 self.assertEqual(tools.GetBytes(0, 1) + U_BOOT_SPL_DATA +
1023 tools.GetBytes(0, 2) + U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -07001024
Simon Glass3ab95982018-08-01 15:22:37 -06001025 def testPackZeroOffset(self):
1026 """Test that an entry at offset 0 is not given a new offset"""
Simon Glass4f443042016-11-25 20:15:52 -07001027 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001028 self._DoTestFile('025_pack_zero_size.dts')
Simon Glass3ab95982018-08-01 15:22:37 -06001029 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -07001030 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1031 str(e.exception))
1032
1033 def testPackUbootDtb(self):
1034 """Test that a device tree can be added to U-Boot"""
Simon Glass741f2d62018-10-01 12:22:30 -06001035 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001036 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glasse0ff8552016-11-25 20:15:53 -07001037
1038 def testPackX86RomNoSize(self):
1039 """Test that the end-at-4gb property requires a size property"""
1040 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001041 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -06001042 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glasse0ff8552016-11-25 20:15:53 -07001043 "using end-at-4gb", str(e.exception))
1044
Jagdish Gediya94b57db2018-09-03 21:35:07 +05301045 def test4gbAndSkipAtStartTogether(self):
1046 """Test that the end-at-4gb and skip-at-size property can't be used
1047 together"""
1048 with self.assertRaises(ValueError) as e:
Simon Glassdfdd2b62019-08-24 07:23:02 -06001049 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -06001050 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya94b57db2018-09-03 21:35:07 +05301051 "'skip-at-start'", str(e.exception))
1052
Simon Glasse0ff8552016-11-25 20:15:53 -07001053 def testPackX86RomOutside(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001054 """Test that the end-at-4gb property checks for offset boundaries"""
Simon Glasse0ff8552016-11-25 20:15:53 -07001055 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001056 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glasse6bed4f2020-10-26 17:40:05 -06001057 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
1058 "is outside the section '/binman' starting at "
1059 '0xffffffe0 (4294967264) of size 0x20 (32)',
Simon Glasse0ff8552016-11-25 20:15:53 -07001060 str(e.exception))
1061
1062 def testPackX86Rom(self):
1063 """Test that a basic x86 ROM can be created"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001064 self._SetupSplElf()
Simon Glass9255f3c2019-08-24 07:23:01 -06001065 data = self._DoReadFile('029_x86_rom.dts')
Simon Glasseb0086f2019-08-24 07:23:04 -06001066 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 3) + U_BOOT_SPL_DATA +
Simon Glasse6d85ff2019-05-14 15:53:47 -06001067 tools.GetBytes(0, 2), data)
Simon Glasse0ff8552016-11-25 20:15:53 -07001068
1069 def testPackX86RomMeNoDesc(self):
1070 """Test that an invalid Intel descriptor entry is detected"""
Simon Glass0ba4b3d2020-07-09 18:39:41 -06001071 try:
Simon Glass52b10dd2020-07-25 15:11:19 -06001072 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
Simon Glass0ba4b3d2020-07-09 18:39:41 -06001073 with self.assertRaises(ValueError) as e:
Simon Glass52b10dd2020-07-25 15:11:19 -06001074 self._DoTestFile('163_x86_rom_me_empty.dts')
Simon Glass0ba4b3d2020-07-09 18:39:41 -06001075 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1076 str(e.exception))
1077 finally:
1078 self._SetupDescriptor()
Simon Glasse0ff8552016-11-25 20:15:53 -07001079
1080 def testPackX86RomBadDesc(self):
1081 """Test that the Intel requires a descriptor entry"""
1082 with self.assertRaises(ValueError) as e:
Simon Glass9255f3c2019-08-24 07:23:01 -06001083 self._DoTestFile('030_x86_rom_me_no_desc.dts')
Simon Glass3ab95982018-08-01 15:22:37 -06001084 self.assertIn("Node '/binman/intel-me': No offset set with "
1085 "offset-unset: should another entry provide this correct "
1086 "offset?", str(e.exception))
Simon Glasse0ff8552016-11-25 20:15:53 -07001087
1088 def testPackX86RomMe(self):
1089 """Test that an x86 ROM with an ME region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001090 data = self._DoReadFile('031_x86_rom_me.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06001091 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
1092 if data[:0x1000] != expected_desc:
1093 self.fail('Expected descriptor binary at start of image')
Simon Glasse0ff8552016-11-25 20:15:53 -07001094 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1095
1096 def testPackVga(self):
1097 """Test that an image with a VGA binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001098 data = self._DoReadFile('032_intel_vga.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -07001099 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1100
1101 def testPackStart16(self):
1102 """Test that an image with an x86 start16 region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001103 data = self._DoReadFile('033_x86_start16.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -07001104 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1105
Jagdish Gediya9d368f32018-09-03 21:35:08 +05301106 def testPackPowerpcMpc85xxBootpgResetvec(self):
1107 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1108 created"""
Simon Glassdfdd2b62019-08-24 07:23:02 -06001109 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
Jagdish Gediya9d368f32018-09-03 21:35:08 +05301110 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1111
Simon Glass736bb0a2018-07-06 10:27:17 -06001112 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glassadc57012018-07-06 10:27:16 -06001113 """Handle running a test for insertion of microcode
1114
1115 Args:
1116 dts_fname: Name of test .dts file
1117 nodtb_data: Data that we expect in the first section
Simon Glass736bb0a2018-07-06 10:27:17 -06001118 ucode_second: True if the microsecond entry is second instead of
1119 third
Simon Glassadc57012018-07-06 10:27:16 -06001120
1121 Returns:
1122 Tuple:
1123 Contents of first region (U-Boot or SPL)
Simon Glass3ab95982018-08-01 15:22:37 -06001124 Offset and size components of microcode pointer, as inserted
Simon Glassadc57012018-07-06 10:27:16 -06001125 in the above (two 4-byte words)
1126 """
Simon Glass6b187df2017-11-12 21:52:27 -07001127 data = self._DoReadFile(dts_fname, True)
Simon Glasse0ff8552016-11-25 20:15:53 -07001128
1129 # Now check the device tree has no microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001130 if ucode_second:
1131 ucode_content = data[len(nodtb_data):]
1132 ucode_pos = len(nodtb_data)
1133 dtb_with_ucode = ucode_content[16:]
1134 fdt_len = self.GetFdtLen(dtb_with_ucode)
1135 else:
1136 dtb_with_ucode = data[len(nodtb_data):]
1137 fdt_len = self.GetFdtLen(dtb_with_ucode)
1138 ucode_content = dtb_with_ucode[fdt_len:]
1139 ucode_pos = len(nodtb_data) + fdt_len
Simon Glasse0ff8552016-11-25 20:15:53 -07001140 fname = tools.GetOutputFilename('test.dtb')
1141 with open(fname, 'wb') as fd:
Simon Glassadc57012018-07-06 10:27:16 -06001142 fd.write(dtb_with_ucode)
Simon Glassec3f3782017-05-27 07:38:29 -06001143 dtb = fdt.FdtScan(fname)
1144 ucode = dtb.GetNode('/microcode')
Simon Glasse0ff8552016-11-25 20:15:53 -07001145 self.assertTrue(ucode)
1146 for node in ucode.subnodes:
1147 self.assertFalse(node.props.get('data'))
1148
Simon Glasse0ff8552016-11-25 20:15:53 -07001149 # Check that the microcode appears immediately after the Fdt
1150 # This matches the concatenation of the data properties in
Simon Glass87722132017-11-12 21:52:26 -07001151 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glasse0ff8552016-11-25 20:15:53 -07001152 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1153 0x78235609)
Simon Glassadc57012018-07-06 10:27:16 -06001154 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glasse0ff8552016-11-25 20:15:53 -07001155
1156 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -06001157 # expected offset and size
Simon Glasse0ff8552016-11-25 20:15:53 -07001158 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1159 len(ucode_data))
Simon Glass736bb0a2018-07-06 10:27:17 -06001160 u_boot = data[:len(nodtb_data)]
1161 return u_boot, pos_and_size
Simon Glass6b187df2017-11-12 21:52:27 -07001162
1163 def testPackUbootMicrocode(self):
1164 """Test that x86 microcode can be handled correctly
1165
1166 We expect to see the following in the image, in order:
1167 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1168 place
1169 u-boot.dtb with the microcode removed
1170 the microcode
1171 """
Simon Glass741f2d62018-10-01 12:22:30 -06001172 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass6b187df2017-11-12 21:52:27 -07001173 U_BOOT_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001174 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1175 b' somewhere in here', first)
Simon Glasse0ff8552016-11-25 20:15:53 -07001176
Simon Glass160a7662017-05-27 07:38:26 -06001177 def _RunPackUbootSingleMicrocode(self):
Simon Glasse0ff8552016-11-25 20:15:53 -07001178 """Test that x86 microcode can be handled correctly
1179
1180 We expect to see the following in the image, in order:
1181 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1182 place
1183 u-boot.dtb with the microcode
1184 an empty microcode region
1185 """
1186 # We need the libfdt library to run this test since only that allows
1187 # finding the offset of a property. This is required by
1188 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass741f2d62018-10-01 12:22:30 -06001189 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glasse0ff8552016-11-25 20:15:53 -07001190
1191 second = data[len(U_BOOT_NODTB_DATA):]
1192
1193 fdt_len = self.GetFdtLen(second)
1194 third = second[fdt_len:]
1195 second = second[:fdt_len]
1196
Simon Glass160a7662017-05-27 07:38:26 -06001197 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1198 self.assertIn(ucode_data, second)
1199 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -07001200
Simon Glass160a7662017-05-27 07:38:26 -06001201 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -06001202 # expected offset and size
Simon Glass160a7662017-05-27 07:38:26 -06001203 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1204 len(ucode_data))
1205 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glassc6c10e72019-05-17 22:00:46 -06001206 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1207 b' somewhere in here', first)
Simon Glassc49deb82016-11-25 20:15:54 -07001208
Simon Glass75db0862016-11-25 20:15:55 -07001209 def testPackUbootSingleMicrocode(self):
1210 """Test that x86 microcode can be handled correctly with fdt_normal.
1211 """
Simon Glass160a7662017-05-27 07:38:26 -06001212 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001213
Simon Glassc49deb82016-11-25 20:15:54 -07001214 def testUBootImg(self):
1215 """Test that u-boot.img can be put in a file"""
Simon Glass741f2d62018-10-01 12:22:30 -06001216 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glassc49deb82016-11-25 20:15:54 -07001217 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glass75db0862016-11-25 20:15:55 -07001218
1219 def testNoMicrocode(self):
1220 """Test that a missing microcode region is detected"""
1221 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001222 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001223 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1224 "node found in ", str(e.exception))
1225
1226 def testMicrocodeWithoutNode(self):
1227 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1228 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001229 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001230 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1231 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1232
1233 def testMicrocodeWithoutNode2(self):
1234 """Test that a missing u-boot-ucode node is detected"""
1235 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001236 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001237 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1238 "microcode region u-boot-ucode", str(e.exception))
1239
1240 def testMicrocodeWithoutPtrInElf(self):
1241 """Test that a U-Boot binary without the microcode symbol is detected"""
1242 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glass75db0862016-11-25 20:15:55 -07001243 try:
Simon Glassbccd91d2019-08-24 07:22:55 -06001244 TestFunctional._MakeInputFile('u-boot',
1245 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass75db0862016-11-25 20:15:55 -07001246
1247 with self.assertRaises(ValueError) as e:
Simon Glass160a7662017-05-27 07:38:26 -06001248 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001249 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1250 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1251
1252 finally:
1253 # Put the original file back
Simon Glassf514d8f2019-08-24 07:22:54 -06001254 TestFunctional._MakeInputFile('u-boot',
1255 tools.ReadFile(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glass75db0862016-11-25 20:15:55 -07001256
1257 def testMicrocodeNotInImage(self):
1258 """Test that microcode must be placed within the image"""
1259 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001260 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001261 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1262 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glass25ac0e62018-06-01 09:38:14 -06001263 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glass75db0862016-11-25 20:15:55 -07001264
1265 def testWithoutMicrocode(self):
1266 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glassbccd91d2019-08-24 07:22:55 -06001267 TestFunctional._MakeInputFile('u-boot',
1268 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass741f2d62018-10-01 12:22:30 -06001269 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001270
1271 # Now check the device tree has no microcode
1272 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1273 second = data[len(U_BOOT_NODTB_DATA):]
1274
1275 fdt_len = self.GetFdtLen(second)
1276 self.assertEqual(dtb, second[:fdt_len])
1277
1278 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1279 third = data[used_len:]
Simon Glasse6d85ff2019-05-14 15:53:47 -06001280 self.assertEqual(tools.GetBytes(0, 0x200 - used_len), third)
Simon Glass75db0862016-11-25 20:15:55 -07001281
1282 def testUnknownPosSize(self):
1283 """Test that microcode must be placed within the image"""
1284 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001285 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glass3ab95982018-08-01 15:22:37 -06001286 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glass75db0862016-11-25 20:15:55 -07001287 "entry 'invalid-entry'", str(e.exception))
Simon Glassda229092016-11-25 20:15:56 -07001288
1289 def testPackFsp(self):
1290 """Test that an image with a FSP binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001291 data = self._DoReadFile('042_intel_fsp.dts')
Simon Glassda229092016-11-25 20:15:56 -07001292 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1293
1294 def testPackCmc(self):
Bin Meng59ea8c22017-08-15 22:41:54 -07001295 """Test that an image with a CMC binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001296 data = self._DoReadFile('043_intel_cmc.dts')
Simon Glassda229092016-11-25 20:15:56 -07001297 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Meng59ea8c22017-08-15 22:41:54 -07001298
1299 def testPackVbt(self):
1300 """Test that an image with a VBT binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001301 data = self._DoReadFile('046_intel_vbt.dts')
Bin Meng59ea8c22017-08-15 22:41:54 -07001302 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glass9fc60b42017-11-12 21:52:22 -07001303
Simon Glass56509842017-11-12 21:52:25 -07001304 def testSplBssPad(self):
1305 """Test that we can pad SPL's BSS with zeros"""
Simon Glass6b187df2017-11-12 21:52:27 -07001306 # ELF file with a '__bss_size' symbol
Simon Glass11ae93e2018-10-01 21:12:47 -06001307 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001308 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001309 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
1310 data)
Simon Glass56509842017-11-12 21:52:25 -07001311
Simon Glass86af5112018-10-01 21:12:42 -06001312 def testSplBssPadMissing(self):
1313 """Test that a missing symbol is detected"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001314 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glassb50e5612017-11-13 18:54:54 -07001315 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001316 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassb50e5612017-11-13 18:54:54 -07001317 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1318 str(e.exception))
1319
Simon Glass87722132017-11-12 21:52:26 -07001320 def testPackStart16Spl(self):
Simon Glass35b384c2018-09-14 04:57:10 -06001321 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001322 data = self._DoReadFile('048_x86_start16_spl.dts')
Simon Glass87722132017-11-12 21:52:26 -07001323 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1324
Simon Glass736bb0a2018-07-06 10:27:17 -06001325 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1326 """Helper function for microcode tests
Simon Glass6b187df2017-11-12 21:52:27 -07001327
1328 We expect to see the following in the image, in order:
1329 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1330 correct place
1331 u-boot.dtb with the microcode removed
1332 the microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001333
1334 Args:
1335 dts: Device tree file to use for test
1336 ucode_second: True if the microsecond entry is second instead of
1337 third
Simon Glass6b187df2017-11-12 21:52:27 -07001338 """
Simon Glass11ae93e2018-10-01 21:12:47 -06001339 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass736bb0a2018-07-06 10:27:17 -06001340 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1341 ucode_second=ucode_second)
Simon Glassc6c10e72019-05-17 22:00:46 -06001342 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1343 b'ter somewhere in here', first)
Simon Glass6b187df2017-11-12 21:52:27 -07001344
Simon Glass736bb0a2018-07-06 10:27:17 -06001345 def testPackUbootSplMicrocode(self):
1346 """Test that x86 microcode can be handled correctly in SPL"""
Simon Glass741f2d62018-10-01 12:22:30 -06001347 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass736bb0a2018-07-06 10:27:17 -06001348
1349 def testPackUbootSplMicrocodeReorder(self):
1350 """Test that order doesn't matter for microcode entries
1351
1352 This is the same as testPackUbootSplMicrocode but when we process the
1353 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1354 entry, so we reply on binman to try later.
1355 """
Simon Glass741f2d62018-10-01 12:22:30 -06001356 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass736bb0a2018-07-06 10:27:17 -06001357 ucode_second=True)
1358
Simon Glassca4f4ff2017-11-12 21:52:28 -07001359 def testPackMrc(self):
1360 """Test that an image with an MRC binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001361 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassca4f4ff2017-11-12 21:52:28 -07001362 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1363
Simon Glass47419ea2017-11-13 18:54:55 -07001364 def testSplDtb(self):
1365 """Test that an image with spl/u-boot-spl.dtb can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001366 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass47419ea2017-11-13 18:54:55 -07001367 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1368
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001369 def testSplNoDtb(self):
1370 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass0fe44dc2021-04-25 08:39:32 +12001371 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001372 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001373 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1374
Simon Glass3d433382021-03-21 18:24:30 +13001375 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
1376 use_expanded=False):
Simon Glassf5898822021-03-18 20:24:56 +13001377 """Check the image contains the expected symbol values
1378
1379 Args:
1380 dts: Device tree file to use for test
1381 base_data: Data before and after 'u-boot' section
1382 u_boot_offset: Offset of 'u-boot' section in image
Simon Glass3d433382021-03-21 18:24:30 +13001383 entry_args: Dict of entry args to supply to binman
1384 key: arg name
1385 value: value of that arg
1386 use_expanded: True to use expanded entries where available, e.g.
1387 'u-boot-expanded' instead of 'u-boot'
Simon Glassf5898822021-03-18 20:24:56 +13001388 """
Simon Glass1542c8b2019-08-24 07:22:56 -06001389 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass19790632017-11-13 18:55:01 -07001390 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1391 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Simon Glassf5898822021-03-18 20:24:56 +13001392 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
1393 addr)
Simon Glass19790632017-11-13 18:55:01 -07001394
Simon Glass11ae93e2018-10-01 21:12:47 -06001395 self._SetupSplElf('u_boot_binman_syms')
Simon Glass3d433382021-03-21 18:24:30 +13001396 data = self._DoReadFileDtb(dts, entry_args=entry_args,
1397 use_expanded=use_expanded)[0]
Simon Glassf5898822021-03-18 20:24:56 +13001398 # The image should contain the symbols from u_boot_binman_syms.c
1399 # Note that image_pos is adjusted by the base address of the image,
1400 # which is 0x10 in our test image
1401 sym_values = struct.pack('<LQLL', 0x00,
1402 u_boot_offset + len(U_BOOT_DATA),
1403 0x10 + u_boot_offset, 0x04)
1404 expected = (sym_values + base_data[20:] +
Simon Glasse6d85ff2019-05-14 15:53:47 -06001405 tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
Simon Glassf5898822021-03-18 20:24:56 +13001406 base_data[20:])
Simon Glass19790632017-11-13 18:55:01 -07001407 self.assertEqual(expected, data)
1408
Simon Glassf5898822021-03-18 20:24:56 +13001409 def testSymbols(self):
1410 """Test binman can assign symbols embedded in U-Boot"""
1411 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x18)
1412
1413 def testSymbolsNoDtb(self):
1414 """Test binman can assign symbols embedded in U-Boot SPL"""
Simon Glasse9e0db82021-03-21 18:24:29 +13001415 self.checkSymbols('196_symbols_nodtb.dts',
Simon Glassf5898822021-03-18 20:24:56 +13001416 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1417 0x38)
1418
Simon Glassdd57c132018-06-01 09:38:11 -06001419 def testPackUnitAddress(self):
1420 """Test that we support multiple binaries with the same name"""
Simon Glass741f2d62018-10-01 12:22:30 -06001421 data = self._DoReadFile('054_unit_address.dts')
Simon Glassdd57c132018-06-01 09:38:11 -06001422 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1423
Simon Glass18546952018-06-01 09:38:16 -06001424 def testSections(self):
1425 """Basic test of sections"""
Simon Glass741f2d62018-10-01 12:22:30 -06001426 data = self._DoReadFile('055_sections.dts')
Simon Glassc6c10e72019-05-17 22:00:46 -06001427 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1428 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
1429 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
Simon Glass18546952018-06-01 09:38:16 -06001430 self.assertEqual(expected, data)
Simon Glass9fc60b42017-11-12 21:52:22 -07001431
Simon Glass3b0c3822018-06-01 09:38:20 -06001432 def testMap(self):
1433 """Tests outputting a map of the images"""
Simon Glass741f2d62018-10-01 12:22:30 -06001434 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001435 self.assertEqual('''ImagePos Offset Size Name
143600000000 00000000 00000028 main-section
143700000000 00000000 00000010 section@0
143800000000 00000000 00000004 u-boot
143900000010 00000010 00000010 section@1
144000000010 00000000 00000004 u-boot
144100000020 00000020 00000004 section@2
144200000020 00000000 00000004 u-boot
Simon Glass3b0c3822018-06-01 09:38:20 -06001443''', map_data)
1444
Simon Glassc8d48ef2018-06-01 09:38:21 -06001445 def testNamePrefix(self):
1446 """Tests that name prefixes are used"""
Simon Glass741f2d62018-10-01 12:22:30 -06001447 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001448 self.assertEqual('''ImagePos Offset Size Name
144900000000 00000000 00000028 main-section
145000000000 00000000 00000010 section@0
145100000000 00000000 00000004 ro-u-boot
145200000010 00000010 00000010 section@1
145300000010 00000000 00000004 rw-u-boot
Simon Glassc8d48ef2018-06-01 09:38:21 -06001454''', map_data)
1455
Simon Glass736bb0a2018-07-06 10:27:17 -06001456 def testUnknownContents(self):
1457 """Test that obtaining the contents works as expected"""
1458 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001459 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass8beb11e2019-07-08 14:25:47 -06001460 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glass16287932020-04-17 18:09:03 -06001461 "processing of contents: remaining ["
1462 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass736bb0a2018-07-06 10:27:17 -06001463
Simon Glass5c890232018-07-06 10:27:19 -06001464 def testBadChangeSize(self):
1465 """Test that trying to change the size of an entry fails"""
Simon Glassc52c9e72019-07-08 14:25:37 -06001466 try:
1467 state.SetAllowEntryExpansion(False)
1468 with self.assertRaises(ValueError) as e:
1469 self._DoReadFile('059_change_size.dts', True)
Simon Glass79d3c582019-07-20 12:23:57 -06001470 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glassc52c9e72019-07-08 14:25:37 -06001471 str(e.exception))
1472 finally:
1473 state.SetAllowEntryExpansion(True)
Simon Glass5c890232018-07-06 10:27:19 -06001474
Simon Glass16b8d6b2018-07-06 10:27:42 -06001475 def testUpdateFdt(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001476 """Test that we can update the device tree with offset/size info"""
Simon Glass741f2d62018-10-01 12:22:30 -06001477 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glass16b8d6b2018-07-06 10:27:42 -06001478 update_dtb=True)
Simon Glasscee02e62018-07-17 13:25:52 -06001479 dtb = fdt.Fdt(out_dtb_fname)
1480 dtb.Scan()
Simon Glass12bb1a92019-07-20 12:23:51 -06001481 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001482 self.assertEqual({
Simon Glassdbf6be92018-08-01 15:22:42 -06001483 'image-pos': 0,
Simon Glass8122f392018-07-17 13:25:28 -06001484 'offset': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001485 '_testing:offset': 32,
Simon Glass79d3c582019-07-20 12:23:57 -06001486 '_testing:size': 2,
Simon Glassdbf6be92018-08-01 15:22:42 -06001487 '_testing:image-pos': 32,
Simon Glass3ab95982018-08-01 15:22:37 -06001488 'section@0/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001489 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001490 'section@0/u-boot:image-pos': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001491 'section@0:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001492 'section@0:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001493 'section@0:image-pos': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001494
Simon Glass3ab95982018-08-01 15:22:37 -06001495 'section@1/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001496 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001497 'section@1/u-boot:image-pos': 16,
Simon Glass3ab95982018-08-01 15:22:37 -06001498 'section@1:offset': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001499 'section@1:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001500 'section@1:image-pos': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001501 'size': 40
1502 }, props)
1503
1504 def testUpdateFdtBad(self):
1505 """Test that we detect when ProcessFdt never completes"""
1506 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001507 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001508 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glass16287932020-04-17 18:09:03 -06001509 '[<binman.etype._testing.Entry__testing',
1510 str(e.exception))
Simon Glass5c890232018-07-06 10:27:19 -06001511
Simon Glass53af22a2018-07-17 13:25:32 -06001512 def testEntryArgs(self):
1513 """Test passing arguments to entries from the command line"""
1514 entry_args = {
1515 'test-str-arg': 'test1',
1516 'test-int-arg': '456',
1517 }
Simon Glass741f2d62018-10-01 12:22:30 -06001518 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001519 self.assertIn('image', control.images)
1520 entry = control.images['image'].GetEntries()['_testing']
1521 self.assertEqual('test0', entry.test_str_fdt)
1522 self.assertEqual('test1', entry.test_str_arg)
1523 self.assertEqual(123, entry.test_int_fdt)
1524 self.assertEqual(456, entry.test_int_arg)
1525
1526 def testEntryArgsMissing(self):
1527 """Test missing arguments and properties"""
1528 entry_args = {
1529 'test-int-arg': '456',
1530 }
Simon Glass741f2d62018-10-01 12:22:30 -06001531 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001532 entry = control.images['image'].GetEntries()['_testing']
1533 self.assertEqual('test0', entry.test_str_fdt)
1534 self.assertEqual(None, entry.test_str_arg)
1535 self.assertEqual(None, entry.test_int_fdt)
1536 self.assertEqual(456, entry.test_int_arg)
1537
1538 def testEntryArgsRequired(self):
1539 """Test missing arguments and properties"""
1540 entry_args = {
1541 'test-int-arg': '456',
1542 }
1543 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001544 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass3decfa32020-09-01 05:13:54 -06001545 self.assertIn("Node '/binman/_testing': "
1546 'Missing required properties/entry args: test-str-arg, '
1547 'test-int-fdt, test-int-arg',
Simon Glass53af22a2018-07-17 13:25:32 -06001548 str(e.exception))
1549
1550 def testEntryArgsInvalidFormat(self):
1551 """Test that an invalid entry-argument format is detected"""
Simon Glass53cd5d92019-07-08 14:25:29 -06001552 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1553 '-ano-value']
Simon Glass53af22a2018-07-17 13:25:32 -06001554 with self.assertRaises(ValueError) as e:
1555 self._DoBinman(*args)
1556 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1557
1558 def testEntryArgsInvalidInteger(self):
1559 """Test that an invalid entry-argument integer is detected"""
1560 entry_args = {
1561 'test-int-arg': 'abc',
1562 }
1563 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001564 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001565 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1566 "'test-int-arg' (value 'abc') to integer",
1567 str(e.exception))
1568
1569 def testEntryArgsInvalidDatatype(self):
1570 """Test that an invalid entry-argument datatype is detected
1571
1572 This test could be written in entry_test.py except that it needs
1573 access to control.entry_args, which seems more than that module should
1574 be able to see.
1575 """
1576 entry_args = {
1577 'test-bad-datatype-arg': '12',
1578 }
1579 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001580 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass53af22a2018-07-17 13:25:32 -06001581 entry_args=entry_args)
1582 self.assertIn('GetArg() internal error: Unknown data type ',
1583 str(e.exception))
1584
Simon Glassbb748372018-07-17 13:25:33 -06001585 def testText(self):
1586 """Test for a text entry type"""
1587 entry_args = {
1588 'test-id': TEXT_DATA,
1589 'test-id2': TEXT_DATA2,
1590 'test-id3': TEXT_DATA3,
1591 }
Simon Glass741f2d62018-10-01 12:22:30 -06001592 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glassbb748372018-07-17 13:25:33 -06001593 entry_args=entry_args)
Simon Glassc6c10e72019-05-17 22:00:46 -06001594 expected = (tools.ToBytes(TEXT_DATA) +
1595 tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1596 tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
Simon Glassaa88b502019-07-08 13:18:40 -06001597 b'some text' + b'more text')
Simon Glassbb748372018-07-17 13:25:33 -06001598 self.assertEqual(expected, data)
1599
Simon Glassfd8d1f72018-07-17 13:25:36 -06001600 def testEntryDocs(self):
1601 """Test for creation of entry documentation"""
1602 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass87d43322020-08-05 13:27:46 -06001603 control.WriteEntryDocs(control.GetEntryModules())
Simon Glassfd8d1f72018-07-17 13:25:36 -06001604 self.assertTrue(len(stdout.getvalue()) > 0)
1605
1606 def testEntryDocsMissing(self):
1607 """Test handling of missing entry documentation"""
1608 with self.assertRaises(ValueError) as e:
1609 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass87d43322020-08-05 13:27:46 -06001610 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glassfd8d1f72018-07-17 13:25:36 -06001611 self.assertIn('Documentation is missing for modules: u_boot',
1612 str(e.exception))
1613
Simon Glass11e36cc2018-07-17 13:25:38 -06001614 def testFmap(self):
1615 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001616 data = self._DoReadFile('067_fmap.dts')
Simon Glass11e36cc2018-07-17 13:25:38 -06001617 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc6c10e72019-05-17 22:00:46 -06001618 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1619 U_BOOT_DATA + tools.GetBytes(ord('a'), 12))
Simon Glass11e36cc2018-07-17 13:25:38 -06001620 self.assertEqual(expected, data[:32])
Simon Glassc6c10e72019-05-17 22:00:46 -06001621 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass11e36cc2018-07-17 13:25:38 -06001622 self.assertEqual(1, fhdr.ver_major)
1623 self.assertEqual(0, fhdr.ver_minor)
1624 self.assertEqual(0, fhdr.base)
Simon Glass17365752021-04-03 11:05:10 +13001625 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 5
Simon Glassc7722e82021-04-03 11:05:09 +13001626 self.assertEqual(16 + 16 + expect_size, fhdr.image_size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001627 self.assertEqual(b'FMAP', fhdr.name)
Simon Glass17365752021-04-03 11:05:10 +13001628 self.assertEqual(5, fhdr.nareas)
Simon Glassc7722e82021-04-03 11:05:09 +13001629 fiter = iter(fentries)
Simon Glass11e36cc2018-07-17 13:25:38 -06001630
Simon Glassc7722e82021-04-03 11:05:09 +13001631 fentry = next(fiter)
Simon Glass17365752021-04-03 11:05:10 +13001632 self.assertEqual(b'SECTION0', fentry.name)
1633 self.assertEqual(0, fentry.offset)
1634 self.assertEqual(16, fentry.size)
1635 self.assertEqual(0, fentry.flags)
1636
1637 fentry = next(fiter)
Simon Glassc7722e82021-04-03 11:05:09 +13001638 self.assertEqual(b'RO_U_BOOT', fentry.name)
1639 self.assertEqual(0, fentry.offset)
1640 self.assertEqual(4, fentry.size)
1641 self.assertEqual(0, fentry.flags)
Simon Glass11e36cc2018-07-17 13:25:38 -06001642
Simon Glassc7722e82021-04-03 11:05:09 +13001643 fentry = next(fiter)
Simon Glass17365752021-04-03 11:05:10 +13001644 self.assertEqual(b'SECTION1', fentry.name)
1645 self.assertEqual(16, fentry.offset)
1646 self.assertEqual(16, fentry.size)
1647 self.assertEqual(0, fentry.flags)
1648
1649 fentry = next(fiter)
Simon Glassc7722e82021-04-03 11:05:09 +13001650 self.assertEqual(b'RW_U_BOOT', fentry.name)
1651 self.assertEqual(16, fentry.offset)
1652 self.assertEqual(4, fentry.size)
1653 self.assertEqual(0, fentry.flags)
Simon Glass11e36cc2018-07-17 13:25:38 -06001654
Simon Glassc7722e82021-04-03 11:05:09 +13001655 fentry = next(fiter)
1656 self.assertEqual(b'FMAP', fentry.name)
1657 self.assertEqual(32, fentry.offset)
1658 self.assertEqual(expect_size, fentry.size)
1659 self.assertEqual(0, fentry.flags)
Simon Glass11e36cc2018-07-17 13:25:38 -06001660
Simon Glassec127af2018-07-17 13:25:39 -06001661 def testBlobNamedByArg(self):
1662 """Test we can add a blob with the filename coming from an entry arg"""
1663 entry_args = {
1664 'cros-ec-rw-path': 'ecrw.bin',
1665 }
Simon Glass3decfa32020-09-01 05:13:54 -06001666 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassec127af2018-07-17 13:25:39 -06001667
Simon Glass3af8e492018-07-17 13:25:40 -06001668 def testFill(self):
1669 """Test for an fill entry type"""
Simon Glass741f2d62018-10-01 12:22:30 -06001670 data = self._DoReadFile('069_fill.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001671 expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
Simon Glass3af8e492018-07-17 13:25:40 -06001672 self.assertEqual(expected, data)
1673
1674 def testFillNoSize(self):
1675 """Test for an fill entry type with no size"""
1676 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001677 self._DoReadFile('070_fill_no_size.dts')
Simon Glass3af8e492018-07-17 13:25:40 -06001678 self.assertIn("'fill' entry must have a size property",
1679 str(e.exception))
1680
Simon Glass0ef87aa2018-07-17 13:25:44 -06001681 def _HandleGbbCommand(self, pipe_list):
1682 """Fake calls to the futility utility"""
1683 if pipe_list[0][0] == 'futility':
1684 fname = pipe_list[0][-1]
1685 # Append our GBB data to the file, which will happen every time the
1686 # futility command is called.
Simon Glass1d0ebf72019-05-14 15:53:42 -06001687 with open(fname, 'ab') as fd:
Simon Glass0ef87aa2018-07-17 13:25:44 -06001688 fd.write(GBB_DATA)
1689 return command.CommandResult()
1690
1691 def testGbb(self):
1692 """Test for the Chromium OS Google Binary Block"""
1693 command.test_result = self._HandleGbbCommand
1694 entry_args = {
1695 'keydir': 'devkeys',
1696 'bmpblk': 'bmpblk.bin',
1697 }
Simon Glass741f2d62018-10-01 12:22:30 -06001698 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glass0ef87aa2018-07-17 13:25:44 -06001699
1700 # Since futility
Simon Glasse6d85ff2019-05-14 15:53:47 -06001701 expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1702 tools.GetBytes(0, 0x2180 - 16))
Simon Glass0ef87aa2018-07-17 13:25:44 -06001703 self.assertEqual(expected, data)
1704
1705 def testGbbTooSmall(self):
1706 """Test for the Chromium OS Google Binary Block being large enough"""
1707 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001708 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001709 self.assertIn("Node '/binman/gbb': GBB is too small",
1710 str(e.exception))
1711
1712 def testGbbNoSize(self):
1713 """Test for the Chromium OS Google Binary Block having a size"""
1714 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001715 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001716 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1717 str(e.exception))
1718
Simon Glass24d0d3c2018-07-17 13:25:47 -06001719 def _HandleVblockCommand(self, pipe_list):
Simon Glass5af9ebc2021-01-06 21:35:17 -07001720 """Fake calls to the futility utility
1721
1722 The expected pipe is:
1723
1724 [('futility', 'vbutil_firmware', '--vblock',
1725 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1726 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1727 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1728 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1729
1730 This writes to the output file (here, 'vblock.vblock'). If
1731 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1732 of the input data (here, 'input.vblock').
1733 """
Simon Glass24d0d3c2018-07-17 13:25:47 -06001734 if pipe_list[0][0] == 'futility':
1735 fname = pipe_list[0][3]
Simon Glassa326b492018-09-14 04:57:11 -06001736 with open(fname, 'wb') as fd:
Simon Glass5af9ebc2021-01-06 21:35:17 -07001737 if self._hash_data:
1738 infile = pipe_list[0][11]
1739 m = hashlib.sha256()
1740 data = tools.ReadFile(infile)
1741 m.update(data)
1742 fd.write(m.digest())
1743 else:
1744 fd.write(VBLOCK_DATA)
1745
Simon Glass24d0d3c2018-07-17 13:25:47 -06001746 return command.CommandResult()
1747
1748 def testVblock(self):
1749 """Test for the Chromium OS Verified Boot Block"""
Simon Glass5af9ebc2021-01-06 21:35:17 -07001750 self._hash_data = False
Simon Glass24d0d3c2018-07-17 13:25:47 -06001751 command.test_result = self._HandleVblockCommand
1752 entry_args = {
1753 'keydir': 'devkeys',
1754 }
Simon Glass741f2d62018-10-01 12:22:30 -06001755 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass24d0d3c2018-07-17 13:25:47 -06001756 entry_args=entry_args)
1757 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1758 self.assertEqual(expected, data)
1759
1760 def testVblockNoContent(self):
1761 """Test we detect a vblock which has no content to sign"""
1762 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001763 self._DoReadFile('075_vblock_no_content.dts')
Simon Glass189f2912021-03-21 18:24:31 +13001764 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
Simon Glass24d0d3c2018-07-17 13:25:47 -06001765 'property', str(e.exception))
1766
1767 def testVblockBadPhandle(self):
1768 """Test that we detect a vblock with an invalid phandle in contents"""
1769 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001770 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001771 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1772 '1000', str(e.exception))
1773
1774 def testVblockBadEntry(self):
1775 """Test that we detect an entry that points to a non-entry"""
1776 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001777 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001778 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1779 "'other'", str(e.exception))
1780
Simon Glass5af9ebc2021-01-06 21:35:17 -07001781 def testVblockContent(self):
1782 """Test that the vblock signs the right data"""
1783 self._hash_data = True
1784 command.test_result = self._HandleVblockCommand
1785 entry_args = {
1786 'keydir': 'devkeys',
1787 }
1788 data = self._DoReadFileDtb(
1789 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1790 entry_args=entry_args)[0]
1791 hashlen = 32 # SHA256 hash is 32 bytes
1792 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1793 hashval = data[-hashlen:]
1794 dtb = data[len(U_BOOT_DATA):-hashlen]
1795
1796 expected_data = U_BOOT_DATA + dtb
1797
1798 # The hashval should be a hash of the dtb
1799 m = hashlib.sha256()
1800 m.update(expected_data)
1801 expected_hashval = m.digest()
1802 self.assertEqual(expected_hashval, hashval)
1803
Simon Glassb8ef5b62018-07-17 13:25:48 -06001804 def testTpl(self):
Simon Glass2090f1e2019-08-24 07:23:00 -06001805 """Test that an image with TPL and its device tree can be created"""
Simon Glassb8ef5b62018-07-17 13:25:48 -06001806 # ELF file with a '__bss_size' symbol
Simon Glass2090f1e2019-08-24 07:23:00 -06001807 self._SetupTplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001808 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glassb8ef5b62018-07-17 13:25:48 -06001809 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1810
Simon Glass15a587c2018-07-17 13:25:51 -06001811 def testUsesPos(self):
1812 """Test that the 'pos' property cannot be used anymore"""
1813 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001814 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass15a587c2018-07-17 13:25:51 -06001815 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1816 "'pos'", str(e.exception))
1817
Simon Glassd178eab2018-09-14 04:57:08 -06001818 def testFillZero(self):
1819 """Test for an fill entry type with a size of 0"""
Simon Glass741f2d62018-10-01 12:22:30 -06001820 data = self._DoReadFile('080_fill_empty.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001821 self.assertEqual(tools.GetBytes(0, 16), data)
Simon Glassd178eab2018-09-14 04:57:08 -06001822
Simon Glass0b489362018-09-14 04:57:09 -06001823 def testTextMissing(self):
1824 """Test for a text entry type where there is no text"""
1825 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001826 self._DoReadFileDtb('066_text.dts',)
Simon Glass0b489362018-09-14 04:57:09 -06001827 self.assertIn("Node '/binman/text': No value provided for text label "
1828 "'test-id'", str(e.exception))
1829
Simon Glass35b384c2018-09-14 04:57:10 -06001830 def testPackStart16Tpl(self):
1831 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001832 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glass35b384c2018-09-14 04:57:10 -06001833 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1834
Simon Glass0bfa7b02018-09-14 04:57:12 -06001835 def testSelectImage(self):
1836 """Test that we can select which images to build"""
Simon Glasseb833d82019-04-25 21:58:34 -06001837 expected = 'Skipping images: image1'
Simon Glass0bfa7b02018-09-14 04:57:12 -06001838
Simon Glasseb833d82019-04-25 21:58:34 -06001839 # We should only get the expected message in verbose mode
Simon Glassee0c9a72019-07-08 13:18:48 -06001840 for verbosity in (0, 2):
Simon Glasseb833d82019-04-25 21:58:34 -06001841 with test_util.capture_sys_output() as (stdout, stderr):
1842 retcode = self._DoTestFile('006_dual_image.dts',
1843 verbosity=verbosity,
1844 images=['image2'])
1845 self.assertEqual(0, retcode)
1846 if verbosity:
1847 self.assertIn(expected, stdout.getvalue())
1848 else:
1849 self.assertNotIn(expected, stdout.getvalue())
1850
1851 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1852 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
Simon Glassf86a7362019-07-20 12:24:10 -06001853 self._CleanupOutputDir()
Simon Glass0bfa7b02018-09-14 04:57:12 -06001854
Simon Glass6ed45ba2018-09-14 04:57:24 -06001855 def testUpdateFdtAll(self):
1856 """Test that all device trees are updated with offset/size info"""
Simon Glass3c081312019-07-08 14:25:26 -06001857 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glass6ed45ba2018-09-14 04:57:24 -06001858
1859 base_expected = {
1860 'section:image-pos': 0,
1861 'u-boot-tpl-dtb:size': 513,
1862 'u-boot-spl-dtb:size': 513,
1863 'u-boot-spl-dtb:offset': 493,
1864 'image-pos': 0,
1865 'section/u-boot-dtb:image-pos': 0,
1866 'u-boot-spl-dtb:image-pos': 493,
1867 'section/u-boot-dtb:size': 493,
1868 'u-boot-tpl-dtb:image-pos': 1006,
1869 'section/u-boot-dtb:offset': 0,
1870 'section:size': 493,
1871 'offset': 0,
1872 'section:offset': 0,
1873 'u-boot-tpl-dtb:offset': 1006,
1874 'size': 1519
1875 }
1876
1877 # We expect three device-tree files in the output, one after the other.
1878 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1879 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1880 # main U-Boot tree. All three should have the same postions and offset.
1881 start = 0
1882 for item in ['', 'spl', 'tpl']:
1883 dtb = fdt.Fdt.FromData(data[start:])
1884 dtb.Scan()
Simon Glass12bb1a92019-07-20 12:23:51 -06001885 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
1886 ['spl', 'tpl'])
Simon Glass6ed45ba2018-09-14 04:57:24 -06001887 expected = dict(base_expected)
1888 if item:
1889 expected[item] = 0
1890 self.assertEqual(expected, props)
1891 start += dtb._fdt_obj.totalsize()
1892
1893 def testUpdateFdtOutput(self):
1894 """Test that output DTB files are updated"""
1895 try:
Simon Glass741f2d62018-10-01 12:22:30 -06001896 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glass6ed45ba2018-09-14 04:57:24 -06001897 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1898
1899 # Unfortunately, compiling a source file always results in a file
1900 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass741f2d62018-10-01 12:22:30 -06001901 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glass6ed45ba2018-09-14 04:57:24 -06001902 # binman as a file called u-boot.dtb. To fix this, copy the file
1903 # over to the expected place.
Simon Glass6ed45ba2018-09-14 04:57:24 -06001904 start = 0
1905 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1906 'tpl/u-boot-tpl.dtb.out']:
1907 dtb = fdt.Fdt.FromData(data[start:])
1908 size = dtb._fdt_obj.totalsize()
1909 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1910 outdata = tools.ReadFile(pathname)
1911 name = os.path.split(fname)[0]
1912
1913 if name:
1914 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1915 else:
1916 orig_indata = dtb_data
1917 self.assertNotEqual(outdata, orig_indata,
1918 "Expected output file '%s' be updated" % pathname)
1919 self.assertEqual(outdata, data[start:start + size],
1920 "Expected output file '%s' to match output image" %
1921 pathname)
1922 start += size
1923 finally:
1924 self._ResetDtbs()
1925
Simon Glass83d73c22018-09-14 04:57:26 -06001926 def _decompress(self, data):
Simon Glassff5c7e32019-07-08 13:18:42 -06001927 return tools.Decompress(data, 'lz4')
Simon Glass83d73c22018-09-14 04:57:26 -06001928
1929 def testCompress(self):
1930 """Test compression of blobs"""
Simon Glassac62fba2019-07-08 13:18:53 -06001931 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06001932 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass83d73c22018-09-14 04:57:26 -06001933 use_real_dtb=True, update_dtb=True)
1934 dtb = fdt.Fdt(out_dtb_fname)
1935 dtb.Scan()
1936 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1937 orig = self._decompress(data)
1938 self.assertEquals(COMPRESS_DATA, orig)
Simon Glass97c3e9a2020-10-26 17:40:15 -06001939
1940 # Do a sanity check on various fields
1941 image = control.images['image']
1942 entries = image.GetEntries()
1943 self.assertEqual(1, len(entries))
1944
1945 entry = entries['blob']
1946 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
1947 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
1948 orig = self._decompress(entry.data)
1949 self.assertEqual(orig, entry.uncomp_data)
1950
Simon Glass63e7ba62020-10-26 17:40:16 -06001951 self.assertEqual(image.data, entry.data)
1952
Simon Glass83d73c22018-09-14 04:57:26 -06001953 expected = {
1954 'blob:uncomp-size': len(COMPRESS_DATA),
1955 'blob:size': len(data),
1956 'size': len(data),
1957 }
1958 self.assertEqual(expected, props)
1959
Simon Glass0a98b282018-09-14 04:57:28 -06001960 def testFiles(self):
1961 """Test bringing in multiple files"""
Simon Glass741f2d62018-10-01 12:22:30 -06001962 data = self._DoReadFile('084_files.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001963 self.assertEqual(FILES_DATA, data)
1964
1965 def testFilesCompress(self):
1966 """Test bringing in multiple files and compressing them"""
Simon Glassac62fba2019-07-08 13:18:53 -06001967 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06001968 data = self._DoReadFile('085_files_compress.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001969
1970 image = control.images['image']
1971 entries = image.GetEntries()
1972 files = entries['files']
Simon Glass8beb11e2019-07-08 14:25:47 -06001973 entries = files._entries
Simon Glass0a98b282018-09-14 04:57:28 -06001974
Simon Glassc6c10e72019-05-17 22:00:46 -06001975 orig = b''
Simon Glass0a98b282018-09-14 04:57:28 -06001976 for i in range(1, 3):
1977 key = '%d.dat' % i
1978 start = entries[key].image_pos
1979 len = entries[key].size
1980 chunk = data[start:start + len]
1981 orig += self._decompress(chunk)
1982
1983 self.assertEqual(FILES_DATA, orig)
1984
1985 def testFilesMissing(self):
1986 """Test missing files"""
1987 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001988 data = self._DoReadFile('086_files_none.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001989 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1990 'no files', str(e.exception))
1991
1992 def testFilesNoPattern(self):
1993 """Test missing files"""
1994 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001995 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001996 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1997 str(e.exception))
1998
Simon Glassba64a0b2018-09-14 04:57:29 -06001999 def testExpandSize(self):
2000 """Test an expanding entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06002001 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
Simon Glassba64a0b2018-09-14 04:57:29 -06002002 map=True)
Simon Glassc6c10e72019-05-17 22:00:46 -06002003 expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA +
2004 MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA +
2005 tools.GetBytes(ord('c'), 8) + U_BOOT_DATA +
2006 tools.GetBytes(ord('d'), 8))
Simon Glassba64a0b2018-09-14 04:57:29 -06002007 self.assertEqual(expect, data)
2008 self.assertEqual('''ImagePos Offset Size Name
200900000000 00000000 00000028 main-section
201000000000 00000000 00000008 fill
201100000008 00000008 00000004 u-boot
20120000000c 0000000c 00000004 section
20130000000c 00000000 00000003 intel-mrc
201400000010 00000010 00000004 u-boot2
201500000014 00000014 0000000c section2
201600000014 00000000 00000008 fill
20170000001c 00000008 00000004 u-boot
201800000020 00000020 00000008 fill2
2019''', map_data)
2020
2021 def testExpandSizeBad(self):
2022 """Test an expanding entry which fails to provide contents"""
Simon Glass163ed6c2018-09-14 04:57:36 -06002023 with test_util.capture_sys_output() as (stdout, stderr):
2024 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002025 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
Simon Glassba64a0b2018-09-14 04:57:29 -06002026 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
2027 'expanding entry', str(e.exception))
2028
Simon Glasse0e5df92018-09-14 04:57:31 -06002029 def testHash(self):
2030 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06002031 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06002032 use_real_dtb=True, update_dtb=True)
2033 dtb = fdt.Fdt(out_dtb_fname)
2034 dtb.Scan()
2035 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
2036 m = hashlib.sha256()
2037 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06002038 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06002039
2040 def testHashNoAlgo(self):
2041 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002042 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06002043 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2044 'hash node', str(e.exception))
2045
2046 def testHashBadAlgo(self):
2047 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002048 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06002049 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
2050 str(e.exception))
2051
2052 def testHashSection(self):
2053 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06002054 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06002055 use_real_dtb=True, update_dtb=True)
2056 dtb = fdt.Fdt(out_dtb_fname)
2057 dtb.Scan()
2058 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2059 m = hashlib.sha256()
2060 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06002061 m.update(tools.GetBytes(ord('a'), 16))
2062 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06002063
Simon Glassf0253632018-09-14 04:57:32 -06002064 def testPackUBootTplMicrocode(self):
2065 """Test that x86 microcode can be handled correctly in TPL
2066
2067 We expect to see the following in the image, in order:
2068 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2069 place
2070 u-boot-tpl.dtb with the microcode removed
2071 the microcode
2072 """
Simon Glass2090f1e2019-08-24 07:23:00 -06002073 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass741f2d62018-10-01 12:22:30 -06002074 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glassf0253632018-09-14 04:57:32 -06002075 U_BOOT_TPL_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06002076 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2077 b'ter somewhere in here', first)
Simon Glassf0253632018-09-14 04:57:32 -06002078
Simon Glassf8f8df62018-09-14 04:57:34 -06002079 def testFmapX86(self):
2080 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06002081 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassf8f8df62018-09-14 04:57:34 -06002082 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc6c10e72019-05-17 22:00:46 -06002083 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06002084 self.assertEqual(expected, data[:32])
2085 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2086
2087 self.assertEqual(0x100, fhdr.image_size)
2088
2089 self.assertEqual(0, fentries[0].offset)
2090 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06002091 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06002092
2093 self.assertEqual(4, fentries[1].offset)
2094 self.assertEqual(3, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06002095 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06002096
2097 self.assertEqual(32, fentries[2].offset)
2098 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2099 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06002100 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06002101
2102 def testFmapX86Section(self):
2103 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06002104 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glassc6c10e72019-05-17 22:00:46 -06002105 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06002106 self.assertEqual(expected, data[:32])
2107 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2108
Simon Glass17365752021-04-03 11:05:10 +13002109 self.assertEqual(0x180, fhdr.image_size)
2110 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
Simon Glassc7722e82021-04-03 11:05:09 +13002111 fiter = iter(fentries)
Simon Glassf8f8df62018-09-14 04:57:34 -06002112
Simon Glassc7722e82021-04-03 11:05:09 +13002113 fentry = next(fiter)
2114 self.assertEqual(b'U_BOOT', fentry.name)
2115 self.assertEqual(0, fentry.offset)
2116 self.assertEqual(4, fentry.size)
Simon Glassf8f8df62018-09-14 04:57:34 -06002117
Simon Glassc7722e82021-04-03 11:05:09 +13002118 fentry = next(fiter)
Simon Glass17365752021-04-03 11:05:10 +13002119 self.assertEqual(b'SECTION', fentry.name)
2120 self.assertEqual(4, fentry.offset)
2121 self.assertEqual(0x20 + expect_size, fentry.size)
2122
2123 fentry = next(fiter)
Simon Glassc7722e82021-04-03 11:05:09 +13002124 self.assertEqual(b'INTEL_MRC', fentry.name)
2125 self.assertEqual(4, fentry.offset)
2126 self.assertEqual(3, fentry.size)
Simon Glassf8f8df62018-09-14 04:57:34 -06002127
Simon Glassc7722e82021-04-03 11:05:09 +13002128 fentry = next(fiter)
2129 self.assertEqual(b'FMAP', fentry.name)
2130 self.assertEqual(36, fentry.offset)
2131 self.assertEqual(expect_size, fentry.size)
Simon Glassf8f8df62018-09-14 04:57:34 -06002132
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002133 def testElf(self):
2134 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06002135 self._SetupSplElf()
Simon Glass2090f1e2019-08-24 07:23:00 -06002136 self._SetupTplElf()
Simon Glass53e22bf2019-08-24 07:22:53 -06002137 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002138 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06002139 data = self._DoReadFile('096_elf.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002140
Simon Glass093d1682019-07-08 13:18:25 -06002141 def testElfStrip(self):
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002142 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06002143 self._SetupSplElf()
Simon Glass53e22bf2019-08-24 07:22:53 -06002144 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002145 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06002146 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002147
Simon Glass163ed6c2018-09-14 04:57:36 -06002148 def testPackOverlapMap(self):
2149 """Test that overlapping regions are detected"""
2150 with test_util.capture_sys_output() as (stdout, stderr):
2151 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002152 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glass163ed6c2018-09-14 04:57:36 -06002153 map_fname = tools.GetOutputFilename('image.map')
2154 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2155 stdout.getvalue())
2156
2157 # We should not get an inmage, but there should be a map file
2158 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
2159 self.assertTrue(os.path.exists(map_fname))
Simon Glasseb546ac2019-05-17 22:00:51 -06002160 map_data = tools.ReadFile(map_fname, binary=False)
Simon Glass163ed6c2018-09-14 04:57:36 -06002161 self.assertEqual('''ImagePos Offset Size Name
Simon Glass0ff83da2020-10-26 17:40:24 -06002162<none> 00000000 00000008 main-section
Simon Glass163ed6c2018-09-14 04:57:36 -06002163<none> 00000000 00000004 u-boot
2164<none> 00000003 00000004 u-boot-align
2165''', map_data)
2166
Simon Glass093d1682019-07-08 13:18:25 -06002167 def testPackRefCode(self):
Simon Glass3ae192c2018-10-01 12:22:31 -06002168 """Test that an image with an Intel Reference code binary works"""
2169 data = self._DoReadFile('100_intel_refcode.dts')
2170 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2171
Simon Glass9481c802019-04-25 21:58:39 -06002172 def testSectionOffset(self):
2173 """Tests use of a section with an offset"""
2174 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2175 map=True)
2176 self.assertEqual('''ImagePos Offset Size Name
217700000000 00000000 00000038 main-section
217800000004 00000004 00000010 section@0
217900000004 00000000 00000004 u-boot
218000000018 00000018 00000010 section@1
218100000018 00000000 00000004 u-boot
21820000002c 0000002c 00000004 section@2
21830000002c 00000000 00000004 u-boot
2184''', map_data)
2185 self.assertEqual(data,
Simon Glasse6d85ff2019-05-14 15:53:47 -06002186 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2187 tools.GetBytes(0x21, 12) +
2188 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2189 tools.GetBytes(0x61, 12) +
2190 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2191 tools.GetBytes(0x26, 8))
Simon Glass9481c802019-04-25 21:58:39 -06002192
Simon Glassac62fba2019-07-08 13:18:53 -06002193 def testCbfsRaw(self):
2194 """Test base handling of a Coreboot Filesystem (CBFS)
2195
2196 The exact contents of the CBFS is verified by similar tests in
2197 cbfs_util_test.py. The tests here merely check that the files added to
2198 the CBFS can be found in the final image.
2199 """
2200 data = self._DoReadFile('102_cbfs_raw.dts')
2201 size = 0xb0
2202
2203 cbfs = cbfs_util.CbfsReader(data)
2204 self.assertEqual(size, cbfs.rom_size)
2205
2206 self.assertIn('u-boot-dtb', cbfs.files)
2207 cfile = cbfs.files['u-boot-dtb']
2208 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2209
2210 def testCbfsArch(self):
2211 """Test on non-x86 architecture"""
2212 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2213 size = 0x100
2214
2215 cbfs = cbfs_util.CbfsReader(data)
2216 self.assertEqual(size, cbfs.rom_size)
2217
2218 self.assertIn('u-boot-dtb', cbfs.files)
2219 cfile = cbfs.files['u-boot-dtb']
2220 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2221
2222 def testCbfsStage(self):
2223 """Tests handling of a Coreboot Filesystem (CBFS)"""
2224 if not elf.ELF_TOOLS:
2225 self.skipTest('Python elftools not available')
2226 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2227 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2228 size = 0xb0
2229
2230 data = self._DoReadFile('104_cbfs_stage.dts')
2231 cbfs = cbfs_util.CbfsReader(data)
2232 self.assertEqual(size, cbfs.rom_size)
2233
2234 self.assertIn('u-boot', cbfs.files)
2235 cfile = cbfs.files['u-boot']
2236 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2237
2238 def testCbfsRawCompress(self):
2239 """Test handling of compressing raw files"""
2240 self._CheckLz4()
2241 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2242 size = 0x140
2243
2244 cbfs = cbfs_util.CbfsReader(data)
2245 self.assertIn('u-boot', cbfs.files)
2246 cfile = cbfs.files['u-boot']
2247 self.assertEqual(COMPRESS_DATA, cfile.data)
2248
2249 def testCbfsBadArch(self):
2250 """Test handling of a bad architecture"""
2251 with self.assertRaises(ValueError) as e:
2252 self._DoReadFile('106_cbfs_bad_arch.dts')
2253 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2254
2255 def testCbfsNoSize(self):
2256 """Test handling of a missing size property"""
2257 with self.assertRaises(ValueError) as e:
2258 self._DoReadFile('107_cbfs_no_size.dts')
2259 self.assertIn('entry must have a size property', str(e.exception))
2260
Simon Glasse2f04742021-11-23 11:03:54 -07002261 def testCbfsNoContents(self):
Simon Glassac62fba2019-07-08 13:18:53 -06002262 """Test handling of a CBFS entry which does not provide contentsy"""
2263 with self.assertRaises(ValueError) as e:
2264 self._DoReadFile('108_cbfs_no_contents.dts')
2265 self.assertIn('Could not complete processing of contents',
2266 str(e.exception))
2267
2268 def testCbfsBadCompress(self):
2269 """Test handling of a bad architecture"""
2270 with self.assertRaises(ValueError) as e:
2271 self._DoReadFile('109_cbfs_bad_compress.dts')
2272 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2273 str(e.exception))
2274
2275 def testCbfsNamedEntries(self):
2276 """Test handling of named entries"""
2277 data = self._DoReadFile('110_cbfs_name.dts')
2278
2279 cbfs = cbfs_util.CbfsReader(data)
2280 self.assertIn('FRED', cbfs.files)
2281 cfile1 = cbfs.files['FRED']
2282 self.assertEqual(U_BOOT_DATA, cfile1.data)
2283
2284 self.assertIn('hello', cbfs.files)
2285 cfile2 = cbfs.files['hello']
2286 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2287
Simon Glassc5ac1382019-07-08 13:18:54 -06002288 def _SetupIfwi(self, fname):
2289 """Set up to run an IFWI test
2290
2291 Args:
2292 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2293 """
2294 self._SetupSplElf()
Simon Glass2090f1e2019-08-24 07:23:00 -06002295 self._SetupTplElf()
Simon Glassc5ac1382019-07-08 13:18:54 -06002296
2297 # Intel Integrated Firmware Image (IFWI) file
2298 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2299 data = fd.read()
2300 TestFunctional._MakeInputFile(fname,data)
2301
2302 def _CheckIfwi(self, data):
2303 """Check that an image with an IFWI contains the correct output
2304
2305 Args:
2306 data: Conents of output file
2307 """
2308 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
2309 if data[:0x1000] != expected_desc:
2310 self.fail('Expected descriptor binary at start of image')
2311
2312 # We expect to find the TPL wil in subpart IBBP entry IBBL
2313 image_fname = tools.GetOutputFilename('image.bin')
2314 tpl_fname = tools.GetOutputFilename('tpl.out')
2315 tools.RunIfwiTool(image_fname, tools.CMD_EXTRACT, fname=tpl_fname,
2316 subpart='IBBP', entry_name='IBBL')
2317
2318 tpl_data = tools.ReadFile(tpl_fname)
Simon Glasse95be632019-08-24 07:22:51 -06002319 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glassc5ac1382019-07-08 13:18:54 -06002320
2321 def testPackX86RomIfwi(self):
2322 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2323 self._SetupIfwi('fitimage.bin')
Simon Glass9255f3c2019-08-24 07:23:01 -06002324 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002325 self._CheckIfwi(data)
2326
2327 def testPackX86RomIfwiNoDesc(self):
2328 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2329 self._SetupIfwi('ifwi.bin')
Simon Glass9255f3c2019-08-24 07:23:01 -06002330 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002331 self._CheckIfwi(data)
2332
2333 def testPackX86RomIfwiNoData(self):
2334 """Test that an x86 ROM with IFWI handles missing data"""
2335 self._SetupIfwi('ifwi.bin')
2336 with self.assertRaises(ValueError) as e:
Simon Glass9255f3c2019-08-24 07:23:01 -06002337 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002338 self.assertIn('Could not complete processing of contents',
2339 str(e.exception))
Simon Glass53af22a2018-07-17 13:25:32 -06002340
Simon Glasse073d4e2019-07-08 13:18:56 -06002341 def testCbfsOffset(self):
2342 """Test a CBFS with files at particular offsets
2343
2344 Like all CFBS tests, this is just checking the logic that calls
2345 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2346 """
2347 data = self._DoReadFile('114_cbfs_offset.dts')
2348 size = 0x200
2349
2350 cbfs = cbfs_util.CbfsReader(data)
2351 self.assertEqual(size, cbfs.rom_size)
2352
2353 self.assertIn('u-boot', cbfs.files)
2354 cfile = cbfs.files['u-boot']
2355 self.assertEqual(U_BOOT_DATA, cfile.data)
2356 self.assertEqual(0x40, cfile.cbfs_offset)
2357
2358 self.assertIn('u-boot-dtb', cbfs.files)
2359 cfile2 = cbfs.files['u-boot-dtb']
2360 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2361 self.assertEqual(0x140, cfile2.cbfs_offset)
2362
Simon Glass086cec92019-07-08 14:25:27 -06002363 def testFdtmap(self):
2364 """Test an FDT map can be inserted in the image"""
2365 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2366 fdtmap_data = data[len(U_BOOT_DATA):]
2367 magic = fdtmap_data[:8]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002368 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass086cec92019-07-08 14:25:27 -06002369 self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
2370
2371 fdt_data = fdtmap_data[16:]
2372 dtb = fdt.Fdt.FromData(fdt_data)
2373 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002374 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass086cec92019-07-08 14:25:27 -06002375 self.assertEqual({
2376 'image-pos': 0,
2377 'offset': 0,
2378 'u-boot:offset': 0,
2379 'u-boot:size': len(U_BOOT_DATA),
2380 'u-boot:image-pos': 0,
2381 'fdtmap:image-pos': 4,
2382 'fdtmap:offset': 4,
2383 'fdtmap:size': len(fdtmap_data),
2384 'size': len(data),
2385 }, props)
2386
2387 def testFdtmapNoMatch(self):
2388 """Check handling of an FDT map when the section cannot be found"""
2389 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2390
2391 # Mangle the section name, which should cause a mismatch between the
2392 # correct FDT path and the one expected by the section
2393 image = control.images['image']
Simon Glasscf228942019-07-08 14:25:28 -06002394 image._node.path += '-suffix'
Simon Glass086cec92019-07-08 14:25:27 -06002395 entries = image.GetEntries()
2396 fdtmap = entries['fdtmap']
2397 with self.assertRaises(ValueError) as e:
2398 fdtmap._GetFdtmap()
2399 self.assertIn("Cannot locate node for path '/binman-suffix'",
2400 str(e.exception))
2401
Simon Glasscf228942019-07-08 14:25:28 -06002402 def testFdtmapHeader(self):
2403 """Test an FDT map and image header can be inserted in the image"""
2404 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2405 fdtmap_pos = len(U_BOOT_DATA)
2406 fdtmap_data = data[fdtmap_pos:]
2407 fdt_data = fdtmap_data[16:]
2408 dtb = fdt.Fdt.FromData(fdt_data)
2409 fdt_size = dtb.GetFdtObj().totalsize()
2410 hdr_data = data[-8:]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002411 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002412 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2413 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2414
2415 def testFdtmapHeaderStart(self):
2416 """Test an image header can be inserted at the image start"""
2417 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2418 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2419 hdr_data = data[:8]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002420 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002421 offset = struct.unpack('<I', hdr_data[4:])[0]
2422 self.assertEqual(fdtmap_pos, offset)
2423
2424 def testFdtmapHeaderPos(self):
2425 """Test an image header can be inserted at a chosen position"""
2426 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2427 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2428 hdr_data = data[0x80:0x88]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002429 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002430 offset = struct.unpack('<I', hdr_data[4:])[0]
2431 self.assertEqual(fdtmap_pos, offset)
2432
2433 def testHeaderMissingFdtmap(self):
2434 """Test an image header requires an fdtmap"""
2435 with self.assertRaises(ValueError) as e:
2436 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2437 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2438 str(e.exception))
2439
2440 def testHeaderNoLocation(self):
2441 """Test an image header with a no specified location is detected"""
2442 with self.assertRaises(ValueError) as e:
2443 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2444 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2445 str(e.exception))
2446
Simon Glassc52c9e72019-07-08 14:25:37 -06002447 def testEntryExpand(self):
2448 """Test expanding an entry after it is packed"""
2449 data = self._DoReadFile('121_entry_expand.dts')
Simon Glass79d3c582019-07-20 12:23:57 -06002450 self.assertEqual(b'aaa', data[:3])
2451 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2452 self.assertEqual(b'aaa', data[-3:])
Simon Glassc52c9e72019-07-08 14:25:37 -06002453
2454 def testEntryExpandBad(self):
2455 """Test expanding an entry after it is packed, twice"""
2456 with self.assertRaises(ValueError) as e:
2457 self._DoReadFile('122_entry_expand_twice.dts')
Simon Glass61ec04f2019-07-20 12:23:58 -06002458 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glassc52c9e72019-07-08 14:25:37 -06002459 str(e.exception))
2460
2461 def testEntryExpandSection(self):
2462 """Test expanding an entry within a section after it is packed"""
2463 data = self._DoReadFile('123_entry_expand_section.dts')
Simon Glass79d3c582019-07-20 12:23:57 -06002464 self.assertEqual(b'aaa', data[:3])
2465 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2466 self.assertEqual(b'aaa', data[-3:])
Simon Glassc52c9e72019-07-08 14:25:37 -06002467
Simon Glass6c223fd2019-07-08 14:25:38 -06002468 def testCompressDtb(self):
2469 """Test that compress of device-tree files is supported"""
2470 self._CheckLz4()
2471 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2472 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2473 comp_data = data[len(U_BOOT_DATA):]
2474 orig = self._decompress(comp_data)
2475 dtb = fdt.Fdt.FromData(orig)
2476 dtb.Scan()
2477 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2478 expected = {
2479 'u-boot:size': len(U_BOOT_DATA),
2480 'u-boot-dtb:uncomp-size': len(orig),
2481 'u-boot-dtb:size': len(comp_data),
2482 'size': len(data),
2483 }
2484 self.assertEqual(expected, props)
2485
Simon Glass69f7cb32019-07-08 14:25:41 -06002486 def testCbfsUpdateFdt(self):
2487 """Test that we can update the device tree with CBFS offset/size info"""
2488 self._CheckLz4()
2489 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2490 update_dtb=True)
2491 dtb = fdt.Fdt(out_dtb_fname)
2492 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002493 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass69f7cb32019-07-08 14:25:41 -06002494 del props['cbfs/u-boot:size']
2495 self.assertEqual({
2496 'offset': 0,
2497 'size': len(data),
2498 'image-pos': 0,
2499 'cbfs:offset': 0,
2500 'cbfs:size': len(data),
2501 'cbfs:image-pos': 0,
2502 'cbfs/u-boot:offset': 0x38,
2503 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2504 'cbfs/u-boot:image-pos': 0x38,
2505 'cbfs/u-boot-dtb:offset': 0xb8,
2506 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2507 'cbfs/u-boot-dtb:image-pos': 0xb8,
2508 }, props)
2509
Simon Glass8a1ad062019-07-08 14:25:42 -06002510 def testCbfsBadType(self):
2511 """Test an image header with a no specified location is detected"""
2512 with self.assertRaises(ValueError) as e:
2513 self._DoReadFile('126_cbfs_bad_type.dts')
2514 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2515
Simon Glass41b8ba02019-07-08 14:25:43 -06002516 def testList(self):
2517 """Test listing the files in an image"""
2518 self._CheckLz4()
2519 data = self._DoReadFile('127_list.dts')
2520 image = control.images['image']
2521 entries = image.BuildEntryList()
2522 self.assertEqual(7, len(entries))
2523
2524 ent = entries[0]
2525 self.assertEqual(0, ent.indent)
2526 self.assertEqual('main-section', ent.name)
2527 self.assertEqual('section', ent.etype)
2528 self.assertEqual(len(data), ent.size)
2529 self.assertEqual(0, ent.image_pos)
2530 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002531 self.assertEqual(0, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002532
2533 ent = entries[1]
2534 self.assertEqual(1, ent.indent)
2535 self.assertEqual('u-boot', ent.name)
2536 self.assertEqual('u-boot', ent.etype)
2537 self.assertEqual(len(U_BOOT_DATA), ent.size)
2538 self.assertEqual(0, ent.image_pos)
2539 self.assertEqual(None, ent.uncomp_size)
2540 self.assertEqual(0, ent.offset)
2541
2542 ent = entries[2]
2543 self.assertEqual(1, ent.indent)
2544 self.assertEqual('section', ent.name)
2545 self.assertEqual('section', ent.etype)
2546 section_size = ent.size
2547 self.assertEqual(0x100, ent.image_pos)
2548 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002549 self.assertEqual(0x100, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002550
2551 ent = entries[3]
2552 self.assertEqual(2, ent.indent)
2553 self.assertEqual('cbfs', ent.name)
2554 self.assertEqual('cbfs', ent.etype)
2555 self.assertEqual(0x400, ent.size)
2556 self.assertEqual(0x100, ent.image_pos)
2557 self.assertEqual(None, ent.uncomp_size)
2558 self.assertEqual(0, ent.offset)
2559
2560 ent = entries[4]
2561 self.assertEqual(3, ent.indent)
2562 self.assertEqual('u-boot', ent.name)
2563 self.assertEqual('u-boot', ent.etype)
2564 self.assertEqual(len(U_BOOT_DATA), ent.size)
2565 self.assertEqual(0x138, ent.image_pos)
2566 self.assertEqual(None, ent.uncomp_size)
2567 self.assertEqual(0x38, ent.offset)
2568
2569 ent = entries[5]
2570 self.assertEqual(3, ent.indent)
2571 self.assertEqual('u-boot-dtb', ent.name)
2572 self.assertEqual('text', ent.etype)
2573 self.assertGreater(len(COMPRESS_DATA), ent.size)
2574 self.assertEqual(0x178, ent.image_pos)
2575 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2576 self.assertEqual(0x78, ent.offset)
2577
2578 ent = entries[6]
2579 self.assertEqual(2, ent.indent)
2580 self.assertEqual('u-boot-dtb', ent.name)
2581 self.assertEqual('u-boot-dtb', ent.etype)
2582 self.assertEqual(0x500, ent.image_pos)
2583 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2584 dtb_size = ent.size
2585 # Compressing this data expands it since headers are added
2586 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2587 self.assertEqual(0x400, ent.offset)
2588
2589 self.assertEqual(len(data), 0x100 + section_size)
2590 self.assertEqual(section_size, 0x400 + dtb_size)
2591
Simon Glasse1925fa2019-07-08 14:25:44 -06002592 def testFindFdtmap(self):
2593 """Test locating an FDT map in an image"""
2594 self._CheckLz4()
2595 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2596 image = control.images['image']
2597 entries = image.GetEntries()
2598 entry = entries['fdtmap']
2599 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2600
2601 def testFindFdtmapMissing(self):
2602 """Test failing to locate an FDP map"""
2603 data = self._DoReadFile('005_simple.dts')
2604 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2605
Simon Glass2d260032019-07-08 14:25:45 -06002606 def testFindImageHeader(self):
2607 """Test locating a image header"""
2608 self._CheckLz4()
Simon Glassffded752019-07-08 14:25:46 -06002609 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002610 image = control.images['image']
2611 entries = image.GetEntries()
2612 entry = entries['fdtmap']
2613 # The header should point to the FDT map
2614 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2615
2616 def testFindImageHeaderStart(self):
2617 """Test locating a image header located at the start of an image"""
Simon Glassffded752019-07-08 14:25:46 -06002618 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002619 image = control.images['image']
2620 entries = image.GetEntries()
2621 entry = entries['fdtmap']
2622 # The header should point to the FDT map
2623 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2624
2625 def testFindImageHeaderMissing(self):
2626 """Test failing to locate an image header"""
2627 data = self._DoReadFile('005_simple.dts')
2628 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2629
Simon Glassffded752019-07-08 14:25:46 -06002630 def testReadImage(self):
2631 """Test reading an image and accessing its FDT map"""
2632 self._CheckLz4()
2633 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2634 image_fname = tools.GetOutputFilename('image.bin')
2635 orig_image = control.images['image']
2636 image = Image.FromFile(image_fname)
2637 self.assertEqual(orig_image.GetEntries().keys(),
2638 image.GetEntries().keys())
2639
2640 orig_entry = orig_image.GetEntries()['fdtmap']
2641 entry = image.GetEntries()['fdtmap']
2642 self.assertEquals(orig_entry.offset, entry.offset)
2643 self.assertEquals(orig_entry.size, entry.size)
2644 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2645
2646 def testReadImageNoHeader(self):
2647 """Test accessing an image's FDT map without an image header"""
2648 self._CheckLz4()
2649 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
2650 image_fname = tools.GetOutputFilename('image.bin')
2651 image = Image.FromFile(image_fname)
2652 self.assertTrue(isinstance(image, Image))
Simon Glass10f9d002019-07-20 12:23:50 -06002653 self.assertEqual('image', image.image_name[-5:])
Simon Glassffded752019-07-08 14:25:46 -06002654
2655 def testReadImageFail(self):
2656 """Test failing to read an image image's FDT map"""
2657 self._DoReadFile('005_simple.dts')
2658 image_fname = tools.GetOutputFilename('image.bin')
2659 with self.assertRaises(ValueError) as e:
2660 image = Image.FromFile(image_fname)
2661 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glasse073d4e2019-07-08 13:18:56 -06002662
Simon Glass61f564d2019-07-08 14:25:48 -06002663 def testListCmd(self):
2664 """Test listing the files in an image using an Fdtmap"""
2665 self._CheckLz4()
2666 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2667
2668 # lz4 compression size differs depending on the version
2669 image = control.images['image']
2670 entries = image.GetEntries()
2671 section_size = entries['section'].size
2672 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2673 fdtmap_offset = entries['fdtmap'].offset
2674
Simon Glassf86a7362019-07-20 12:24:10 -06002675 try:
2676 tmpdir, updated_fname = self._SetupImageInTmpdir()
2677 with test_util.capture_sys_output() as (stdout, stderr):
2678 self._DoBinman('ls', '-i', updated_fname)
2679 finally:
2680 shutil.rmtree(tmpdir)
Simon Glass61f564d2019-07-08 14:25:48 -06002681 lines = stdout.getvalue().splitlines()
2682 expected = [
2683'Name Image-pos Size Entry-type Offset Uncomp-size',
2684'----------------------------------------------------------------------',
2685'main-section 0 c00 section 0',
2686' u-boot 0 4 u-boot 0',
2687' section 100 %x section 100' % section_size,
2688' cbfs 100 400 cbfs 0',
2689' u-boot 138 4 u-boot 38',
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002690' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glass61f564d2019-07-08 14:25:48 -06002691' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002692' fdtmap %x 3bd fdtmap %x' %
Simon Glass61f564d2019-07-08 14:25:48 -06002693 (fdtmap_offset, fdtmap_offset),
2694' image-header bf8 8 image-header bf8',
2695 ]
2696 self.assertEqual(expected, lines)
2697
2698 def testListCmdFail(self):
2699 """Test failing to list an image"""
2700 self._DoReadFile('005_simple.dts')
Simon Glassf86a7362019-07-20 12:24:10 -06002701 try:
2702 tmpdir, updated_fname = self._SetupImageInTmpdir()
2703 with self.assertRaises(ValueError) as e:
2704 self._DoBinman('ls', '-i', updated_fname)
2705 finally:
2706 shutil.rmtree(tmpdir)
Simon Glass61f564d2019-07-08 14:25:48 -06002707 self.assertIn("Cannot find FDT map in image", str(e.exception))
2708
2709 def _RunListCmd(self, paths, expected):
2710 """List out entries and check the result
2711
2712 Args:
2713 paths: List of paths to pass to the list command
2714 expected: Expected list of filenames to be returned, in order
2715 """
2716 self._CheckLz4()
2717 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2718 image_fname = tools.GetOutputFilename('image.bin')
2719 image = Image.FromFile(image_fname)
2720 lines = image.GetListEntries(paths)[1]
2721 files = [line[0].strip() for line in lines[1:]]
2722 self.assertEqual(expected, files)
2723
2724 def testListCmdSection(self):
2725 """Test listing the files in a section"""
2726 self._RunListCmd(['section'],
2727 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2728
2729 def testListCmdFile(self):
2730 """Test listing a particular file"""
2731 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2732
2733 def testListCmdWildcard(self):
2734 """Test listing a wildcarded file"""
2735 self._RunListCmd(['*boot*'],
2736 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2737
2738 def testListCmdWildcardMulti(self):
2739 """Test listing a wildcarded file"""
2740 self._RunListCmd(['*cb*', '*head*'],
2741 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2742
2743 def testListCmdEmpty(self):
2744 """Test listing a wildcarded file"""
2745 self._RunListCmd(['nothing'], [])
2746
2747 def testListCmdPath(self):
2748 """Test listing the files in a sub-entry of a section"""
2749 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2750
Simon Glassf667e452019-07-08 14:25:50 -06002751 def _RunExtractCmd(self, entry_name, decomp=True):
2752 """Extract an entry from an image
2753
2754 Args:
2755 entry_name: Entry name to extract
2756 decomp: True to decompress the data if compressed, False to leave
2757 it in its raw uncompressed format
2758
2759 Returns:
2760 data from entry
2761 """
2762 self._CheckLz4()
2763 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2764 image_fname = tools.GetOutputFilename('image.bin')
2765 return control.ReadEntry(image_fname, entry_name, decomp)
2766
2767 def testExtractSimple(self):
2768 """Test extracting a single file"""
2769 data = self._RunExtractCmd('u-boot')
2770 self.assertEqual(U_BOOT_DATA, data)
2771
Simon Glass71ce0ba2019-07-08 14:25:52 -06002772 def testExtractSection(self):
2773 """Test extracting the files in a section"""
2774 data = self._RunExtractCmd('section')
2775 cbfs_data = data[:0x400]
2776 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002777 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass71ce0ba2019-07-08 14:25:52 -06002778 dtb_data = data[0x400:]
2779 dtb = self._decompress(dtb_data)
2780 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2781
2782 def testExtractCompressed(self):
2783 """Test extracting compressed data"""
2784 data = self._RunExtractCmd('section/u-boot-dtb')
2785 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2786
2787 def testExtractRaw(self):
2788 """Test extracting compressed data without decompressing it"""
2789 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2790 dtb = self._decompress(data)
2791 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2792
2793 def testExtractCbfs(self):
2794 """Test extracting CBFS data"""
2795 data = self._RunExtractCmd('section/cbfs/u-boot')
2796 self.assertEqual(U_BOOT_DATA, data)
2797
2798 def testExtractCbfsCompressed(self):
2799 """Test extracting CBFS compressed data"""
2800 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2801 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2802
2803 def testExtractCbfsRaw(self):
2804 """Test extracting CBFS compressed data without decompressing it"""
2805 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Simon Glasseb0f4a42019-07-20 12:24:06 -06002806 dtb = tools.Decompress(data, 'lzma', with_header=False)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002807 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2808
Simon Glassf667e452019-07-08 14:25:50 -06002809 def testExtractBadEntry(self):
2810 """Test extracting a bad section path"""
2811 with self.assertRaises(ValueError) as e:
2812 self._RunExtractCmd('section/does-not-exist')
2813 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2814 str(e.exception))
2815
2816 def testExtractMissingFile(self):
2817 """Test extracting file that does not exist"""
2818 with self.assertRaises(IOError) as e:
2819 control.ReadEntry('missing-file', 'name')
2820
2821 def testExtractBadFile(self):
2822 """Test extracting an invalid file"""
2823 fname = os.path.join(self._indir, 'badfile')
2824 tools.WriteFile(fname, b'')
2825 with self.assertRaises(ValueError) as e:
2826 control.ReadEntry(fname, 'name')
2827
Simon Glass71ce0ba2019-07-08 14:25:52 -06002828 def testExtractCmd(self):
2829 """Test extracting a file fron an image on the command line"""
2830 self._CheckLz4()
2831 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass71ce0ba2019-07-08 14:25:52 -06002832 fname = os.path.join(self._indir, 'output.extact')
Simon Glassf86a7362019-07-20 12:24:10 -06002833 try:
2834 tmpdir, updated_fname = self._SetupImageInTmpdir()
2835 with test_util.capture_sys_output() as (stdout, stderr):
2836 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2837 '-f', fname)
2838 finally:
2839 shutil.rmtree(tmpdir)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002840 data = tools.ReadFile(fname)
2841 self.assertEqual(U_BOOT_DATA, data)
2842
2843 def testExtractOneEntry(self):
2844 """Test extracting a single entry fron an image """
2845 self._CheckLz4()
2846 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2847 image_fname = tools.GetOutputFilename('image.bin')
2848 fname = os.path.join(self._indir, 'output.extact')
2849 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
2850 data = tools.ReadFile(fname)
2851 self.assertEqual(U_BOOT_DATA, data)
2852
2853 def _CheckExtractOutput(self, decomp):
2854 """Helper to test file output with and without decompression
2855
2856 Args:
2857 decomp: True to decompress entry data, False to output it raw
2858 """
2859 def _CheckPresent(entry_path, expect_data, expect_size=None):
2860 """Check and remove expected file
2861
2862 This checks the data/size of a file and removes the file both from
2863 the outfiles set and from the output directory. Once all files are
2864 processed, both the set and directory should be empty.
2865
2866 Args:
2867 entry_path: Entry path
2868 expect_data: Data to expect in file, or None to skip check
2869 expect_size: Size of data to expect in file, or None to skip
2870 """
2871 path = os.path.join(outdir, entry_path)
2872 data = tools.ReadFile(path)
2873 os.remove(path)
2874 if expect_data:
2875 self.assertEqual(expect_data, data)
2876 elif expect_size:
2877 self.assertEqual(expect_size, len(data))
2878 outfiles.remove(path)
2879
2880 def _CheckDirPresent(name):
2881 """Remove expected directory
2882
2883 This gives an error if the directory does not exist as expected
2884
2885 Args:
2886 name: Name of directory to remove
2887 """
2888 path = os.path.join(outdir, name)
2889 os.rmdir(path)
2890
2891 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2892 image_fname = tools.GetOutputFilename('image.bin')
2893 outdir = os.path.join(self._indir, 'extract')
2894 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2895
2896 # Create a set of all file that were output (should be 9)
2897 outfiles = set()
2898 for root, dirs, files in os.walk(outdir):
2899 outfiles |= set([os.path.join(root, fname) for fname in files])
2900 self.assertEqual(9, len(outfiles))
2901 self.assertEqual(9, len(einfos))
2902
2903 image = control.images['image']
2904 entries = image.GetEntries()
2905
2906 # Check the 9 files in various ways
2907 section = entries['section']
2908 section_entries = section.GetEntries()
2909 cbfs_entries = section_entries['cbfs'].GetEntries()
2910 _CheckPresent('u-boot', U_BOOT_DATA)
2911 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
2912 dtb_len = EXTRACT_DTB_SIZE
2913 if not decomp:
2914 dtb_len = cbfs_entries['u-boot-dtb'].size
2915 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
2916 if not decomp:
2917 dtb_len = section_entries['u-boot-dtb'].size
2918 _CheckPresent('section/u-boot-dtb', None, dtb_len)
2919
2920 fdtmap = entries['fdtmap']
2921 _CheckPresent('fdtmap', fdtmap.data)
2922 hdr = entries['image-header']
2923 _CheckPresent('image-header', hdr.data)
2924
2925 _CheckPresent('section/root', section.data)
2926 cbfs = section_entries['cbfs']
2927 _CheckPresent('section/cbfs/root', cbfs.data)
2928 data = tools.ReadFile(image_fname)
2929 _CheckPresent('root', data)
2930
2931 # There should be no files left. Remove all the directories to check.
2932 # If there are any files/dirs remaining, one of these checks will fail.
2933 self.assertEqual(0, len(outfiles))
2934 _CheckDirPresent('section/cbfs')
2935 _CheckDirPresent('section')
2936 _CheckDirPresent('')
2937 self.assertFalse(os.path.exists(outdir))
2938
2939 def testExtractAllEntries(self):
2940 """Test extracting all entries"""
2941 self._CheckLz4()
2942 self._CheckExtractOutput(decomp=True)
2943
2944 def testExtractAllEntriesRaw(self):
2945 """Test extracting all entries without decompressing them"""
2946 self._CheckLz4()
2947 self._CheckExtractOutput(decomp=False)
2948
2949 def testExtractSelectedEntries(self):
2950 """Test extracting some entries"""
2951 self._CheckLz4()
2952 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2953 image_fname = tools.GetOutputFilename('image.bin')
2954 outdir = os.path.join(self._indir, 'extract')
2955 einfos = control.ExtractEntries(image_fname, None, outdir,
2956 ['*cb*', '*head*'])
2957
2958 # File output is tested by testExtractAllEntries(), so just check that
2959 # the expected entries are selected
2960 names = [einfo.name for einfo in einfos]
2961 self.assertEqual(names,
2962 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2963
2964 def testExtractNoEntryPaths(self):
2965 """Test extracting some entries"""
2966 self._CheckLz4()
2967 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2968 image_fname = tools.GetOutputFilename('image.bin')
2969 with self.assertRaises(ValueError) as e:
2970 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassbb5edc12019-07-20 12:24:14 -06002971 self.assertIn('Must specify an entry path to write with -f',
Simon Glass71ce0ba2019-07-08 14:25:52 -06002972 str(e.exception))
2973
2974 def testExtractTooManyEntryPaths(self):
2975 """Test extracting some entries"""
2976 self._CheckLz4()
2977 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2978 image_fname = tools.GetOutputFilename('image.bin')
2979 with self.assertRaises(ValueError) as e:
2980 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassbb5edc12019-07-20 12:24:14 -06002981 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass71ce0ba2019-07-08 14:25:52 -06002982 str(e.exception))
2983
Simon Glasse2705fa2019-07-08 14:25:53 -06002984 def testPackAlignSection(self):
2985 """Test that sections can have alignment"""
2986 self._DoReadFile('131_pack_align_section.dts')
2987
2988 self.assertIn('image', control.images)
2989 image = control.images['image']
2990 entries = image.GetEntries()
2991 self.assertEqual(3, len(entries))
2992
2993 # First u-boot
2994 self.assertIn('u-boot', entries)
2995 entry = entries['u-boot']
2996 self.assertEqual(0, entry.offset)
2997 self.assertEqual(0, entry.image_pos)
2998 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2999 self.assertEqual(len(U_BOOT_DATA), entry.size)
3000
3001 # Section0
3002 self.assertIn('section0', entries)
3003 section0 = entries['section0']
3004 self.assertEqual(0x10, section0.offset)
3005 self.assertEqual(0x10, section0.image_pos)
3006 self.assertEqual(len(U_BOOT_DATA), section0.size)
3007
3008 # Second u-boot
3009 section_entries = section0.GetEntries()
3010 self.assertIn('u-boot', section_entries)
3011 entry = section_entries['u-boot']
3012 self.assertEqual(0, entry.offset)
3013 self.assertEqual(0x10, entry.image_pos)
3014 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3015 self.assertEqual(len(U_BOOT_DATA), entry.size)
3016
3017 # Section1
3018 self.assertIn('section1', entries)
3019 section1 = entries['section1']
3020 self.assertEqual(0x14, section1.offset)
3021 self.assertEqual(0x14, section1.image_pos)
3022 self.assertEqual(0x20, section1.size)
3023
3024 # Second u-boot
3025 section_entries = section1.GetEntries()
3026 self.assertIn('u-boot', section_entries)
3027 entry = section_entries['u-boot']
3028 self.assertEqual(0, entry.offset)
3029 self.assertEqual(0x14, entry.image_pos)
3030 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3031 self.assertEqual(len(U_BOOT_DATA), entry.size)
3032
3033 # Section2
3034 self.assertIn('section2', section_entries)
3035 section2 = section_entries['section2']
3036 self.assertEqual(0x4, section2.offset)
3037 self.assertEqual(0x18, section2.image_pos)
3038 self.assertEqual(4, section2.size)
3039
3040 # Third u-boot
3041 section_entries = section2.GetEntries()
3042 self.assertIn('u-boot', section_entries)
3043 entry = section_entries['u-boot']
3044 self.assertEqual(0, entry.offset)
3045 self.assertEqual(0x18, entry.image_pos)
3046 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3047 self.assertEqual(len(U_BOOT_DATA), entry.size)
3048
Simon Glass51014aa2019-07-20 12:23:56 -06003049 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3050 dts='132_replace.dts'):
Simon Glass10f9d002019-07-20 12:23:50 -06003051 """Replace an entry in an image
3052
3053 This writes the entry data to update it, then opens the updated file and
3054 returns the value that it now finds there.
3055
3056 Args:
3057 entry_name: Entry name to replace
3058 data: Data to replace it with
3059 decomp: True to compress the data if needed, False if data is
3060 already compressed so should be used as is
Simon Glass51014aa2019-07-20 12:23:56 -06003061 allow_resize: True to allow entries to change size, False to raise
3062 an exception
Simon Glass10f9d002019-07-20 12:23:50 -06003063
3064 Returns:
3065 Tuple:
3066 data from entry
3067 data from fdtmap (excluding header)
Simon Glass51014aa2019-07-20 12:23:56 -06003068 Image object that was modified
Simon Glass10f9d002019-07-20 12:23:50 -06003069 """
Simon Glass51014aa2019-07-20 12:23:56 -06003070 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass10f9d002019-07-20 12:23:50 -06003071 update_dtb=True)[1]
3072
3073 self.assertIn('image', control.images)
3074 image = control.images['image']
3075 entries = image.GetEntries()
3076 orig_dtb_data = entries['u-boot-dtb'].data
3077 orig_fdtmap_data = entries['fdtmap'].data
3078
3079 image_fname = tools.GetOutputFilename('image.bin')
3080 updated_fname = tools.GetOutputFilename('image-updated.bin')
3081 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
Simon Glass51014aa2019-07-20 12:23:56 -06003082 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3083 allow_resize)
Simon Glass10f9d002019-07-20 12:23:50 -06003084 data = control.ReadEntry(updated_fname, entry_name, decomp)
3085
Simon Glass51014aa2019-07-20 12:23:56 -06003086 # The DT data should not change unless resized:
3087 if not allow_resize:
3088 new_dtb_data = entries['u-boot-dtb'].data
3089 self.assertEqual(new_dtb_data, orig_dtb_data)
3090 new_fdtmap_data = entries['fdtmap'].data
3091 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass10f9d002019-07-20 12:23:50 -06003092
Simon Glass51014aa2019-07-20 12:23:56 -06003093 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass10f9d002019-07-20 12:23:50 -06003094
3095 def testReplaceSimple(self):
3096 """Test replacing a single file"""
3097 expected = b'x' * len(U_BOOT_DATA)
Simon Glass51014aa2019-07-20 12:23:56 -06003098 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3099 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06003100 self.assertEqual(expected, data)
3101
3102 # Test that the state looks right. There should be an FDT for the fdtmap
3103 # that we jsut read back in, and it should match what we find in the
3104 # 'control' tables. Checking for an FDT that does not exist should
3105 # return None.
3106 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glass51014aa2019-07-20 12:23:56 -06003107 self.assertIsNotNone(path)
Simon Glass10f9d002019-07-20 12:23:50 -06003108 self.assertEqual(expected_fdtmap, fdtmap)
3109
3110 dtb = state.GetFdtForEtype('fdtmap')
3111 self.assertEqual(dtb.GetContents(), fdtmap)
3112
3113 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3114 self.assertIsNone(missing_path)
3115 self.assertIsNone(missing_fdtmap)
3116
3117 missing_dtb = state.GetFdtForEtype('missing')
3118 self.assertIsNone(missing_dtb)
3119
3120 self.assertEqual('/binman', state.fdt_path_prefix)
3121
3122 def testReplaceResizeFail(self):
3123 """Test replacing a file by something larger"""
3124 expected = U_BOOT_DATA + b'x'
3125 with self.assertRaises(ValueError) as e:
Simon Glass51014aa2019-07-20 12:23:56 -06003126 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3127 dts='139_replace_repack.dts')
Simon Glass10f9d002019-07-20 12:23:50 -06003128 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3129 str(e.exception))
3130
3131 def testReplaceMulti(self):
3132 """Test replacing entry data where multiple images are generated"""
3133 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3134 update_dtb=True)[0]
3135 expected = b'x' * len(U_BOOT_DATA)
3136 updated_fname = tools.GetOutputFilename('image-updated.bin')
3137 tools.WriteFile(updated_fname, data)
3138 entry_name = 'u-boot'
Simon Glass51014aa2019-07-20 12:23:56 -06003139 control.WriteEntry(updated_fname, entry_name, expected,
3140 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06003141 data = control.ReadEntry(updated_fname, entry_name)
3142 self.assertEqual(expected, data)
3143
3144 # Check the state looks right.
3145 self.assertEqual('/binman/image', state.fdt_path_prefix)
3146
3147 # Now check we can write the first image
3148 image_fname = tools.GetOutputFilename('first-image.bin')
3149 updated_fname = tools.GetOutputFilename('first-updated.bin')
3150 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
3151 entry_name = 'u-boot'
Simon Glass51014aa2019-07-20 12:23:56 -06003152 control.WriteEntry(updated_fname, entry_name, expected,
3153 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06003154 data = control.ReadEntry(updated_fname, entry_name)
3155 self.assertEqual(expected, data)
3156
3157 # Check the state looks right.
3158 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass8beb11e2019-07-08 14:25:47 -06003159
Simon Glass12bb1a92019-07-20 12:23:51 -06003160 def testUpdateFdtAllRepack(self):
3161 """Test that all device trees are updated with offset/size info"""
3162 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3163 SECTION_SIZE = 0x300
3164 DTB_SIZE = 602
3165 FDTMAP_SIZE = 608
3166 base_expected = {
3167 'offset': 0,
3168 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3169 'image-pos': 0,
3170 'section:offset': 0,
3171 'section:size': SECTION_SIZE,
3172 'section:image-pos': 0,
3173 'section/u-boot-dtb:offset': 4,
3174 'section/u-boot-dtb:size': 636,
3175 'section/u-boot-dtb:image-pos': 4,
3176 'u-boot-spl-dtb:offset': SECTION_SIZE,
3177 'u-boot-spl-dtb:size': DTB_SIZE,
3178 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3179 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3180 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3181 'u-boot-tpl-dtb:size': DTB_SIZE,
3182 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3183 'fdtmap:size': FDTMAP_SIZE,
3184 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3185 }
3186 main_expected = {
3187 'section:orig-size': SECTION_SIZE,
3188 'section/u-boot-dtb:orig-offset': 4,
3189 }
3190
3191 # We expect three device-tree files in the output, with the first one
3192 # within a fixed-size section.
3193 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3194 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3195 # main U-Boot tree. All three should have the same positions and offset
3196 # except that the main tree should include the main_expected properties
3197 start = 4
3198 for item in ['', 'spl', 'tpl', None]:
3199 if item is None:
3200 start += 16 # Move past fdtmap header
3201 dtb = fdt.Fdt.FromData(data[start:])
3202 dtb.Scan()
3203 props = self._GetPropTree(dtb,
3204 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3205 prefix='/' if item is None else '/binman/')
3206 expected = dict(base_expected)
3207 if item:
3208 expected[item] = 0
3209 else:
3210 # Main DTB and fdtdec should include the 'orig-' properties
3211 expected.update(main_expected)
3212 # Helpful for debugging:
3213 #for prop in sorted(props):
3214 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3215 self.assertEqual(expected, props)
3216 if item == '':
3217 start = SECTION_SIZE
3218 else:
3219 start += dtb._fdt_obj.totalsize()
3220
Simon Glasseba1f0c2019-07-20 12:23:55 -06003221 def testFdtmapHeaderMiddle(self):
3222 """Test an FDT map in the middle of an image when it should be at end"""
3223 with self.assertRaises(ValueError) as e:
3224 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3225 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3226 str(e.exception))
3227
3228 def testFdtmapHeaderStartBad(self):
3229 """Test an FDT map in middle of an image when it should be at start"""
3230 with self.assertRaises(ValueError) as e:
3231 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3232 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3233 str(e.exception))
3234
3235 def testFdtmapHeaderEndBad(self):
3236 """Test an FDT map at the start of an image when it should be at end"""
3237 with self.assertRaises(ValueError) as e:
3238 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3239 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3240 str(e.exception))
3241
3242 def testFdtmapHeaderNoSize(self):
3243 """Test an image header at the end of an image with undefined size"""
3244 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3245
Simon Glass51014aa2019-07-20 12:23:56 -06003246 def testReplaceResize(self):
3247 """Test replacing a single file in an entry with a larger file"""
3248 expected = U_BOOT_DATA + b'x'
3249 data, _, image = self._RunReplaceCmd('u-boot', expected,
3250 dts='139_replace_repack.dts')
3251 self.assertEqual(expected, data)
3252
3253 entries = image.GetEntries()
3254 dtb_data = entries['u-boot-dtb'].data
3255 dtb = fdt.Fdt.FromData(dtb_data)
3256 dtb.Scan()
3257
3258 # The u-boot section should now be larger in the dtb
3259 node = dtb.GetNode('/binman/u-boot')
3260 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3261
3262 # Same for the fdtmap
3263 fdata = entries['fdtmap'].data
3264 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3265 fdtb.Scan()
3266 fnode = fdtb.GetNode('/u-boot')
3267 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3268
3269 def testReplaceResizeNoRepack(self):
3270 """Test replacing an entry with a larger file when not allowed"""
3271 expected = U_BOOT_DATA + b'x'
3272 with self.assertRaises(ValueError) as e:
3273 self._RunReplaceCmd('u-boot', expected)
3274 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3275 str(e.exception))
3276
Simon Glass61ec04f2019-07-20 12:23:58 -06003277 def testEntryShrink(self):
3278 """Test contracting an entry after it is packed"""
3279 try:
3280 state.SetAllowEntryContraction(True)
3281 data = self._DoReadFileDtb('140_entry_shrink.dts',
3282 update_dtb=True)[0]
3283 finally:
3284 state.SetAllowEntryContraction(False)
3285 self.assertEqual(b'a', data[:1])
3286 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3287 self.assertEqual(b'a', data[-1:])
3288
3289 def testEntryShrinkFail(self):
3290 """Test not being allowed to contract an entry after it is packed"""
3291 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3292
3293 # In this case there is a spare byte at the end of the data. The size of
3294 # the contents is only 1 byte but we still have the size before it
3295 # shrunk.
3296 self.assertEqual(b'a\0', data[:2])
3297 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3298 self.assertEqual(b'a\0', data[-2:])
3299
Simon Glass27145fd2019-07-20 12:24:01 -06003300 def testDescriptorOffset(self):
3301 """Test that the Intel descriptor is always placed at at the start"""
3302 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3303 image = control.images['image']
3304 entries = image.GetEntries()
3305 desc = entries['intel-descriptor']
3306 self.assertEqual(0xff800000, desc.offset);
3307 self.assertEqual(0xff800000, desc.image_pos);
3308
Simon Glasseb0f4a42019-07-20 12:24:06 -06003309 def testReplaceCbfs(self):
3310 """Test replacing a single file in CBFS without changing the size"""
3311 self._CheckLz4()
3312 expected = b'x' * len(U_BOOT_DATA)
3313 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3314 updated_fname = tools.GetOutputFilename('image-updated.bin')
3315 tools.WriteFile(updated_fname, data)
3316 entry_name = 'section/cbfs/u-boot'
3317 control.WriteEntry(updated_fname, entry_name, expected,
3318 allow_resize=True)
3319 data = control.ReadEntry(updated_fname, entry_name)
3320 self.assertEqual(expected, data)
3321
3322 def testReplaceResizeCbfs(self):
3323 """Test replacing a single file in CBFS with one of a different size"""
3324 self._CheckLz4()
3325 expected = U_BOOT_DATA + b'x'
3326 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3327 updated_fname = tools.GetOutputFilename('image-updated.bin')
3328 tools.WriteFile(updated_fname, data)
3329 entry_name = 'section/cbfs/u-boot'
3330 control.WriteEntry(updated_fname, entry_name, expected,
3331 allow_resize=True)
3332 data = control.ReadEntry(updated_fname, entry_name)
3333 self.assertEqual(expected, data)
3334
Simon Glassa6cb9952019-07-20 12:24:15 -06003335 def _SetupForReplace(self):
3336 """Set up some files to use to replace entries
3337
3338 This generates an image, copies it to a new file, extracts all the files
3339 in it and updates some of them
3340
3341 Returns:
3342 List
3343 Image filename
3344 Output directory
3345 Expected values for updated entries, each a string
3346 """
3347 data = self._DoReadFileRealDtb('143_replace_all.dts')
3348
3349 updated_fname = tools.GetOutputFilename('image-updated.bin')
3350 tools.WriteFile(updated_fname, data)
3351
3352 outdir = os.path.join(self._indir, 'extract')
3353 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3354
3355 expected1 = b'x' + U_BOOT_DATA + b'y'
3356 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3357 tools.WriteFile(u_boot_fname1, expected1)
3358
3359 expected2 = b'a' + U_BOOT_DATA + b'b'
3360 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
3361 tools.WriteFile(u_boot_fname2, expected2)
3362
3363 expected_text = b'not the same text'
3364 text_fname = os.path.join(outdir, 'text')
3365 tools.WriteFile(text_fname, expected_text)
3366
3367 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3368 dtb = fdt.FdtScan(dtb_fname)
3369 node = dtb.GetNode('/binman/text')
3370 node.AddString('my-property', 'the value')
3371 dtb.Sync(auto_resize=True)
3372 dtb.Flush()
3373
3374 return updated_fname, outdir, expected1, expected2, expected_text
3375
3376 def _CheckReplaceMultiple(self, entry_paths):
3377 """Handle replacing the contents of multiple entries
3378
3379 Args:
3380 entry_paths: List of entry paths to replace
3381
3382 Returns:
3383 List
3384 Dict of entries in the image:
3385 key: Entry name
3386 Value: Entry object
3387 Expected values for updated entries, each a string
3388 """
3389 updated_fname, outdir, expected1, expected2, expected_text = (
3390 self._SetupForReplace())
3391 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3392
3393 image = Image.FromFile(updated_fname)
3394 image.LoadData()
3395 return image.GetEntries(), expected1, expected2, expected_text
3396
3397 def testReplaceAll(self):
3398 """Test replacing the contents of all entries"""
3399 entries, expected1, expected2, expected_text = (
3400 self._CheckReplaceMultiple([]))
3401 data = entries['u-boot'].data
3402 self.assertEqual(expected1, data)
3403
3404 data = entries['u-boot2'].data
3405 self.assertEqual(expected2, data)
3406
3407 data = entries['text'].data
3408 self.assertEqual(expected_text, data)
3409
3410 # Check that the device tree is updated
3411 data = entries['u-boot-dtb'].data
3412 dtb = fdt.Fdt.FromData(data)
3413 dtb.Scan()
3414 node = dtb.GetNode('/binman/text')
3415 self.assertEqual('the value', node.props['my-property'].value)
3416
3417 def testReplaceSome(self):
3418 """Test replacing the contents of a few entries"""
3419 entries, expected1, expected2, expected_text = (
3420 self._CheckReplaceMultiple(['u-boot2', 'text']))
3421
3422 # This one should not change
3423 data = entries['u-boot'].data
3424 self.assertEqual(U_BOOT_DATA, data)
3425
3426 data = entries['u-boot2'].data
3427 self.assertEqual(expected2, data)
3428
3429 data = entries['text'].data
3430 self.assertEqual(expected_text, data)
3431
3432 def testReplaceCmd(self):
3433 """Test replacing a file fron an image on the command line"""
3434 self._DoReadFileRealDtb('143_replace_all.dts')
3435
3436 try:
3437 tmpdir, updated_fname = self._SetupImageInTmpdir()
3438
3439 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3440 expected = b'x' * len(U_BOOT_DATA)
3441 tools.WriteFile(fname, expected)
3442
3443 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
3444 data = tools.ReadFile(updated_fname)
3445 self.assertEqual(expected, data[:len(expected)])
3446 map_fname = os.path.join(tmpdir, 'image-updated.map')
3447 self.assertFalse(os.path.exists(map_fname))
3448 finally:
3449 shutil.rmtree(tmpdir)
3450
3451 def testReplaceCmdSome(self):
3452 """Test replacing some files fron an image on the command line"""
3453 updated_fname, outdir, expected1, expected2, expected_text = (
3454 self._SetupForReplace())
3455
3456 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3457 'u-boot2', 'text')
3458
3459 tools.PrepareOutputDir(None)
3460 image = Image.FromFile(updated_fname)
3461 image.LoadData()
3462 entries = image.GetEntries()
3463
3464 # This one should not change
3465 data = entries['u-boot'].data
3466 self.assertEqual(U_BOOT_DATA, data)
3467
3468 data = entries['u-boot2'].data
3469 self.assertEqual(expected2, data)
3470
3471 data = entries['text'].data
3472 self.assertEqual(expected_text, data)
3473
3474 def testReplaceMissing(self):
3475 """Test replacing entries where the file is missing"""
3476 updated_fname, outdir, expected1, expected2, expected_text = (
3477 self._SetupForReplace())
3478
3479 # Remove one of the files, to generate a warning
3480 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3481 os.remove(u_boot_fname1)
3482
3483 with test_util.capture_sys_output() as (stdout, stderr):
3484 control.ReplaceEntries(updated_fname, None, outdir, [])
3485 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass38fdb4c2020-07-09 18:39:39 -06003486 stderr.getvalue())
Simon Glassa6cb9952019-07-20 12:24:15 -06003487
3488 def testReplaceCmdMap(self):
3489 """Test replacing a file fron an image on the command line"""
3490 self._DoReadFileRealDtb('143_replace_all.dts')
3491
3492 try:
3493 tmpdir, updated_fname = self._SetupImageInTmpdir()
3494
3495 fname = os.path.join(self._indir, 'update-u-boot.bin')
3496 expected = b'x' * len(U_BOOT_DATA)
3497 tools.WriteFile(fname, expected)
3498
3499 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3500 '-f', fname, '-m')
3501 map_fname = os.path.join(tmpdir, 'image-updated.map')
3502 self.assertTrue(os.path.exists(map_fname))
3503 finally:
3504 shutil.rmtree(tmpdir)
3505
3506 def testReplaceNoEntryPaths(self):
3507 """Test replacing an entry without an entry path"""
3508 self._DoReadFileRealDtb('143_replace_all.dts')
3509 image_fname = tools.GetOutputFilename('image.bin')
3510 with self.assertRaises(ValueError) as e:
3511 control.ReplaceEntries(image_fname, 'fname', None, [])
3512 self.assertIn('Must specify an entry path to read with -f',
3513 str(e.exception))
3514
3515 def testReplaceTooManyEntryPaths(self):
3516 """Test extracting some entries"""
3517 self._DoReadFileRealDtb('143_replace_all.dts')
3518 image_fname = tools.GetOutputFilename('image.bin')
3519 with self.assertRaises(ValueError) as e:
3520 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3521 self.assertIn('Must specify exactly one entry path to write with -f',
3522 str(e.exception))
3523
Simon Glass2250ee62019-08-24 07:22:48 -06003524 def testPackReset16(self):
3525 """Test that an image with an x86 reset16 region can be created"""
3526 data = self._DoReadFile('144_x86_reset16.dts')
3527 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3528
3529 def testPackReset16Spl(self):
3530 """Test that an image with an x86 reset16-spl region can be created"""
3531 data = self._DoReadFile('145_x86_reset16_spl.dts')
3532 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3533
3534 def testPackReset16Tpl(self):
3535 """Test that an image with an x86 reset16-tpl region can be created"""
3536 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3537 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3538
Simon Glass5af12072019-08-24 07:22:50 -06003539 def testPackIntelFit(self):
3540 """Test that an image with an Intel FIT and pointer can be created"""
3541 data = self._DoReadFile('147_intel_fit.dts')
3542 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3543 fit = data[16:32];
3544 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3545 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3546
3547 image = control.images['image']
3548 entries = image.GetEntries()
3549 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3550 self.assertEqual(expected_ptr, ptr)
3551
3552 def testPackIntelFitMissing(self):
3553 """Test detection of a FIT pointer with not FIT region"""
3554 with self.assertRaises(ValueError) as e:
3555 self._DoReadFile('148_intel_fit_missing.dts')
3556 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3557 str(e.exception))
3558
Simon Glass7c150132019-11-06 17:22:44 -07003559 def _CheckSymbolsTplSection(self, dts, expected_vals):
3560 data = self._DoReadFile(dts)
3561 sym_values = struct.pack('<LQLL', *expected_vals)
Simon Glass2090f1e2019-08-24 07:23:00 -06003562 upto1 = 4 + len(U_BOOT_SPL_DATA)
Simon Glassb87064c2019-08-24 07:23:05 -06003563 expected1 = tools.GetBytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[20:]
Simon Glass2090f1e2019-08-24 07:23:00 -06003564 self.assertEqual(expected1, data[:upto1])
3565
3566 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Simon Glassb87064c2019-08-24 07:23:05 -06003567 expected2 = tools.GetBytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[20:]
Simon Glass2090f1e2019-08-24 07:23:00 -06003568 self.assertEqual(expected2, data[upto1:upto2])
3569
Simon Glasseb0086f2019-08-24 07:23:04 -06003570 upto3 = 0x34 + len(U_BOOT_DATA)
3571 expected3 = tools.GetBytes(0xff, 1) + U_BOOT_DATA
Simon Glass2090f1e2019-08-24 07:23:00 -06003572 self.assertEqual(expected3, data[upto2:upto3])
3573
Simon Glassb87064c2019-08-24 07:23:05 -06003574 expected4 = sym_values + U_BOOT_TPL_DATA[20:]
Simon Glass7c150132019-11-06 17:22:44 -07003575 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3576
3577 def testSymbolsTplSection(self):
3578 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3579 self._SetupSplElf('u_boot_binman_syms')
3580 self._SetupTplElf('u_boot_binman_syms')
3581 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
3582 [0x04, 0x1c, 0x10 + 0x34, 0x04])
3583
3584 def testSymbolsTplSectionX86(self):
3585 """Test binman can assign symbols in a section with end-at-4gb"""
3586 self._SetupSplElf('u_boot_binman_syms_x86')
3587 self._SetupTplElf('u_boot_binman_syms_x86')
3588 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
3589 [0xffffff04, 0xffffff1c, 0xffffff34,
3590 0x04])
Simon Glass2090f1e2019-08-24 07:23:00 -06003591
Simon Glassbf4d0e22019-08-24 07:23:03 -06003592 def testPackX86RomIfwiSectiom(self):
3593 """Test that a section can be placed in an IFWI region"""
3594 self._SetupIfwi('fitimage.bin')
3595 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3596 self._CheckIfwi(data)
3597
Simon Glassea0fff92019-08-24 07:23:07 -06003598 def testPackFspM(self):
3599 """Test that an image with a FSP memory-init binary can be created"""
3600 data = self._DoReadFile('152_intel_fsp_m.dts')
3601 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3602
Simon Glassbc6a88f2019-10-20 21:31:35 -06003603 def testPackFspS(self):
3604 """Test that an image with a FSP silicon-init binary can be created"""
3605 data = self._DoReadFile('153_intel_fsp_s.dts')
3606 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassea0fff92019-08-24 07:23:07 -06003607
Simon Glass998d1482019-10-20 21:31:36 -06003608 def testPackFspT(self):
3609 """Test that an image with a FSP temp-ram-init binary can be created"""
3610 data = self._DoReadFile('154_intel_fsp_t.dts')
3611 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3612
Simon Glass0dc706f2020-07-09 18:39:31 -06003613 def testMkimage(self):
3614 """Test using mkimage to build an image"""
3615 data = self._DoReadFile('156_mkimage.dts')
3616
3617 # Just check that the data appears in the file somewhere
3618 self.assertIn(U_BOOT_SPL_DATA, data)
3619
Simon Glassce867ad2020-07-09 18:39:36 -06003620 def testExtblob(self):
3621 """Test an image with an external blob"""
3622 data = self._DoReadFile('157_blob_ext.dts')
3623 self.assertEqual(REFCODE_DATA, data)
3624
3625 def testExtblobMissing(self):
3626 """Test an image with a missing external blob"""
3627 with self.assertRaises(ValueError) as e:
3628 self._DoReadFile('158_blob_ext_missing.dts')
3629 self.assertIn("Filename 'missing-file' not found in input path",
3630 str(e.exception))
3631
Simon Glass4f9f1052020-07-09 18:39:38 -06003632 def testExtblobMissingOk(self):
3633 """Test an image with an missing external blob that is allowed"""
Simon Glassb1cca952020-07-09 18:39:40 -06003634 with test_util.capture_sys_output() as (stdout, stderr):
3635 self._DoTestFile('158_blob_ext_missing.dts', allow_missing=True)
3636 err = stderr.getvalue()
3637 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
3638
3639 def testExtblobMissingOkSect(self):
3640 """Test an image with an missing external blob that is allowed"""
3641 with test_util.capture_sys_output() as (stdout, stderr):
3642 self._DoTestFile('159_blob_ext_missing_sect.dts',
3643 allow_missing=True)
3644 err = stderr.getvalue()
3645 self.assertRegex(err, "Image 'main-section'.*missing.*: "
3646 "blob-ext blob-ext2")
Simon Glass4f9f1052020-07-09 18:39:38 -06003647
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003648 def testPackX86RomMeMissingDesc(self):
3649 """Test that an missing Intel descriptor entry is allowed"""
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003650 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass52b10dd2020-07-25 15:11:19 -06003651 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003652 err = stderr.getvalue()
3653 self.assertRegex(err,
3654 "Image 'main-section'.*missing.*: intel-descriptor")
3655
3656 def testPackX86RomMissingIfwi(self):
3657 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3658 self._SetupIfwi('fitimage.bin')
3659 pathname = os.path.join(self._indir, 'fitimage.bin')
3660 os.remove(pathname)
3661 with test_util.capture_sys_output() as (stdout, stderr):
3662 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3663 err = stderr.getvalue()
3664 self.assertRegex(err, "Image 'main-section'.*missing.*: intel-ifwi")
3665
Simon Glassb3295fd2020-07-09 18:39:42 -06003666 def testPackOverlap(self):
3667 """Test that zero-size overlapping regions are ignored"""
3668 self._DoTestFile('160_pack_overlap_zero.dts')
3669
Simon Glassfdc34362020-07-09 18:39:45 -06003670 def testSimpleFit(self):
3671 """Test an image with a FIT inside"""
3672 data = self._DoReadFile('161_fit.dts')
3673 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3674 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3675 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3676
3677 # The data should be inside the FIT
3678 dtb = fdt.Fdt.FromData(fit_data)
3679 dtb.Scan()
3680 fnode = dtb.GetNode('/images/kernel')
3681 self.assertIn('data', fnode.props)
3682
3683 fname = os.path.join(self._indir, 'fit_data.fit')
3684 tools.WriteFile(fname, fit_data)
3685 out = tools.Run('dumpimage', '-l', fname)
3686
3687 # Check a few features to make sure the plumbing works. We don't need
3688 # to test the operation of mkimage or dumpimage here. First convert the
3689 # output into a dict where the keys are the fields printed by dumpimage
3690 # and the values are a list of values for each field
3691 lines = out.splitlines()
3692
3693 # Converts "Compression: gzip compressed" into two groups:
3694 # 'Compression' and 'gzip compressed'
3695 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3696 vals = collections.defaultdict(list)
3697 for line in lines:
3698 mat = re_line.match(line)
3699 vals[mat.group(1)].append(mat.group(2))
3700
3701 self.assertEquals('FIT description: test-desc', lines[0])
3702 self.assertIn('Created:', lines[1])
3703 self.assertIn('Image 0 (kernel)', vals)
3704 self.assertIn('Hash value', vals)
3705 data_sizes = vals.get('Data Size')
3706 self.assertIsNotNone(data_sizes)
3707 self.assertEqual(2, len(data_sizes))
3708 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
3709 self.assertEqual(len(U_BOOT_DATA), int(data_sizes[0].split()[0]))
3710 self.assertEqual(len(U_BOOT_SPL_DTB_DATA), int(data_sizes[1].split()[0]))
3711
3712 def testFitExternal(self):
Simon Glasse9d336d2020-09-01 05:13:55 -06003713 """Test an image with an FIT with external images"""
Simon Glassfdc34362020-07-09 18:39:45 -06003714 data = self._DoReadFile('162_fit_external.dts')
3715 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3716
Simon Glass8bc78b72022-01-09 20:13:39 -07003717 # Size of the external-data region as set up by mkimage
3718 external_data_size = len(U_BOOT_DATA) + 2
3719 expected_size = (len(U_BOOT_DATA) + 0x400 +
3720 tools.Align(external_data_size, 4) +
3721 len(U_BOOT_NODTB_DATA))
3722
Simon Glassfdc34362020-07-09 18:39:45 -06003723 # The data should be outside the FIT
3724 dtb = fdt.Fdt.FromData(fit_data)
3725 dtb.Scan()
3726 fnode = dtb.GetNode('/images/kernel')
3727 self.assertNotIn('data', fnode.props)
Simon Glass8bc78b72022-01-09 20:13:39 -07003728 self.assertEqual(len(U_BOOT_DATA),
3729 fdt_util.fdt32_to_cpu(fnode.props['data-size'].value))
3730 fit_pos = 0x400;
3731 self.assertEqual(
3732 fit_pos,
3733 fdt_util.fdt32_to_cpu(fnode.props['data-position'].value))
3734
3735 self.assertEquals(expected_size, len(data))
3736 actual_pos = len(U_BOOT_DATA) + fit_pos
3737 self.assertEqual(U_BOOT_DATA + b'aa',
3738 data[actual_pos:actual_pos + external_data_size])
Simon Glass12bb1a92019-07-20 12:23:51 -06003739
Alper Nebi Yasak8001d0b2020-08-31 12:58:18 +03003740 def testSectionIgnoreHashSignature(self):
3741 """Test that sections ignore hash, signature nodes for its data"""
3742 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
3743 expected = (U_BOOT_DATA + U_BOOT_DATA)
3744 self.assertEqual(expected, data)
3745
Alper Nebi Yasak3fdeb142020-08-31 12:58:19 +03003746 def testPadInSections(self):
3747 """Test pad-before, pad-after for entries in sections"""
Simon Glassf90d9062020-10-26 17:40:09 -06003748 data, _, _, out_dtb_fname = self._DoReadFileDtb(
3749 '166_pad_in_sections.dts', update_dtb=True)
Alper Nebi Yasak3fdeb142020-08-31 12:58:19 +03003750 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
3751 U_BOOT_DATA + tools.GetBytes(ord('!'), 6) +
3752 U_BOOT_DATA)
3753 self.assertEqual(expected, data)
3754
Simon Glassf90d9062020-10-26 17:40:09 -06003755 dtb = fdt.Fdt(out_dtb_fname)
3756 dtb.Scan()
3757 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
3758 expected = {
3759 'image-pos': 0,
3760 'offset': 0,
3761 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
3762
3763 'section:image-pos': 0,
3764 'section:offset': 0,
3765 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
3766
3767 'section/before:image-pos': 0,
3768 'section/before:offset': 0,
3769 'section/before:size': len(U_BOOT_DATA),
3770
3771 'section/u-boot:image-pos': 4,
3772 'section/u-boot:offset': 4,
3773 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
3774
3775 'section/after:image-pos': 26,
3776 'section/after:offset': 26,
3777 'section/after:size': len(U_BOOT_DATA),
3778 }
3779 self.assertEqual(expected, props)
3780
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03003781 def testFitImageSubentryAlignment(self):
3782 """Test relative alignability of FIT image subentries"""
3783 entry_args = {
3784 'test-id': TEXT_DATA,
3785 }
3786 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
3787 entry_args=entry_args)
3788 dtb = fdt.Fdt.FromData(data)
3789 dtb.Scan()
3790
3791 node = dtb.GetNode('/images/kernel')
3792 data = dtb.GetProps(node)["data"].bytes
3793 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
3794 expected = (tools.GetBytes(0, 0x20) + U_BOOT_SPL_DATA +
3795 tools.GetBytes(0, align_pad) + U_BOOT_DATA)
3796 self.assertEqual(expected, data)
3797
3798 node = dtb.GetNode('/images/fdt-1')
3799 data = dtb.GetProps(node)["data"].bytes
3800 expected = (U_BOOT_SPL_DTB_DATA + tools.GetBytes(0, 20) +
3801 tools.ToBytes(TEXT_DATA) + tools.GetBytes(0, 30) +
3802 U_BOOT_DTB_DATA)
3803 self.assertEqual(expected, data)
3804
3805 def testFitExtblobMissingOk(self):
3806 """Test a FIT with a missing external blob that is allowed"""
3807 with test_util.capture_sys_output() as (stdout, stderr):
3808 self._DoTestFile('168_fit_missing_blob.dts',
3809 allow_missing=True)
3810 err = stderr.getvalue()
Simon Glassb2381432020-09-06 10:39:09 -06003811 self.assertRegex(err, "Image 'main-section'.*missing.*: atf-bl31")
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03003812
Simon Glass3decfa32020-09-01 05:13:54 -06003813 def testBlobNamedByArgMissing(self):
3814 """Test handling of a missing entry arg"""
3815 with self.assertRaises(ValueError) as e:
3816 self._DoReadFile('068_blob_named_by_arg.dts')
3817 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
3818 str(e.exception))
3819
Simon Glassdc2f81a2020-09-01 05:13:58 -06003820 def testPackBl31(self):
3821 """Test that an image with an ATF BL31 binary can be created"""
3822 data = self._DoReadFile('169_atf_bl31.dts')
3823 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
3824
Samuel Holland18bd4552020-10-21 21:12:15 -05003825 def testPackScp(self):
3826 """Test that an image with an SCP binary can be created"""
3827 data = self._DoReadFile('172_scp.dts')
3828 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
3829
Simon Glass6cf99532020-09-01 05:13:59 -06003830 def testFitFdt(self):
3831 """Test an image with an FIT with multiple FDT images"""
3832 def _CheckFdt(seq, expected_data):
3833 """Check the FDT nodes
3834
3835 Args:
3836 seq: Sequence number to check (0 or 1)
3837 expected_data: Expected contents of 'data' property
3838 """
3839 name = 'fdt-%d' % seq
3840 fnode = dtb.GetNode('/images/%s' % name)
3841 self.assertIsNotNone(fnode)
3842 self.assertEqual({'description','type', 'compression', 'data'},
3843 set(fnode.props.keys()))
3844 self.assertEqual(expected_data, fnode.props['data'].bytes)
3845 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
3846 fnode.props['description'].value)
3847
3848 def _CheckConfig(seq, expected_data):
3849 """Check the configuration nodes
3850
3851 Args:
3852 seq: Sequence number to check (0 or 1)
3853 expected_data: Expected contents of 'data' property
3854 """
3855 cnode = dtb.GetNode('/configurations')
3856 self.assertIn('default', cnode.props)
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003857 self.assertEqual('config-2', cnode.props['default'].value)
Simon Glass6cf99532020-09-01 05:13:59 -06003858
3859 name = 'config-%d' % seq
3860 fnode = dtb.GetNode('/configurations/%s' % name)
3861 self.assertIsNotNone(fnode)
3862 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
3863 set(fnode.props.keys()))
3864 self.assertEqual('conf-test-fdt%d.dtb' % seq,
3865 fnode.props['description'].value)
3866 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
3867
3868 entry_args = {
3869 'of-list': 'test-fdt1 test-fdt2',
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003870 'default-dt': 'test-fdt2',
Simon Glass6cf99532020-09-01 05:13:59 -06003871 }
3872 data = self._DoReadFileDtb(
Bin Mengaa75ce92021-05-10 20:23:32 +08003873 '170_fit_fdt.dts',
Simon Glass6cf99532020-09-01 05:13:59 -06003874 entry_args=entry_args,
3875 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3876 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3877 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3878
3879 dtb = fdt.Fdt.FromData(fit_data)
3880 dtb.Scan()
3881 fnode = dtb.GetNode('/images/kernel')
3882 self.assertIn('data', fnode.props)
3883
3884 # Check all the properties in fdt-1 and fdt-2
3885 _CheckFdt(1, TEST_FDT1_DATA)
3886 _CheckFdt(2, TEST_FDT2_DATA)
3887
3888 # Check configurations
3889 _CheckConfig(1, TEST_FDT1_DATA)
3890 _CheckConfig(2, TEST_FDT2_DATA)
3891
3892 def testFitFdtMissingList(self):
3893 """Test handling of a missing 'of-list' entry arg"""
3894 with self.assertRaises(ValueError) as e:
Bin Mengaa75ce92021-05-10 20:23:32 +08003895 self._DoReadFile('170_fit_fdt.dts')
Simon Glass6cf99532020-09-01 05:13:59 -06003896 self.assertIn("Generator node requires 'of-list' entry argument",
3897 str(e.exception))
3898
3899 def testFitFdtEmptyList(self):
3900 """Test handling of an empty 'of-list' entry arg"""
3901 entry_args = {
3902 'of-list': '',
3903 }
3904 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
3905
3906 def testFitFdtMissingProp(self):
3907 """Test handling of a missing 'fit,fdt-list' property"""
3908 with self.assertRaises(ValueError) as e:
3909 self._DoReadFile('171_fit_fdt_missing_prop.dts')
3910 self.assertIn("Generator node requires 'fit,fdt-list' property",
3911 str(e.exception))
Simon Glassdc2f81a2020-09-01 05:13:58 -06003912
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003913 def testFitFdtEmptyList(self):
3914 """Test handling of an empty 'of-list' entry arg"""
3915 entry_args = {
3916 'of-list': '',
3917 }
Bin Mengaa75ce92021-05-10 20:23:32 +08003918 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003919
3920 def testFitFdtMissing(self):
3921 """Test handling of a missing 'default-dt' entry arg"""
3922 entry_args = {
3923 'of-list': 'test-fdt1 test-fdt2',
3924 }
3925 with self.assertRaises(ValueError) as e:
3926 self._DoReadFileDtb(
Bin Mengaa75ce92021-05-10 20:23:32 +08003927 '170_fit_fdt.dts',
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003928 entry_args=entry_args,
3929 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3930 self.assertIn("Generated 'default' node requires default-dt entry argument",
3931 str(e.exception))
3932
3933 def testFitFdtNotInList(self):
3934 """Test handling of a default-dt that is not in the of-list"""
3935 entry_args = {
3936 'of-list': 'test-fdt1 test-fdt2',
3937 'default-dt': 'test-fdt3',
3938 }
3939 with self.assertRaises(ValueError) as e:
3940 self._DoReadFileDtb(
Bin Mengaa75ce92021-05-10 20:23:32 +08003941 '170_fit_fdt.dts',
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003942 entry_args=entry_args,
3943 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3944 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
3945 str(e.exception))
3946
Simon Glassb2381432020-09-06 10:39:09 -06003947 def testFitExtblobMissingHelp(self):
3948 """Test display of help messages when an external blob is missing"""
3949 control.missing_blob_help = control._ReadMissingBlobHelp()
3950 control.missing_blob_help['wibble'] = 'Wibble test'
3951 control.missing_blob_help['another'] = 'Another test'
3952 with test_util.capture_sys_output() as (stdout, stderr):
3953 self._DoTestFile('168_fit_missing_blob.dts',
3954 allow_missing=True)
3955 err = stderr.getvalue()
3956
3957 # We can get the tag from the name, the type or the missing-msg
3958 # property. Check all three.
3959 self.assertIn('You may need to build ARM Trusted', err)
3960 self.assertIn('Wibble test', err)
3961 self.assertIn('Another test', err)
3962
Simon Glass204aa782020-09-06 10:35:32 -06003963 def testMissingBlob(self):
3964 """Test handling of a blob containing a missing file"""
3965 with self.assertRaises(ValueError) as e:
3966 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
3967 self.assertIn("Filename 'missing' not found in input path",
3968 str(e.exception))
3969
Simon Glassfb91d562020-09-06 10:35:33 -06003970 def testEnvironment(self):
3971 """Test adding a U-Boot environment"""
3972 data = self._DoReadFile('174_env.dts')
3973 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3974 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3975 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3976 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
3977 env)
3978
3979 def testEnvironmentNoSize(self):
3980 """Test that a missing 'size' property is detected"""
3981 with self.assertRaises(ValueError) as e:
Simon Glassa4dfe3e2020-10-26 17:40:00 -06003982 self._DoTestFile('175_env_no_size.dts')
Simon Glassfb91d562020-09-06 10:35:33 -06003983 self.assertIn("'u-boot-env' entry must have a size property",
3984 str(e.exception))
3985
3986 def testEnvironmentTooSmall(self):
3987 """Test handling of an environment that does not fit"""
3988 with self.assertRaises(ValueError) as e:
Simon Glassa4dfe3e2020-10-26 17:40:00 -06003989 self._DoTestFile('176_env_too_small.dts')
Simon Glassfb91d562020-09-06 10:35:33 -06003990
3991 # checksum, start byte, environment with \0 terminator, final \0
3992 need = 4 + 1 + len(ENV_DATA) + 1 + 1
3993 short = need - 0x8
3994 self.assertIn("too small to hold data (need %#x more bytes)" % short,
3995 str(e.exception))
3996
Simon Glassf2c0dd82020-10-26 17:40:01 -06003997 def testSkipAtStart(self):
3998 """Test handling of skip-at-start section"""
3999 data = self._DoReadFile('177_skip_at_start.dts')
4000 self.assertEqual(U_BOOT_DATA, data)
4001
4002 image = control.images['image']
4003 entries = image.GetEntries()
4004 section = entries['section']
4005 self.assertEqual(0, section.offset)
4006 self.assertEqual(len(U_BOOT_DATA), section.size)
4007 self.assertEqual(U_BOOT_DATA, section.GetData())
4008
4009 entry = section.GetEntries()['u-boot']
4010 self.assertEqual(16, entry.offset)
4011 self.assertEqual(len(U_BOOT_DATA), entry.size)
4012 self.assertEqual(U_BOOT_DATA, entry.data)
4013
4014 def testSkipAtStartPad(self):
4015 """Test handling of skip-at-start section with padded entry"""
4016 data = self._DoReadFile('178_skip_at_start_pad.dts')
4017 before = tools.GetBytes(0, 8)
4018 after = tools.GetBytes(0, 4)
4019 all = before + U_BOOT_DATA + after
4020 self.assertEqual(all, data)
4021
4022 image = control.images['image']
4023 entries = image.GetEntries()
4024 section = entries['section']
4025 self.assertEqual(0, section.offset)
4026 self.assertEqual(len(all), section.size)
4027 self.assertEqual(all, section.GetData())
4028
4029 entry = section.GetEntries()['u-boot']
4030 self.assertEqual(16, entry.offset)
4031 self.assertEqual(len(all), entry.size)
4032 self.assertEqual(U_BOOT_DATA, entry.data)
4033
4034 def testSkipAtStartSectionPad(self):
4035 """Test handling of skip-at-start section with padding"""
4036 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
4037 before = tools.GetBytes(0, 8)
4038 after = tools.GetBytes(0, 4)
4039 all = before + U_BOOT_DATA + after
Simon Glassd1d3ad72020-10-26 17:40:13 -06004040 self.assertEqual(all, data)
Simon Glassf2c0dd82020-10-26 17:40:01 -06004041
4042 image = control.images['image']
4043 entries = image.GetEntries()
4044 section = entries['section']
4045 self.assertEqual(0, section.offset)
4046 self.assertEqual(len(all), section.size)
Simon Glass63e7ba62020-10-26 17:40:16 -06004047 self.assertEqual(U_BOOT_DATA, section.data)
Simon Glassd1d3ad72020-10-26 17:40:13 -06004048 self.assertEqual(all, section.GetPaddedData())
Simon Glassf2c0dd82020-10-26 17:40:01 -06004049
4050 entry = section.GetEntries()['u-boot']
4051 self.assertEqual(16, entry.offset)
4052 self.assertEqual(len(U_BOOT_DATA), entry.size)
4053 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassfb91d562020-09-06 10:35:33 -06004054
Simon Glass7d398bb2020-10-26 17:40:14 -06004055 def testSectionPad(self):
4056 """Testing padding with sections"""
4057 data = self._DoReadFile('180_section_pad.dts')
4058 expected = (tools.GetBytes(ord('&'), 3) +
4059 tools.GetBytes(ord('!'), 5) +
4060 U_BOOT_DATA +
4061 tools.GetBytes(ord('!'), 1) +
4062 tools.GetBytes(ord('&'), 2))
4063 self.assertEqual(expected, data)
4064
4065 def testSectionAlign(self):
4066 """Testing alignment with sections"""
4067 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4068 expected = (b'\0' + # fill section
4069 tools.GetBytes(ord('&'), 1) + # padding to section align
4070 b'\0' + # fill section
4071 tools.GetBytes(ord('!'), 3) + # padding to u-boot align
4072 U_BOOT_DATA +
4073 tools.GetBytes(ord('!'), 4) + # padding to u-boot size
4074 tools.GetBytes(ord('!'), 4)) # padding to section size
4075 self.assertEqual(expected, data)
4076
Simon Glass8f5ef892020-10-26 17:40:25 -06004077 def testCompressImage(self):
4078 """Test compression of the entire image"""
4079 self._CheckLz4()
4080 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4081 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4082 dtb = fdt.Fdt(out_dtb_fname)
4083 dtb.Scan()
4084 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4085 'uncomp-size'])
4086 orig = self._decompress(data)
4087 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4088
4089 # Do a sanity check on various fields
4090 image = control.images['image']
4091 entries = image.GetEntries()
4092 self.assertEqual(2, len(entries))
4093
4094 entry = entries['blob']
4095 self.assertEqual(COMPRESS_DATA, entry.data)
4096 self.assertEqual(len(COMPRESS_DATA), entry.size)
4097
4098 entry = entries['u-boot']
4099 self.assertEqual(U_BOOT_DATA, entry.data)
4100 self.assertEqual(len(U_BOOT_DATA), entry.size)
4101
4102 self.assertEqual(len(data), image.size)
4103 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4104 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4105 orig = self._decompress(image.data)
4106 self.assertEqual(orig, image.uncomp_data)
4107
4108 expected = {
4109 'blob:offset': 0,
4110 'blob:size': len(COMPRESS_DATA),
4111 'u-boot:offset': len(COMPRESS_DATA),
4112 'u-boot:size': len(U_BOOT_DATA),
4113 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4114 'offset': 0,
4115 'image-pos': 0,
4116 'size': len(data),
4117 }
4118 self.assertEqual(expected, props)
4119
4120 def testCompressImageLess(self):
4121 """Test compression where compression reduces the image size"""
4122 self._CheckLz4()
4123 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4124 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4125 dtb = fdt.Fdt(out_dtb_fname)
4126 dtb.Scan()
4127 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4128 'uncomp-size'])
4129 orig = self._decompress(data)
4130
4131 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
4132
4133 # Do a sanity check on various fields
4134 image = control.images['image']
4135 entries = image.GetEntries()
4136 self.assertEqual(2, len(entries))
4137
4138 entry = entries['blob']
4139 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4140 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4141
4142 entry = entries['u-boot']
4143 self.assertEqual(U_BOOT_DATA, entry.data)
4144 self.assertEqual(len(U_BOOT_DATA), entry.size)
4145
4146 self.assertEqual(len(data), image.size)
4147 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4148 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4149 image.uncomp_size)
4150 orig = self._decompress(image.data)
4151 self.assertEqual(orig, image.uncomp_data)
4152
4153 expected = {
4154 'blob:offset': 0,
4155 'blob:size': len(COMPRESS_DATA_BIG),
4156 'u-boot:offset': len(COMPRESS_DATA_BIG),
4157 'u-boot:size': len(U_BOOT_DATA),
4158 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4159 'offset': 0,
4160 'image-pos': 0,
4161 'size': len(data),
4162 }
4163 self.assertEqual(expected, props)
4164
4165 def testCompressSectionSize(self):
4166 """Test compression of a section with a fixed size"""
4167 self._CheckLz4()
4168 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4169 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4170 dtb = fdt.Fdt(out_dtb_fname)
4171 dtb.Scan()
4172 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4173 'uncomp-size'])
4174 orig = self._decompress(data)
4175 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4176 expected = {
4177 'section/blob:offset': 0,
4178 'section/blob:size': len(COMPRESS_DATA),
4179 'section/u-boot:offset': len(COMPRESS_DATA),
4180 'section/u-boot:size': len(U_BOOT_DATA),
4181 'section:offset': 0,
4182 'section:image-pos': 0,
4183 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4184 'section:size': 0x30,
4185 'offset': 0,
4186 'image-pos': 0,
4187 'size': 0x30,
4188 }
4189 self.assertEqual(expected, props)
4190
4191 def testCompressSection(self):
4192 """Test compression of a section with no fixed size"""
4193 self._CheckLz4()
4194 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4195 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4196 dtb = fdt.Fdt(out_dtb_fname)
4197 dtb.Scan()
4198 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4199 'uncomp-size'])
4200 orig = self._decompress(data)
4201 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4202 expected = {
4203 'section/blob:offset': 0,
4204 'section/blob:size': len(COMPRESS_DATA),
4205 'section/u-boot:offset': len(COMPRESS_DATA),
4206 'section/u-boot:size': len(U_BOOT_DATA),
4207 'section:offset': 0,
4208 'section:image-pos': 0,
4209 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4210 'section:size': len(data),
4211 'offset': 0,
4212 'image-pos': 0,
4213 'size': len(data),
4214 }
4215 self.assertEqual(expected, props)
4216
4217 def testCompressExtra(self):
4218 """Test compression of a section with no fixed size"""
4219 self._CheckLz4()
4220 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4221 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4222 dtb = fdt.Fdt(out_dtb_fname)
4223 dtb.Scan()
4224 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4225 'uncomp-size'])
4226
4227 base = data[len(U_BOOT_DATA):]
4228 self.assertEquals(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
4229 rest = base[len(U_BOOT_DATA):]
4230
4231 # Check compressed data
4232 section1 = self._decompress(rest)
4233 expect1 = tools.Compress(COMPRESS_DATA + U_BOOT_DATA, 'lz4')
4234 self.assertEquals(expect1, rest[:len(expect1)])
4235 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, section1)
4236 rest1 = rest[len(expect1):]
4237
4238 section2 = self._decompress(rest1)
4239 expect2 = tools.Compress(COMPRESS_DATA + COMPRESS_DATA, 'lz4')
4240 self.assertEquals(expect2, rest1[:len(expect2)])
4241 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA, section2)
4242 rest2 = rest1[len(expect2):]
4243
4244 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4245 len(expect2) + len(U_BOOT_DATA))
4246 #self.assertEquals(expect_size, len(data))
4247
4248 #self.assertEquals(U_BOOT_DATA, rest2)
4249
4250 self.maxDiff = None
4251 expected = {
4252 'u-boot:offset': 0,
4253 'u-boot:image-pos': 0,
4254 'u-boot:size': len(U_BOOT_DATA),
4255
4256 'base:offset': len(U_BOOT_DATA),
4257 'base:image-pos': len(U_BOOT_DATA),
4258 'base:size': len(data) - len(U_BOOT_DATA),
4259 'base/u-boot:offset': 0,
4260 'base/u-boot:image-pos': len(U_BOOT_DATA),
4261 'base/u-boot:size': len(U_BOOT_DATA),
4262 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4263 len(expect2),
4264 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4265 len(expect2),
4266 'base/u-boot2:size': len(U_BOOT_DATA),
4267
4268 'base/section:offset': len(U_BOOT_DATA),
4269 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4270 'base/section:size': len(expect1),
4271 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4272 'base/section/blob:offset': 0,
4273 'base/section/blob:size': len(COMPRESS_DATA),
4274 'base/section/u-boot:offset': len(COMPRESS_DATA),
4275 'base/section/u-boot:size': len(U_BOOT_DATA),
4276
4277 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4278 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4279 'base/section2:size': len(expect2),
4280 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4281 'base/section2/blob:offset': 0,
4282 'base/section2/blob:size': len(COMPRESS_DATA),
4283 'base/section2/blob2:offset': len(COMPRESS_DATA),
4284 'base/section2/blob2:size': len(COMPRESS_DATA),
4285
4286 'offset': 0,
4287 'image-pos': 0,
4288 'size': len(data),
4289 }
4290 self.assertEqual(expected, props)
4291
Simon Glass870a9ea2021-01-06 21:35:15 -07004292 def testSymbolsSubsection(self):
4293 """Test binman can assign symbols from a subsection"""
Simon Glassf5898822021-03-18 20:24:56 +13004294 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x18)
Simon Glass870a9ea2021-01-06 21:35:15 -07004295
Simon Glass939d1062021-01-06 21:35:16 -07004296 def testReadImageEntryArg(self):
4297 """Test reading an image that would need an entry arg to generate"""
4298 entry_args = {
4299 'cros-ec-rw-path': 'ecrw.bin',
4300 }
4301 data = self.data = self._DoReadFileDtb(
4302 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4303 entry_args=entry_args)
4304
4305 image_fname = tools.GetOutputFilename('image.bin')
4306 orig_image = control.images['image']
4307
4308 # This should not generate an error about the missing 'cros-ec-rw-path'
4309 # since we are reading the image from a file. Compare with
4310 # testEntryArgsRequired()
4311 image = Image.FromFile(image_fname)
4312 self.assertEqual(orig_image.GetEntries().keys(),
4313 image.GetEntries().keys())
4314
Simon Glass6eb99322021-01-06 21:35:18 -07004315 def testFilesAlign(self):
4316 """Test alignment with files"""
4317 data = self._DoReadFile('190_files_align.dts')
4318
4319 # The first string is 15 bytes so will align to 16
4320 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4321 self.assertEqual(expect, data)
4322
Simon Glass5c6ba712021-01-06 21:35:19 -07004323 def testReadImageSkip(self):
4324 """Test reading an image and accessing its FDT map"""
4325 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
4326 image_fname = tools.GetOutputFilename('image.bin')
4327 orig_image = control.images['image']
4328 image = Image.FromFile(image_fname)
4329 self.assertEqual(orig_image.GetEntries().keys(),
4330 image.GetEntries().keys())
4331
4332 orig_entry = orig_image.GetEntries()['fdtmap']
4333 entry = image.GetEntries()['fdtmap']
4334 self.assertEqual(orig_entry.offset, entry.offset)
4335 self.assertEqual(orig_entry.size, entry.size)
4336 self.assertEqual(16, entry.image_pos)
4337
4338 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4339
4340 self.assertEquals(U_BOOT_DATA, u_boot.ReadData())
4341
Simon Glass77a64e02021-03-18 20:24:57 +13004342 def testTplNoDtb(self):
4343 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
Simon Glass0fe44dc2021-04-25 08:39:32 +12004344 self._SetupTplElf()
Simon Glass77a64e02021-03-18 20:24:57 +13004345 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4346 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4347 data[:len(U_BOOT_TPL_NODTB_DATA)])
4348
Simon Glassd26efc82021-03-18 20:24:58 +13004349 def testTplBssPad(self):
4350 """Test that we can pad TPL's BSS with zeros"""
4351 # ELF file with a '__bss_size' symbol
4352 self._SetupTplElf()
4353 data = self._DoReadFile('193_tpl_bss_pad.dts')
4354 self.assertEqual(U_BOOT_TPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
4355 data)
4356
4357 def testTplBssPadMissing(self):
4358 """Test that a missing symbol is detected"""
4359 self._SetupTplElf('u_boot_ucode_ptr')
4360 with self.assertRaises(ValueError) as e:
4361 self._DoReadFile('193_tpl_bss_pad.dts')
4362 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4363 str(e.exception))
4364
Simon Glass06684922021-03-18 20:25:07 +13004365 def checkDtbSizes(self, data, pad_len, start):
4366 """Check the size arguments in a dtb embedded in an image
4367
4368 Args:
4369 data: The image data
4370 pad_len: Length of the pad section in the image, in bytes
4371 start: Start offset of the devicetree to examine, within the image
4372
4373 Returns:
4374 Size of the devicetree in bytes
4375 """
4376 dtb_data = data[start:]
4377 dtb = fdt.Fdt.FromData(dtb_data)
4378 fdt_size = dtb.GetFdtObj().totalsize()
4379 dtb.Scan()
4380 props = self._GetPropTree(dtb, 'size')
4381 self.assertEqual({
4382 'size': len(data),
4383 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4384 'u-boot-spl/u-boot-spl-dtb:size': 801,
4385 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4386 'u-boot-spl:size': 860,
4387 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4388 'u-boot/u-boot-dtb:size': 781,
4389 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4390 'u-boot:size': 827,
4391 }, props)
4392 return fdt_size
4393
4394 def testExpanded(self):
4395 """Test that an expanded entry type is selected when needed"""
4396 self._SetupSplElf()
4397 self._SetupTplElf()
4398
4399 # SPL has a devicetree, TPL does not
4400 entry_args = {
4401 'spl-dtb': '1',
4402 'spl-bss-pad': 'y',
4403 'tpl-dtb': '',
4404 }
4405 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4406 entry_args=entry_args)
4407 image = control.images['image']
4408 entries = image.GetEntries()
4409 self.assertEqual(3, len(entries))
4410
4411 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4412 self.assertIn('u-boot', entries)
4413 entry = entries['u-boot']
4414 self.assertEqual('u-boot-expanded', entry.etype)
4415 subent = entry.GetEntries()
4416 self.assertEqual(2, len(subent))
4417 self.assertIn('u-boot-nodtb', subent)
4418 self.assertIn('u-boot-dtb', subent)
4419
4420 # Second, u-boot-spl, which should be expanded into three parts
4421 self.assertIn('u-boot-spl', entries)
4422 entry = entries['u-boot-spl']
4423 self.assertEqual('u-boot-spl-expanded', entry.etype)
4424 subent = entry.GetEntries()
4425 self.assertEqual(3, len(subent))
4426 self.assertIn('u-boot-spl-nodtb', subent)
4427 self.assertIn('u-boot-spl-bss-pad', subent)
4428 self.assertIn('u-boot-spl-dtb', subent)
4429
4430 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4431 # devicetree
4432 self.assertIn('u-boot-tpl', entries)
4433 entry = entries['u-boot-tpl']
4434 self.assertEqual('u-boot-tpl', entry.etype)
4435 self.assertEqual(None, entry.GetEntries())
4436
4437 def testExpandedTpl(self):
4438 """Test that an expanded entry type is selected for TPL when needed"""
4439 self._SetupTplElf()
4440
4441 entry_args = {
4442 'tpl-bss-pad': 'y',
4443 'tpl-dtb': 'y',
4444 }
4445 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4446 entry_args=entry_args)
4447 image = control.images['image']
4448 entries = image.GetEntries()
4449 self.assertEqual(1, len(entries))
4450
4451 # We only have u-boot-tpl, which be expanded
4452 self.assertIn('u-boot-tpl', entries)
4453 entry = entries['u-boot-tpl']
4454 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4455 subent = entry.GetEntries()
4456 self.assertEqual(3, len(subent))
4457 self.assertIn('u-boot-tpl-nodtb', subent)
4458 self.assertIn('u-boot-tpl-bss-pad', subent)
4459 self.assertIn('u-boot-tpl-dtb', subent)
4460
4461 def testExpandedNoPad(self):
4462 """Test an expanded entry without BSS pad enabled"""
4463 self._SetupSplElf()
4464 self._SetupTplElf()
4465
4466 # SPL has a devicetree, TPL does not
4467 entry_args = {
4468 'spl-dtb': 'something',
4469 'spl-bss-pad': 'n',
4470 'tpl-dtb': '',
4471 }
4472 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4473 entry_args=entry_args)
4474 image = control.images['image']
4475 entries = image.GetEntries()
4476
4477 # Just check u-boot-spl, which should be expanded into two parts
4478 self.assertIn('u-boot-spl', entries)
4479 entry = entries['u-boot-spl']
4480 self.assertEqual('u-boot-spl-expanded', entry.etype)
4481 subent = entry.GetEntries()
4482 self.assertEqual(2, len(subent))
4483 self.assertIn('u-boot-spl-nodtb', subent)
4484 self.assertIn('u-boot-spl-dtb', subent)
4485
4486 def testExpandedTplNoPad(self):
4487 """Test that an expanded entry type with padding disabled in TPL"""
4488 self._SetupTplElf()
4489
4490 entry_args = {
4491 'tpl-bss-pad': '',
4492 'tpl-dtb': 'y',
4493 }
4494 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4495 entry_args=entry_args)
4496 image = control.images['image']
4497 entries = image.GetEntries()
4498 self.assertEqual(1, len(entries))
4499
4500 # We only have u-boot-tpl, which be expanded
4501 self.assertIn('u-boot-tpl', entries)
4502 entry = entries['u-boot-tpl']
4503 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4504 subent = entry.GetEntries()
4505 self.assertEqual(2, len(subent))
4506 self.assertIn('u-boot-tpl-nodtb', subent)
4507 self.assertIn('u-boot-tpl-dtb', subent)
4508
4509 def testFdtInclude(self):
4510 """Test that an Fdt is update within all binaries"""
4511 self._SetupSplElf()
4512 self._SetupTplElf()
4513
4514 # SPL has a devicetree, TPL does not
4515 self.maxDiff = None
4516 entry_args = {
4517 'spl-dtb': '1',
4518 'spl-bss-pad': 'y',
4519 'tpl-dtb': '',
4520 }
4521 # Build the image. It includes two separate devicetree binaries, each
4522 # with their own contents, but all contain the binman definition.
4523 data = self._DoReadFileDtb(
4524 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4525 update_dtb=True, entry_args=entry_args)[0]
4526 pad_len = 10
4527
4528 # Check the U-Boot dtb
4529 start = len(U_BOOT_NODTB_DATA)
4530 fdt_size = self.checkDtbSizes(data, pad_len, start)
4531
4532 # Now check SPL
4533 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4534 fdt_size = self.checkDtbSizes(data, pad_len, start)
4535
4536 # TPL has no devicetree
4537 start += fdt_size + len(U_BOOT_TPL_DATA)
4538 self.assertEqual(len(data), start)
Simon Glass7d398bb2020-10-26 17:40:14 -06004539
Simon Glass3d433382021-03-21 18:24:30 +13004540 def testSymbolsExpanded(self):
4541 """Test binman can assign symbols in expanded entries"""
4542 entry_args = {
4543 'spl-dtb': '1',
4544 }
4545 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4546 U_BOOT_SPL_DTB_DATA, 0x38,
4547 entry_args=entry_args, use_expanded=True)
4548
Simon Glass189f2912021-03-21 18:24:31 +13004549 def testCollection(self):
4550 """Test a collection"""
4551 data = self._DoReadFile('198_collection.dts')
4552 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
4553 tools.GetBytes(0xff, 2) + U_BOOT_NODTB_DATA +
4554 tools.GetBytes(0xfe, 3) + U_BOOT_DTB_DATA,
4555 data)
4556
Simon Glass631f7522021-03-21 18:24:32 +13004557 def testCollectionSection(self):
4558 """Test a collection where a section must be built first"""
4559 # Sections never have their contents when GetData() is called, but when
Simon Glassd34bcdd2021-11-23 11:03:47 -07004560 # BuildSectionData() is called with required=True, a section will force
Simon Glass631f7522021-03-21 18:24:32 +13004561 # building the contents, producing an error is anything is still
4562 # missing.
4563 data = self._DoReadFile('199_collection_section.dts')
4564 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
4565 self.assertEqual(section + U_BOOT_DATA + tools.GetBytes(0xff, 2) +
4566 section + tools.GetBytes(0xfe, 3) + U_BOOT_DATA,
4567 data)
4568
Simon Glass5ff9fed2021-03-21 18:24:33 +13004569 def testAlignDefault(self):
4570 """Test that default alignment works on sections"""
4571 data = self._DoReadFile('200_align_default.dts')
4572 expected = (U_BOOT_DATA + tools.GetBytes(0, 8 - len(U_BOOT_DATA)) +
4573 U_BOOT_DATA)
4574 # Special alignment for section
4575 expected += tools.GetBytes(0, 32 - len(expected))
4576 # No alignment within the nested section
4577 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
4578 # Now the final piece, which should be default-aligned
4579 expected += tools.GetBytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
4580 self.assertEqual(expected, data)
Simon Glass631f7522021-03-21 18:24:32 +13004581
Bin Meng4c4d6072021-05-10 20:23:33 +08004582 def testPackOpenSBI(self):
4583 """Test that an image with an OpenSBI binary can be created"""
4584 data = self._DoReadFile('201_opensbi.dts')
4585 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
4586
Simon Glassc69d19c2021-07-06 10:36:37 -06004587 def testSectionsSingleThread(self):
4588 """Test sections without multithreading"""
4589 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
4590 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
4591 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
4592 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
4593 self.assertEqual(expected, data)
4594
4595 def testThreadTimeout(self):
4596 """Test handling a thread that takes too long"""
4597 with self.assertRaises(ValueError) as e:
4598 self._DoTestFile('202_section_timeout.dts',
4599 test_section_timeout=True)
Simon Glassb2dfe832021-10-18 12:13:15 -06004600 self.assertIn("Timed out obtaining contents", str(e.exception))
Simon Glassc69d19c2021-07-06 10:36:37 -06004601
Simon Glass03ebc202021-07-06 10:36:41 -06004602 def testTiming(self):
4603 """Test output of timing information"""
4604 data = self._DoReadFile('055_sections.dts')
4605 with test_util.capture_sys_output() as (stdout, stderr):
4606 state.TimingShow()
4607 self.assertIn('read:', stdout.getvalue())
4608 self.assertIn('compress:', stdout.getvalue())
4609
Simon Glass0427bed2021-11-03 21:09:18 -06004610 def testUpdateFdtInElf(self):
4611 """Test that we can update the devicetree in an ELF file"""
4612 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4613 outfile = os.path.join(self._indir, 'u-boot.out')
4614 begin_sym = 'dtb_embed_begin'
4615 end_sym = 'dtb_embed_end'
4616 retcode = self._DoTestFile(
4617 '060_fdt_update.dts', update_dtb=True,
4618 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4619 self.assertEqual(0, retcode)
4620
4621 # Check that the output file does in fact contact a dtb with the binman
4622 # definition in the correct place
4623 syms = elf.GetSymbolFileOffset(infile,
4624 ['dtb_embed_begin', 'dtb_embed_end'])
4625 data = tools.ReadFile(outfile)
4626 dtb_data = data[syms['dtb_embed_begin'].offset:
4627 syms['dtb_embed_end'].offset]
4628
4629 dtb = fdt.Fdt.FromData(dtb_data)
4630 dtb.Scan()
4631 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4632 self.assertEqual({
4633 'image-pos': 0,
4634 'offset': 0,
4635 '_testing:offset': 32,
4636 '_testing:size': 2,
4637 '_testing:image-pos': 32,
4638 'section@0/u-boot:offset': 0,
4639 'section@0/u-boot:size': len(U_BOOT_DATA),
4640 'section@0/u-boot:image-pos': 0,
4641 'section@0:offset': 0,
4642 'section@0:size': 16,
4643 'section@0:image-pos': 0,
4644
4645 'section@1/u-boot:offset': 0,
4646 'section@1/u-boot:size': len(U_BOOT_DATA),
4647 'section@1/u-boot:image-pos': 16,
4648 'section@1:offset': 16,
4649 'section@1:size': 16,
4650 'section@1:image-pos': 16,
4651 'size': 40
4652 }, props)
4653
4654 def testUpdateFdtInElfInvalid(self):
4655 """Test that invalid args are detected with --update-fdt-in-elf"""
4656 with self.assertRaises(ValueError) as e:
4657 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
4658 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
4659 str(e.exception))
4660
4661 def testUpdateFdtInElfNoSyms(self):
4662 """Test that missing symbols are detected with --update-fdt-in-elf"""
4663 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4664 outfile = ''
4665 begin_sym = 'wrong_begin'
4666 end_sym = 'wrong_end'
4667 with self.assertRaises(ValueError) as e:
4668 self._DoTestFile(
4669 '060_fdt_update.dts',
4670 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4671 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
4672 str(e.exception))
4673
4674 def testUpdateFdtInElfTooSmall(self):
4675 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
4676 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
4677 outfile = os.path.join(self._indir, 'u-boot.out')
4678 begin_sym = 'dtb_embed_begin'
4679 end_sym = 'dtb_embed_end'
4680 with self.assertRaises(ValueError) as e:
4681 self._DoTestFile(
4682 '060_fdt_update.dts', update_dtb=True,
4683 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4684 self.assertRegex(
4685 str(e.exception),
4686 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
4687
Simon Glassc475dec2021-11-23 11:03:42 -07004688 def testVersion(self):
4689 """Test we can get the binman version"""
4690 version = '(unreleased)'
4691 self.assertEqual(version, state.GetVersion(self._indir))
4692
4693 with self.assertRaises(SystemExit):
4694 with test_util.capture_sys_output() as (_, stderr):
4695 self._DoBinman('-V')
4696 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
4697
4698 # Try running the tool too, just to be safe
4699 result = self._RunBinman('-V')
4700 self.assertEqual('Binman %s\n' % version, result.stderr)
4701
4702 # Set up a version file to make sure that works
4703 version = 'v2025.01-rc2'
4704 tools.WriteFile(os.path.join(self._indir, 'version'), version,
4705 binary=False)
4706 self.assertEqual(version, state.GetVersion(self._indir))
4707
Simon Glass943bf782021-11-23 21:09:50 -07004708 def testAltFormat(self):
4709 """Test that alternative formats can be used to extract"""
4710 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
4711
4712 try:
4713 tmpdir, updated_fname = self._SetupImageInTmpdir()
4714 with test_util.capture_sys_output() as (stdout, _):
4715 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
4716 self.assertEqual(
4717 '''Flag (-F) Entry type Description
4718fdt fdtmap Extract the devicetree blob from the fdtmap
4719''',
4720 stdout.getvalue())
4721
4722 dtb = os.path.join(tmpdir, 'fdt.dtb')
4723 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
4724 dtb, 'fdtmap')
4725
4726 # Check that we can read it and it can be scanning, meaning it does
4727 # not have a 16-byte fdtmap header
4728 data = tools.ReadFile(dtb)
4729 dtb = fdt.Fdt.FromData(data)
4730 dtb.Scan()
4731
4732 # Now check u-boot which has no alt_format
4733 fname = os.path.join(tmpdir, 'fdt.dtb')
4734 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
4735 '-f', fname, 'u-boot')
4736 data = tools.ReadFile(fname)
4737 self.assertEqual(U_BOOT_DATA, data)
4738
4739 finally:
4740 shutil.rmtree(tmpdir)
4741
Simon Glasscc2c5002021-11-23 21:09:52 -07004742 def testExtblobList(self):
4743 """Test an image with an external blob list"""
4744 data = self._DoReadFile('215_blob_ext_list.dts')
4745 self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
4746
4747 def testExtblobListMissing(self):
4748 """Test an image with a missing external blob"""
4749 with self.assertRaises(ValueError) as e:
4750 self._DoReadFile('216_blob_ext_list_missing.dts')
4751 self.assertIn("Filename 'missing-file' not found in input path",
4752 str(e.exception))
4753
4754 def testExtblobListMissingOk(self):
4755 """Test an image with an missing external blob that is allowed"""
4756 with test_util.capture_sys_output() as (stdout, stderr):
4757 self._DoTestFile('216_blob_ext_list_missing.dts',
4758 allow_missing=True)
4759 err = stderr.getvalue()
4760 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
4761
Simon Glass75989722021-11-23 21:08:59 -07004762 def testFip(self):
4763 """Basic test of generation of an ARM Firmware Image Package (FIP)"""
4764 data = self._DoReadFile('203_fip.dts')
4765 hdr, fents = fip_util.decode_fip(data)
4766 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
4767 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
4768 self.assertEqual(0x123, hdr.flags)
4769
4770 self.assertEqual(2, len(fents))
4771
4772 fent = fents[0]
4773 self.assertEqual(
4774 bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
4775 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
4776 self.assertEqual('soc-fw', fent.fip_type)
4777 self.assertEqual(0x88, fent.offset)
4778 self.assertEqual(len(ATF_BL31_DATA), fent.size)
4779 self.assertEqual(0x123456789abcdef, fent.flags)
4780 self.assertEqual(ATF_BL31_DATA, fent.data)
4781 self.assertEqual(True, fent.valid)
4782
4783 fent = fents[1]
4784 self.assertEqual(
4785 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
4786 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
4787 self.assertEqual('scp-fwu-cfg', fent.fip_type)
4788 self.assertEqual(0x8c, fent.offset)
4789 self.assertEqual(len(ATF_BL31_DATA), fent.size)
4790 self.assertEqual(0, fent.flags)
4791 self.assertEqual(ATF_BL2U_DATA, fent.data)
4792 self.assertEqual(True, fent.valid)
4793
4794 def testFipOther(self):
4795 """Basic FIP with something that isn't a external blob"""
4796 data = self._DoReadFile('204_fip_other.dts')
4797 hdr, fents = fip_util.decode_fip(data)
4798
4799 self.assertEqual(2, len(fents))
4800 fent = fents[1]
4801 self.assertEqual('rot-cert', fent.fip_type)
4802 self.assertEqual(b'aa', fent.data)
4803
4804 def testFipOther(self):
4805 """Basic FIP with something that isn't a external blob"""
4806 data = self._DoReadFile('204_fip_other.dts')
4807 hdr, fents = fip_util.decode_fip(data)
4808
4809 self.assertEqual(2, len(fents))
4810 fent = fents[1]
4811 self.assertEqual('rot-cert', fent.fip_type)
4812 self.assertEqual(b'aa', fent.data)
4813
4814 def testFipNoType(self):
4815 """FIP with an entry of an unknown type"""
4816 with self.assertRaises(ValueError) as e:
4817 self._DoReadFile('205_fip_no_type.dts')
4818 self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
4819 str(e.exception))
4820
4821 def testFipUuid(self):
4822 """Basic FIP with a manual uuid"""
4823 data = self._DoReadFile('206_fip_uuid.dts')
4824 hdr, fents = fip_util.decode_fip(data)
4825
4826 self.assertEqual(2, len(fents))
4827 fent = fents[1]
4828 self.assertEqual(None, fent.fip_type)
4829 self.assertEqual(
4830 bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
4831 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
4832 fent.uuid)
4833 self.assertEqual(U_BOOT_DATA, fent.data)
4834
4835 def testFipLs(self):
4836 """Test listing a FIP"""
4837 data = self._DoReadFileRealDtb('207_fip_ls.dts')
4838 hdr, fents = fip_util.decode_fip(data)
4839
4840 try:
4841 tmpdir, updated_fname = self._SetupImageInTmpdir()
4842 with test_util.capture_sys_output() as (stdout, stderr):
4843 self._DoBinman('ls', '-i', updated_fname)
4844 finally:
4845 shutil.rmtree(tmpdir)
4846 lines = stdout.getvalue().splitlines()
4847 expected = [
4848'Name Image-pos Size Entry-type Offset Uncomp-size',
4849'----------------------------------------------------------------',
4850'main-section 0 2d3 section 0',
4851' atf-fip 0 90 atf-fip 0',
4852' soc-fw 88 4 blob-ext 88',
4853' u-boot 8c 4 u-boot 8c',
4854' fdtmap 90 243 fdtmap 90',
4855]
4856 self.assertEqual(expected, lines)
4857
4858 image = control.images['image']
4859 entries = image.GetEntries()
4860 fdtmap = entries['fdtmap']
4861
4862 fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
4863 magic = fdtmap_data[:8]
4864 self.assertEqual(b'_FDTMAP_', magic)
4865 self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
4866
4867 fdt_data = fdtmap_data[16:]
4868 dtb = fdt.Fdt.FromData(fdt_data)
4869 dtb.Scan()
4870 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
4871 self.assertEqual({
4872 'atf-fip/soc-fw:image-pos': 136,
4873 'atf-fip/soc-fw:offset': 136,
4874 'atf-fip/soc-fw:size': 4,
4875 'atf-fip/u-boot:image-pos': 140,
4876 'atf-fip/u-boot:offset': 140,
4877 'atf-fip/u-boot:size': 4,
4878 'atf-fip:image-pos': 0,
4879 'atf-fip:offset': 0,
4880 'atf-fip:size': 144,
4881 'image-pos': 0,
4882 'offset': 0,
4883 'fdtmap:image-pos': fdtmap.image_pos,
4884 'fdtmap:offset': fdtmap.offset,
4885 'fdtmap:size': len(fdtmap_data),
4886 'size': len(data),
4887 }, props)
4888
4889 def testFipExtractOneEntry(self):
4890 """Test extracting a single entry fron an FIP"""
4891 self._DoReadFileRealDtb('207_fip_ls.dts')
4892 image_fname = tools.GetOutputFilename('image.bin')
4893 fname = os.path.join(self._indir, 'output.extact')
4894 control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
4895 data = tools.ReadFile(fname)
4896 self.assertEqual(U_BOOT_DATA, data)
4897
4898 def testFipReplace(self):
4899 """Test replacing a single file in a FIP"""
4900 expected = U_BOOT_DATA + tools.GetBytes(0x78, 50)
4901 data = self._DoReadFileRealDtb('208_fip_replace.dts')
4902 updated_fname = tools.GetOutputFilename('image-updated.bin')
4903 tools.WriteFile(updated_fname, data)
4904 entry_name = 'atf-fip/u-boot'
4905 control.WriteEntry(updated_fname, entry_name, expected,
4906 allow_resize=True)
4907 actual = control.ReadEntry(updated_fname, entry_name)
4908 self.assertEqual(expected, actual)
4909
4910 new_data = tools.ReadFile(updated_fname)
4911 hdr, fents = fip_util.decode_fip(new_data)
4912
4913 self.assertEqual(2, len(fents))
4914
4915 # Check that the FIP entry is updated
4916 fent = fents[1]
4917 self.assertEqual(0x8c, fent.offset)
4918 self.assertEqual(len(expected), fent.size)
4919 self.assertEqual(0, fent.flags)
4920 self.assertEqual(expected, fent.data)
4921 self.assertEqual(True, fent.valid)
4922
4923 def testFipMissing(self):
4924 with test_util.capture_sys_output() as (stdout, stderr):
4925 self._DoTestFile('209_fip_missing.dts', allow_missing=True)
4926 err = stderr.getvalue()
4927 self.assertRegex(err, "Image 'main-section'.*missing.*: rmm-fw")
4928
4929 def testFipSize(self):
4930 """Test a FIP with a size property"""
4931 data = self._DoReadFile('210_fip_size.dts')
4932 self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
4933 hdr, fents = fip_util.decode_fip(data)
4934 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
4935 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
4936
4937 self.assertEqual(1, len(fents))
4938
4939 fent = fents[0]
4940 self.assertEqual('soc-fw', fent.fip_type)
4941 self.assertEqual(0x60, fent.offset)
4942 self.assertEqual(len(ATF_BL31_DATA), fent.size)
4943 self.assertEqual(ATF_BL31_DATA, fent.data)
4944 self.assertEqual(True, fent.valid)
4945
4946 rest = data[0x60 + len(ATF_BL31_DATA):0x100]
4947 self.assertEqual(tools.GetBytes(0xff, len(rest)), rest)
4948
4949 def testFipBadAlign(self):
4950 """Test that an invalid alignment value in a FIP is detected"""
4951 with self.assertRaises(ValueError) as e:
4952 self._DoTestFile('211_fip_bad_align.dts')
4953 self.assertIn(
4954 "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
4955 str(e.exception))
4956
4957 def testFipCollection(self):
4958 """Test using a FIP in a collection"""
4959 data = self._DoReadFile('212_fip_collection.dts')
4960 entry1 = control.images['image'].GetEntries()['collection']
4961 data1 = data[:entry1.size]
4962 hdr1, fents2 = fip_util.decode_fip(data1)
4963
4964 entry2 = control.images['image'].GetEntries()['atf-fip']
4965 data2 = data[entry2.offset:entry2.offset + entry2.size]
4966 hdr1, fents2 = fip_util.decode_fip(data2)
4967
4968 # The 'collection' entry should have U-Boot included at the end
4969 self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
4970 self.assertEqual(data1, data2 + U_BOOT_DATA)
4971 self.assertEqual(U_BOOT_DATA, data1[-4:])
4972
4973 # There should be a U-Boot after the final FIP
4974 self.assertEqual(U_BOOT_DATA, data[-4:])
Simon Glassc69d19c2021-07-06 10:36:37 -06004975
Simon Glass32d4f102022-01-12 13:10:35 -07004976 def testFakeBlob(self):
4977 """Test handling of faking an external blob"""
4978 with test_util.capture_sys_output() as (stdout, stderr):
4979 self._DoTestFile('217_fake_blob.dts', allow_missing=True,
4980 allow_fake_blobs=True)
4981 err = stderr.getvalue()
4982 self.assertRegex(
4983 err,
4984 "Image '.*' has faked external blobs and is non-functional: .*")
Simon Glass32d4f102022-01-12 13:10:35 -07004985
Simon Glassf4590e02022-01-09 20:13:46 -07004986 def testExtblobListFaked(self):
4987 """Test an extblob with missing external blob that are faked"""
4988 with test_util.capture_sys_output() as (stdout, stderr):
4989 self._DoTestFile('216_blob_ext_list_missing.dts',
4990 allow_fake_blobs=True)
4991 err = stderr.getvalue()
4992 self.assertRegex(err, "Image 'main-section'.*faked.*: blob-ext-list")
4993
Simon Glass32d4f102022-01-12 13:10:35 -07004994
Simon Glass9fc60b42017-11-12 21:52:22 -07004995if __name__ == "__main__":
4996 unittest.main()