blob: f543d173997c7a75a65987dd66f2904cdfd61ef8 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001# SPDX-License-Identifier: GPL-2.0+
Simon Glass57454f42016-11-25 20:15:52 -07002# Copyright (c) 2016 Google, Inc
3# Written by Simon Glass <sjg@chromium.org>
4#
Simon Glass57454f42016-11-25 20:15:52 -07005# To run a single test, change to this directory, and:
6#
7# python -m unittest func_test.TestFunctional.testHelp
8
Simon Glass45d556d2020-07-09 18:39:45 -06009import collections
Simon Glassc585dd42020-04-17 18:09:03 -060010import gzip
Simon Glassae7cf032018-09-14 04:57:31 -060011import hashlib
Simon Glass57454f42016-11-25 20:15:52 -070012from optparse import OptionParser
13import os
Simon Glass45d556d2020-07-09 18:39:45 -060014import re
Simon Glass57454f42016-11-25 20:15:52 -070015import shutil
16import struct
17import sys
18import tempfile
19import unittest
Simon Glass162017b2022-01-09 20:13:57 -070020import unittest.mock
21import urllib.error
Simon Glass57454f42016-11-25 20:15:52 -070022
Simon Glass4eae9252022-01-09 20:13:50 -070023from binman import bintool
Simon Glassc585dd42020-04-17 18:09:03 -060024from binman import cbfs_util
25from binman import cmdline
26from binman import control
27from binman import elf
28from binman import elf_test
Simon Glass3efb2972021-11-23 21:08:59 -070029from binman import fip_util
Simon Glassc585dd42020-04-17 18:09:03 -060030from binman import fmap_util
Simon Glassc585dd42020-04-17 18:09:03 -060031from binman import state
32from dtoc import fdt
33from dtoc import fdt_util
34from binman.etype import fdtmap
35from binman.etype import image_header
Simon Glass90cd6f02020-08-05 13:27:47 -060036from binman.image import Image
Simon Glassa997ea52020-04-17 18:09:04 -060037from patman import command
38from patman import test_util
39from patman import tools
40from patman import tout
Simon Glass57454f42016-11-25 20:15:52 -070041
42# Contents of test files, corresponding to different entry types
Simon Glass303f62f2019-05-17 22:00:46 -060043U_BOOT_DATA = b'1234'
44U_BOOT_IMG_DATA = b'img'
Simon Glass4e353e22019-08-24 07:23:04 -060045U_BOOT_SPL_DATA = b'56780123456789abcdefghi'
46U_BOOT_TPL_DATA = b'tpl9876543210fedcbazyw'
Simon Glass303f62f2019-05-17 22:00:46 -060047BLOB_DATA = b'89'
48ME_DATA = b'0abcd'
49VGA_DATA = b'vga'
50U_BOOT_DTB_DATA = b'udtb'
51U_BOOT_SPL_DTB_DATA = b'spldtb'
52U_BOOT_TPL_DTB_DATA = b'tpldtb'
53X86_START16_DATA = b'start16'
54X86_START16_SPL_DATA = b'start16spl'
55X86_START16_TPL_DATA = b'start16tpl'
Simon Glass0b074d62019-08-24 07:22:48 -060056X86_RESET16_DATA = b'reset16'
57X86_RESET16_SPL_DATA = b'reset16spl'
58X86_RESET16_TPL_DATA = b'reset16tpl'
Simon Glass303f62f2019-05-17 22:00:46 -060059PPC_MPC85XX_BR_DATA = b'ppcmpc85xxbr'
60U_BOOT_NODTB_DATA = b'nodtb with microcode pointer somewhere in here'
61U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here'
62U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here'
63FSP_DATA = b'fsp'
64CMC_DATA = b'cmc'
65VBT_DATA = b'vbt'
66MRC_DATA = b'mrc'
Simon Glass2ca52032018-07-17 13:25:33 -060067TEXT_DATA = 'text'
68TEXT_DATA2 = 'text2'
69TEXT_DATA3 = 'text3'
Simon Glass303f62f2019-05-17 22:00:46 -060070CROS_EC_RW_DATA = b'ecrw'
71GBB_DATA = b'gbbd'
72BMPBLK_DATA = b'bmp'
73VBLOCK_DATA = b'vblk'
74FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
75 b"sorry you're alive\n")
Simon Glassccec0262019-07-08 13:18:42 -060076COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
Simon Glassd92c8362020-10-26 17:40:25 -060077COMPRESS_DATA_BIG = COMPRESS_DATA * 2
Simon Glass303f62f2019-05-17 22:00:46 -060078REFCODE_DATA = b'refcode'
Simon Glassba7985d2019-08-24 07:23:07 -060079FSP_M_DATA = b'fsp_m'
Simon Glass4d9086d2019-10-20 21:31:35 -060080FSP_S_DATA = b'fsp_s'
Simon Glass9ea87b22019-10-20 21:31:36 -060081FSP_T_DATA = b'fsp_t'
Simon Glass559c4de2020-09-01 05:13:58 -060082ATF_BL31_DATA = b'bl31'
Simon Glass3efb2972021-11-23 21:08:59 -070083ATF_BL2U_DATA = b'bl2u'
Bin Mengc0b15742021-05-10 20:23:33 +080084OPENSBI_DATA = b'opensbi'
Samuel Holland9d8cc632020-10-21 21:12:15 -050085SCP_DATA = b'scp'
Simon Glassa435cd12020-09-01 05:13:59 -060086TEST_FDT1_DATA = b'fdt1'
87TEST_FDT2_DATA = b'test-fdt2'
Simon Glassa0729502020-09-06 10:35:33 -060088ENV_DATA = b'var1=1\nvar2="2"'
Simon Glassa435cd12020-09-01 05:13:59 -060089
90# Subdirectory of the input dir to use to put test FDTs
91TEST_FDT_SUBDIR = 'fdts'
Simon Glassdb168d42018-07-17 13:25:39 -060092
Simon Glass2c6adba2019-07-20 12:23:47 -060093# The expected size for the device tree in some tests
Simon Glass4c613bf2019-07-08 14:25:50 -060094EXTRACT_DTB_SIZE = 0x3c9
95
Simon Glass2c6adba2019-07-20 12:23:47 -060096# Properties expected to be in the device tree when update_dtb is used
97BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
98
Simon Glassfb30e292019-07-20 12:23:51 -060099# Extra properties expected to be in the device tree when allow-repack is used
100REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
101
Simon Glass57454f42016-11-25 20:15:52 -0700102
103class TestFunctional(unittest.TestCase):
104 """Functional tests for binman
105
106 Most of these use a sample .dts file to build an image and then check
107 that it looks correct. The sample files are in the test/ subdirectory
108 and are numbered.
109
110 For each entry type a very small test file is created using fixed
111 string contents. This makes it easy to test that things look right, and
112 debug problems.
113
114 In some cases a 'real' file must be used - these are also supplied in
115 the test/ diurectory.
116 """
117 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600118 def setUpClass(cls):
Simon Glassb3393262017-11-12 21:52:20 -0700119 global entry
Simon Glassc585dd42020-04-17 18:09:03 -0600120 from binman import entry
Simon Glassb3393262017-11-12 21:52:20 -0700121
Simon Glass57454f42016-11-25 20:15:52 -0700122 # Handle the case where argv[0] is 'python'
Simon Glass862f8e22019-08-24 07:22:43 -0600123 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
124 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
Simon Glass57454f42016-11-25 20:15:52 -0700125
126 # Create a temporary directory for input files
Simon Glass862f8e22019-08-24 07:22:43 -0600127 cls._indir = tempfile.mkdtemp(prefix='binmant.')
Simon Glass57454f42016-11-25 20:15:52 -0700128
129 # Create some test files
130 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
131 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
132 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glass8425a1f2018-07-17 13:25:48 -0600133 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700134 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glass72232452016-11-25 20:15:53 -0700135 TestFunctional._MakeInputFile('me.bin', ME_DATA)
136 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glass862f8e22019-08-24 07:22:43 -0600137 cls._ResetDtbs()
Simon Glass0b074d62019-08-24 07:22:48 -0600138
Jagdish Gediya311d4842018-09-03 21:35:08 +0530139 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glass0b074d62019-08-24 07:22:48 -0600140
Simon Glassabab18c2019-08-24 07:22:49 -0600141 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
142 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
Simon Glasse83679d2017-11-12 21:52:26 -0700143 X86_START16_SPL_DATA)
Simon Glassabab18c2019-08-24 07:22:49 -0600144 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
Simon Glassed40e962018-09-14 04:57:10 -0600145 X86_START16_TPL_DATA)
Simon Glass0b074d62019-08-24 07:22:48 -0600146
147 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
148 X86_RESET16_DATA)
149 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
150 X86_RESET16_SPL_DATA)
151 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
152 X86_RESET16_TPL_DATA)
153
Simon Glass57454f42016-11-25 20:15:52 -0700154 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass3d274232017-11-12 21:52:27 -0700155 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
156 U_BOOT_SPL_NODTB_DATA)
Simon Glass3fb4f422018-09-14 04:57:32 -0600157 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
158 U_BOOT_TPL_NODTB_DATA)
Simon Glassb4176d42016-11-25 20:15:56 -0700159 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
160 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Mengd7bcdf52017-08-15 22:41:54 -0700161 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassa409c932017-11-12 21:52:28 -0700162 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassdb168d42018-07-17 13:25:39 -0600163 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600164 TestFunctional._MakeInputDir('devkeys')
165 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass41902e42018-10-01 12:22:31 -0600166 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glassba7985d2019-08-24 07:23:07 -0600167 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
Simon Glass4d9086d2019-10-20 21:31:35 -0600168 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
Simon Glass9ea87b22019-10-20 21:31:36 -0600169 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700170
Simon Glassf6290892019-08-24 07:22:53 -0600171 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
172 elf_test.BuildElfTestFiles(cls._elf_testdir)
173
Simon Glass72232452016-11-25 20:15:53 -0700174 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glass4affd4b2019-08-24 07:22:54 -0600175 TestFunctional._MakeInputFile('u-boot',
176 tools.ReadFile(cls.ElfTestFile('u_boot_ucode_ptr')))
Simon Glass72232452016-11-25 20:15:53 -0700177
178 # Intel flash descriptor file
Simon Glasse88cef92020-07-09 18:39:41 -0600179 cls._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -0700180
Simon Glass862f8e22019-08-24 07:22:43 -0600181 shutil.copytree(cls.TestFile('files'),
182 os.path.join(cls._indir, 'files'))
Simon Glassac6328c2018-09-14 04:57:28 -0600183
Simon Glass7ba33592018-09-14 04:57:26 -0600184 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
Simon Glassd92c8362020-10-26 17:40:25 -0600185 TestFunctional._MakeInputFile('compress_big', COMPRESS_DATA_BIG)
Simon Glass559c4de2020-09-01 05:13:58 -0600186 TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
Simon Glass3efb2972021-11-23 21:08:59 -0700187 TestFunctional._MakeInputFile('bl2u.bin', ATF_BL2U_DATA)
Bin Mengc0b15742021-05-10 20:23:33 +0800188 TestFunctional._MakeInputFile('fw_dynamic.bin', OPENSBI_DATA)
Samuel Holland9d8cc632020-10-21 21:12:15 -0500189 TestFunctional._MakeInputFile('scp.bin', SCP_DATA)
Simon Glass7ba33592018-09-14 04:57:26 -0600190
Simon Glassa435cd12020-09-01 05:13:59 -0600191 # Add a few .dtb files for testing
192 TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR,
193 TEST_FDT1_DATA)
194 TestFunctional._MakeInputFile('%s/test-fdt2.dtb' % TEST_FDT_SUBDIR,
195 TEST_FDT2_DATA)
196
Simon Glassa0729502020-09-06 10:35:33 -0600197 TestFunctional._MakeInputFile('env.txt', ENV_DATA)
198
Simon Glass1de34482019-07-08 13:18:53 -0600199 # Travis-CI may have an old lz4
Simon Glass862f8e22019-08-24 07:22:43 -0600200 cls.have_lz4 = True
Simon Glass1de34482019-07-08 13:18:53 -0600201 try:
202 tools.Run('lz4', '--no-frame-crc', '-c',
Simon Glasscc311ac2019-10-31 07:42:50 -0600203 os.path.join(cls._indir, 'u-boot.bin'), binary=True)
Simon Glass1de34482019-07-08 13:18:53 -0600204 except:
Simon Glass862f8e22019-08-24 07:22:43 -0600205 cls.have_lz4 = False
Simon Glass1de34482019-07-08 13:18:53 -0600206
Simon Glass57454f42016-11-25 20:15:52 -0700207 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600208 def tearDownClass(cls):
Simon Glass57454f42016-11-25 20:15:52 -0700209 """Remove the temporary input directory and its contents"""
Simon Glass862f8e22019-08-24 07:22:43 -0600210 if cls.preserve_indir:
211 print('Preserving input dir: %s' % cls._indir)
Simon Glass1c420c92019-07-08 13:18:49 -0600212 else:
Simon Glass862f8e22019-08-24 07:22:43 -0600213 if cls._indir:
214 shutil.rmtree(cls._indir)
215 cls._indir = None
Simon Glass57454f42016-11-25 20:15:52 -0700216
Simon Glass1c420c92019-07-08 13:18:49 -0600217 @classmethod
Simon Glasscebfab22019-07-08 13:18:50 -0600218 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
Simon Glassf46732a2019-07-08 14:25:29 -0600219 toolpath=None, verbosity=None):
Simon Glass1c420c92019-07-08 13:18:49 -0600220 """Accept arguments controlling test execution
221
222 Args:
223 preserve_indir: Preserve the shared input directory used by all
224 tests in this class.
225 preserve_outdir: Preserve the output directories used by tests. Each
226 test has its own, so this is normally only useful when running a
227 single test.
Simon Glasscebfab22019-07-08 13:18:50 -0600228 toolpath: ist of paths to use for tools
Simon Glass1c420c92019-07-08 13:18:49 -0600229 """
230 cls.preserve_indir = preserve_indir
231 cls.preserve_outdirs = preserve_outdirs
Simon Glasscebfab22019-07-08 13:18:50 -0600232 cls.toolpath = toolpath
Simon Glassf46732a2019-07-08 14:25:29 -0600233 cls.verbosity = verbosity
Simon Glass1c420c92019-07-08 13:18:49 -0600234
Simon Glass1de34482019-07-08 13:18:53 -0600235 def _CheckLz4(self):
236 if not self.have_lz4:
237 self.skipTest('lz4 --no-frame-crc not available')
238
Simon Glassee9d10d2019-07-20 12:24:09 -0600239 def _CleanupOutputDir(self):
240 """Remove the temporary output directory"""
241 if self.preserve_outdirs:
242 print('Preserving output dir: %s' % tools.outdir)
243 else:
244 tools._FinaliseForTest()
245
Simon Glass57454f42016-11-25 20:15:52 -0700246 def setUp(self):
247 # Enable this to turn on debugging output
248 # tout.Init(tout.DEBUG)
249 command.test_result = None
250
251 def tearDown(self):
252 """Remove the temporary output directory"""
Simon Glassee9d10d2019-07-20 12:24:09 -0600253 self._CleanupOutputDir()
Simon Glass57454f42016-11-25 20:15:52 -0700254
Simon Glassb3d6fc72019-07-20 12:24:10 -0600255 def _SetupImageInTmpdir(self):
256 """Set up the output image in a new temporary directory
257
258 This is used when an image has been generated in the output directory,
259 but we want to run binman again. This will create a new output
260 directory and fail to delete the original one.
261
262 This creates a new temporary directory, copies the image to it (with a
263 new name) and removes the old output directory.
264
265 Returns:
266 Tuple:
267 Temporary directory to use
268 New image filename
269 """
270 image_fname = tools.GetOutputFilename('image.bin')
271 tmpdir = tempfile.mkdtemp(prefix='binman.')
272 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
273 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
274 self._CleanupOutputDir()
275 return tmpdir, updated_fname
276
Simon Glass8425a1f2018-07-17 13:25:48 -0600277 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600278 def _ResetDtbs(cls):
Simon Glass8425a1f2018-07-17 13:25:48 -0600279 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
280 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
281 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
282
Simon Glass57454f42016-11-25 20:15:52 -0700283 def _RunBinman(self, *args, **kwargs):
284 """Run binman using the command line
285
286 Args:
287 Arguments to pass, as a list of strings
288 kwargs: Arguments to pass to Command.RunPipe()
289 """
290 result = command.RunPipe([[self._binman_pathname] + list(args)],
291 capture=True, capture_stderr=True, raise_on_error=False)
292 if result.return_code and kwargs.get('raise_on_error', True):
293 raise Exception("Error running '%s': %s" % (' '.join(args),
294 result.stdout + result.stderr))
295 return result
296
Simon Glassf46732a2019-07-08 14:25:29 -0600297 def _DoBinman(self, *argv):
Simon Glass57454f42016-11-25 20:15:52 -0700298 """Run binman using directly (in the same process)
299
300 Args:
301 Arguments to pass, as a list of strings
302 Returns:
303 Return value (0 for success)
304 """
Simon Glassf46732a2019-07-08 14:25:29 -0600305 argv = list(argv)
306 args = cmdline.ParseArgs(argv)
307 args.pager = 'binman-invalid-pager'
308 args.build_dir = self._indir
Simon Glass57454f42016-11-25 20:15:52 -0700309
310 # For testing, you can force an increase in verbosity here
Simon Glassf46732a2019-07-08 14:25:29 -0600311 # args.verbosity = tout.DEBUG
312 return control.Binman(args)
Simon Glass57454f42016-11-25 20:15:52 -0700313
Simon Glass91710b32018-07-17 13:25:32 -0600314 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glassb4595d82019-04-25 21:58:34 -0600315 entry_args=None, images=None, use_real_dtb=False,
Simon Glassed930672021-03-18 20:25:05 +1300316 use_expanded=False, verbosity=None, allow_missing=False,
Heiko Thiery6d451362022-01-06 11:49:41 +0100317 allow_fake_blobs=False, extra_indirs=None, threads=None,
Simon Glassadfb8492021-11-03 21:09:18 -0600318 test_section_timeout=False, update_fdt_in_elf=None):
Simon Glass57454f42016-11-25 20:15:52 -0700319 """Run binman with a given test file
320
321 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600322 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600323 debug: True to enable debugging output
Simon Glass30732662018-06-01 09:38:20 -0600324 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600325 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600326 tree before packing it into the image
Simon Glass3b376c32018-09-14 04:57:12 -0600327 entry_args: Dict of entry args to supply to binman
328 key: arg name
329 value: value of that arg
330 images: List of image names to build
Simon Glass31ee50f2020-09-01 05:13:55 -0600331 use_real_dtb: True to use the test file as the contents of
332 the u-boot-dtb entry. Normally this is not needed and the
333 test contents (the U_BOOT_DTB_DATA string) can be used.
334 But in some test we need the real contents.
Simon Glassed930672021-03-18 20:25:05 +1300335 use_expanded: True to use expanded entries where available, e.g.
336 'u-boot-expanded' instead of 'u-boot'
Simon Glass31ee50f2020-09-01 05:13:55 -0600337 verbosity: Verbosity level to use (0-3, None=don't set it)
338 allow_missing: Set the '--allow-missing' flag so that missing
339 external binaries just produce a warning instead of an error
Heiko Thiery6d451362022-01-06 11:49:41 +0100340 allow_fake_blobs: Set the '--fake-ext-blobs' flag
Simon Glassa435cd12020-09-01 05:13:59 -0600341 extra_indirs: Extra input directories to add using -I
Simon Glass76f496d2021-07-06 10:36:37 -0600342 threads: Number of threads to use (None for default, 0 for
343 single-threaded)
Simon Glass9a798402021-11-03 21:09:17 -0600344 test_section_timeout: True to force the first time to timeout, as
345 used in testThreadTimeout()
Simon Glassadfb8492021-11-03 21:09:18 -0600346 update_fdt_in_elf: Value to pass with --update-fdt-in-elf=xxx
Simon Glass9a798402021-11-03 21:09:17 -0600347
348 Returns:
349 int return code, 0 on success
Simon Glass57454f42016-11-25 20:15:52 -0700350 """
Simon Glassf46732a2019-07-08 14:25:29 -0600351 args = []
Simon Glass075a45c2017-11-13 18:55:00 -0700352 if debug:
353 args.append('-D')
Simon Glassf46732a2019-07-08 14:25:29 -0600354 if verbosity is not None:
355 args.append('-v%d' % verbosity)
356 elif self.verbosity:
357 args.append('-v%d' % self.verbosity)
358 if self.toolpath:
359 for path in self.toolpath:
360 args += ['--toolpath', path]
Simon Glass76f496d2021-07-06 10:36:37 -0600361 if threads is not None:
362 args.append('-T%d' % threads)
363 if test_section_timeout:
364 args.append('--test-section-timeout')
Simon Glassf46732a2019-07-08 14:25:29 -0600365 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass30732662018-06-01 09:38:20 -0600366 if map:
367 args.append('-m')
Simon Glassa87014e2018-07-06 10:27:42 -0600368 if update_dtb:
Simon Glass38a411c2019-07-08 13:18:47 -0600369 args.append('-u')
Simon Glass31402012018-09-14 04:57:23 -0600370 if not use_real_dtb:
371 args.append('--fake-dtb')
Simon Glassed930672021-03-18 20:25:05 +1300372 if not use_expanded:
373 args.append('--no-expanded')
Simon Glass91710b32018-07-17 13:25:32 -0600374 if entry_args:
Simon Glass5f3645b2019-05-14 15:53:41 -0600375 for arg, value in entry_args.items():
Simon Glass91710b32018-07-17 13:25:32 -0600376 args.append('-a%s=%s' % (arg, value))
Simon Glass5d94cc62020-07-09 18:39:38 -0600377 if allow_missing:
378 args.append('-M')
Heiko Thiery6d451362022-01-06 11:49:41 +0100379 if allow_fake_blobs:
380 args.append('--fake-ext-blobs')
Simon Glassadfb8492021-11-03 21:09:18 -0600381 if update_fdt_in_elf:
382 args += ['--update-fdt-in-elf', update_fdt_in_elf]
Simon Glass3b376c32018-09-14 04:57:12 -0600383 if images:
384 for image in images:
385 args += ['-i', image]
Simon Glassa435cd12020-09-01 05:13:59 -0600386 if extra_indirs:
387 for indir in extra_indirs:
388 args += ['-I', indir]
Simon Glass075a45c2017-11-13 18:55:00 -0700389 return self._DoBinman(*args)
Simon Glass57454f42016-11-25 20:15:52 -0700390
391 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glass72232452016-11-25 20:15:53 -0700392 """Set up a new test device-tree file
393
394 The given file is compiled and set up as the device tree to be used
395 for ths test.
396
397 Args:
398 fname: Filename of .dts file to read
Simon Glass1e324002018-06-01 09:38:19 -0600399 outfile: Output filename for compiled device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700400
401 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600402 Contents of device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700403 """
Simon Glassb8d2daa2019-07-20 12:23:49 -0600404 tmpdir = tempfile.mkdtemp(prefix='binmant.')
405 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
Simon Glass33486662019-05-14 15:53:42 -0600406 with open(dtb, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700407 data = fd.read()
408 TestFunctional._MakeInputFile(outfile, data)
Simon Glassb8d2daa2019-07-20 12:23:49 -0600409 shutil.rmtree(tmpdir)
Simon Glass752e7552018-10-01 21:12:41 -0600410 return data
Simon Glass57454f42016-11-25 20:15:52 -0700411
Simon Glasse219aa42018-09-14 04:57:24 -0600412 def _GetDtbContentsForSplTpl(self, dtb_data, name):
413 """Create a version of the main DTB for SPL or SPL
414
415 For testing we don't actually have different versions of the DTB. With
416 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
417 we don't normally have any unwanted nodes.
418
419 We still want the DTBs for SPL and TPL to be different though, since
420 otherwise it is confusing to know which one we are looking at. So add
421 an 'spl' or 'tpl' property to the top-level node.
Simon Glass31ee50f2020-09-01 05:13:55 -0600422
423 Args:
424 dtb_data: dtb data to modify (this should be a value devicetree)
425 name: Name of a new property to add
426
427 Returns:
428 New dtb data with the property added
Simon Glasse219aa42018-09-14 04:57:24 -0600429 """
430 dtb = fdt.Fdt.FromData(dtb_data)
431 dtb.Scan()
432 dtb.GetNode('/binman').AddZeroProp(name)
433 dtb.Sync(auto_resize=True)
434 dtb.Pack()
435 return dtb.GetContents()
436
Simon Glassed930672021-03-18 20:25:05 +1300437 def _DoReadFileDtb(self, fname, use_real_dtb=False, use_expanded=False,
438 map=False, update_dtb=False, entry_args=None,
Simon Glass76f496d2021-07-06 10:36:37 -0600439 reset_dtbs=True, extra_indirs=None, threads=None):
Simon Glass57454f42016-11-25 20:15:52 -0700440 """Run binman and return the resulting image
441
442 This runs binman with a given test file and then reads the resulting
443 output file. It is a shortcut function since most tests need to do
444 these steps.
445
446 Raises an assertion failure if binman returns a non-zero exit code.
447
448 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600449 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass57454f42016-11-25 20:15:52 -0700450 use_real_dtb: True to use the test file as the contents of
451 the u-boot-dtb entry. Normally this is not needed and the
452 test contents (the U_BOOT_DTB_DATA string) can be used.
453 But in some test we need the real contents.
Simon Glassed930672021-03-18 20:25:05 +1300454 use_expanded: True to use expanded entries where available, e.g.
455 'u-boot-expanded' instead of 'u-boot'
Simon Glass30732662018-06-01 09:38:20 -0600456 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600457 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600458 tree before packing it into the image
Simon Glass31ee50f2020-09-01 05:13:55 -0600459 entry_args: Dict of entry args to supply to binman
460 key: arg name
461 value: value of that arg
462 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
463 function. If reset_dtbs is True, then the original test dtb
464 is written back before this function finishes
Simon Glassa435cd12020-09-01 05:13:59 -0600465 extra_indirs: Extra input directories to add using -I
Simon Glass76f496d2021-07-06 10:36:37 -0600466 threads: Number of threads to use (None for default, 0 for
467 single-threaded)
Simon Glass72232452016-11-25 20:15:53 -0700468
469 Returns:
470 Tuple:
471 Resulting image contents
472 Device tree contents
Simon Glass30732662018-06-01 09:38:20 -0600473 Map data showing contents of image (or None if none)
Simon Glassdef77b52018-07-17 13:25:27 -0600474 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass57454f42016-11-25 20:15:52 -0700475 """
Simon Glass72232452016-11-25 20:15:53 -0700476 dtb_data = None
Simon Glass57454f42016-11-25 20:15:52 -0700477 # Use the compiled test file as the u-boot-dtb input
478 if use_real_dtb:
Simon Glass72232452016-11-25 20:15:53 -0700479 dtb_data = self._SetupDtb(fname)
Simon Glasse219aa42018-09-14 04:57:24 -0600480
481 # For testing purposes, make a copy of the DT for SPL and TPL. Add
482 # a node indicating which it is, so aid verification.
483 for name in ['spl', 'tpl']:
484 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
485 outfile = os.path.join(self._indir, dtb_fname)
486 TestFunctional._MakeInputFile(dtb_fname,
487 self._GetDtbContentsForSplTpl(dtb_data, name))
Simon Glass57454f42016-11-25 20:15:52 -0700488
489 try:
Simon Glass91710b32018-07-17 13:25:32 -0600490 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glassa435cd12020-09-01 05:13:59 -0600491 entry_args=entry_args, use_real_dtb=use_real_dtb,
Simon Glass76f496d2021-07-06 10:36:37 -0600492 use_expanded=use_expanded, extra_indirs=extra_indirs,
493 threads=threads)
Simon Glass57454f42016-11-25 20:15:52 -0700494 self.assertEqual(0, retcode)
Simon Glasse219aa42018-09-14 04:57:24 -0600495 out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
Simon Glass57454f42016-11-25 20:15:52 -0700496
497 # Find the (only) image, read it and return its contents
498 image = control.images['image']
Simon Glassa87014e2018-07-06 10:27:42 -0600499 image_fname = tools.GetOutputFilename('image.bin')
500 self.assertTrue(os.path.exists(image_fname))
Simon Glass30732662018-06-01 09:38:20 -0600501 if map:
502 map_fname = tools.GetOutputFilename('image.map')
503 with open(map_fname) as fd:
504 map_data = fd.read()
505 else:
506 map_data = None
Simon Glass33486662019-05-14 15:53:42 -0600507 with open(image_fname, 'rb') as fd:
Simon Glassa87014e2018-07-06 10:27:42 -0600508 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass57454f42016-11-25 20:15:52 -0700509 finally:
510 # Put the test file back
Simon Glasse219aa42018-09-14 04:57:24 -0600511 if reset_dtbs and use_real_dtb:
Simon Glass8425a1f2018-07-17 13:25:48 -0600512 self._ResetDtbs()
Simon Glass57454f42016-11-25 20:15:52 -0700513
Simon Glass5b4bce32019-07-08 14:25:26 -0600514 def _DoReadFileRealDtb(self, fname):
515 """Run binman with a real .dtb file and return the resulting data
516
517 Args:
518 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
519
520 Returns:
521 Resulting image contents
522 """
523 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
524
Simon Glass72232452016-11-25 20:15:53 -0700525 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass1e324002018-06-01 09:38:19 -0600526 """Helper function which discards the device-tree binary
527
528 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600529 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600530 use_real_dtb: True to use the test file as the contents of
531 the u-boot-dtb entry. Normally this is not needed and the
532 test contents (the U_BOOT_DTB_DATA string) can be used.
533 But in some test we need the real contents.
Simon Glassdef77b52018-07-17 13:25:27 -0600534
535 Returns:
536 Resulting image contents
Simon Glass1e324002018-06-01 09:38:19 -0600537 """
Simon Glass72232452016-11-25 20:15:53 -0700538 return self._DoReadFileDtb(fname, use_real_dtb)[0]
539
Simon Glass57454f42016-11-25 20:15:52 -0700540 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600541 def _MakeInputFile(cls, fname, contents):
Simon Glass57454f42016-11-25 20:15:52 -0700542 """Create a new test input file, creating directories as needed
543
544 Args:
Simon Glasse8561af2018-08-01 15:22:37 -0600545 fname: Filename to create
Simon Glass57454f42016-11-25 20:15:52 -0700546 contents: File contents to write in to the file
547 Returns:
548 Full pathname of file created
549 """
Simon Glass862f8e22019-08-24 07:22:43 -0600550 pathname = os.path.join(cls._indir, fname)
Simon Glass57454f42016-11-25 20:15:52 -0700551 dirname = os.path.dirname(pathname)
552 if dirname and not os.path.exists(dirname):
553 os.makedirs(dirname)
554 with open(pathname, 'wb') as fd:
555 fd.write(contents)
556 return pathname
557
558 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600559 def _MakeInputDir(cls, dirname):
Simon Glassc1ae83c2018-07-17 13:25:44 -0600560 """Create a new test input directory, creating directories as needed
561
562 Args:
563 dirname: Directory name to create
564
565 Returns:
566 Full pathname of directory created
567 """
Simon Glass862f8e22019-08-24 07:22:43 -0600568 pathname = os.path.join(cls._indir, dirname)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600569 if not os.path.exists(pathname):
570 os.makedirs(pathname)
571 return pathname
572
573 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600574 def _SetupSplElf(cls, src_fname='bss_data'):
Simon Glass7057d022018-10-01 21:12:47 -0600575 """Set up an ELF file with a '_dt_ucode_base_size' symbol
576
577 Args:
578 Filename of ELF file to use as SPL
579 """
Simon Glass93a806f2019-08-24 07:22:59 -0600580 TestFunctional._MakeInputFile('spl/u-boot-spl',
581 tools.ReadFile(cls.ElfTestFile(src_fname)))
Simon Glass7057d022018-10-01 21:12:47 -0600582
583 @classmethod
Simon Glass3eb5b202019-08-24 07:23:00 -0600584 def _SetupTplElf(cls, src_fname='bss_data'):
585 """Set up an ELF file with a '_dt_ucode_base_size' symbol
586
587 Args:
588 Filename of ELF file to use as TPL
589 """
590 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
591 tools.ReadFile(cls.ElfTestFile(src_fname)))
592
593 @classmethod
Simon Glasse88cef92020-07-09 18:39:41 -0600594 def _SetupDescriptor(cls):
595 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
596 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
597
598 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600599 def TestFile(cls, fname):
600 return os.path.join(cls._binman_dir, 'test', fname)
Simon Glass57454f42016-11-25 20:15:52 -0700601
Simon Glassf6290892019-08-24 07:22:53 -0600602 @classmethod
603 def ElfTestFile(cls, fname):
604 return os.path.join(cls._elf_testdir, fname)
605
Simon Glass57454f42016-11-25 20:15:52 -0700606 def AssertInList(self, grep_list, target):
607 """Assert that at least one of a list of things is in a target
608
609 Args:
610 grep_list: List of strings to check
611 target: Target string
612 """
613 for grep in grep_list:
614 if grep in target:
615 return
Simon Glass848cdb52019-05-17 22:00:50 -0600616 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass57454f42016-11-25 20:15:52 -0700617
618 def CheckNoGaps(self, entries):
619 """Check that all entries fit together without gaps
620
621 Args:
622 entries: List of entries to check
623 """
Simon Glasse8561af2018-08-01 15:22:37 -0600624 offset = 0
Simon Glass57454f42016-11-25 20:15:52 -0700625 for entry in entries.values():
Simon Glasse8561af2018-08-01 15:22:37 -0600626 self.assertEqual(offset, entry.offset)
627 offset += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700628
Simon Glass72232452016-11-25 20:15:53 -0700629 def GetFdtLen(self, dtb):
Simon Glass1e324002018-06-01 09:38:19 -0600630 """Get the totalsize field from a device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700631
632 Args:
Simon Glass1e324002018-06-01 09:38:19 -0600633 dtb: Device-tree binary contents
Simon Glass72232452016-11-25 20:15:53 -0700634
635 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600636 Total size of device-tree binary, from the header
Simon Glass72232452016-11-25 20:15:53 -0700637 """
638 return struct.unpack('>L', dtb[4:8])[0]
639
Simon Glass0f621332019-07-08 14:25:27 -0600640 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glassa87014e2018-07-06 10:27:42 -0600641 def AddNode(node, path):
642 if node.name != '/':
643 path += '/' + node.name
Simon Glass0f621332019-07-08 14:25:27 -0600644 for prop in node.props.values():
645 if prop.name in prop_names:
646 prop_path = path + ':' + prop.name
647 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
648 prop.value)
Simon Glassa87014e2018-07-06 10:27:42 -0600649 for subnode in node.subnodes:
Simon Glassa87014e2018-07-06 10:27:42 -0600650 AddNode(subnode, path)
651
652 tree = {}
Simon Glassa87014e2018-07-06 10:27:42 -0600653 AddNode(dtb.GetRoot(), '')
654 return tree
655
Simon Glass57454f42016-11-25 20:15:52 -0700656 def testRun(self):
657 """Test a basic run with valid args"""
658 result = self._RunBinman('-h')
659
660 def testFullHelp(self):
661 """Test that the full help is displayed with -H"""
662 result = self._RunBinman('-H')
Simon Glass75ead662021-03-18 20:25:13 +1300663 help_file = os.path.join(self._binman_dir, 'README.rst')
Tom Rinic3c0b6d2018-01-16 15:29:50 -0500664 # Remove possible extraneous strings
665 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
666 gothelp = result.stdout.replace(extra, '')
667 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass57454f42016-11-25 20:15:52 -0700668 self.assertEqual(0, len(result.stderr))
669 self.assertEqual(0, result.return_code)
670
671 def testFullHelpInternal(self):
672 """Test that the full help is displayed with -H"""
673 try:
674 command.test_result = command.CommandResult()
675 result = self._DoBinman('-H')
Simon Glass75ead662021-03-18 20:25:13 +1300676 help_file = os.path.join(self._binman_dir, 'README.rst')
Simon Glass57454f42016-11-25 20:15:52 -0700677 finally:
678 command.test_result = None
679
680 def testHelp(self):
681 """Test that the basic help is displayed with -h"""
682 result = self._RunBinman('-h')
683 self.assertTrue(len(result.stdout) > 200)
684 self.assertEqual(0, len(result.stderr))
685 self.assertEqual(0, result.return_code)
686
Simon Glass57454f42016-11-25 20:15:52 -0700687 def testBoard(self):
688 """Test that we can run it with a specific board"""
Simon Glass511f6582018-10-01 12:22:30 -0600689 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass57454f42016-11-25 20:15:52 -0700690 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glassed930672021-03-18 20:25:05 +1300691 result = self._DoBinman('build', '-n', '-b', 'sandbox')
Simon Glass57454f42016-11-25 20:15:52 -0700692 self.assertEqual(0, result)
693
694 def testNeedBoard(self):
695 """Test that we get an error when no board ius supplied"""
696 with self.assertRaises(ValueError) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600697 result = self._DoBinman('build')
Simon Glass57454f42016-11-25 20:15:52 -0700698 self.assertIn("Must provide a board to process (use -b <board>)",
699 str(e.exception))
700
701 def testMissingDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600702 """Test that an invalid device-tree file generates an error"""
Simon Glass57454f42016-11-25 20:15:52 -0700703 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600704 self._RunBinman('build', '-d', 'missing_file')
Simon Glass57454f42016-11-25 20:15:52 -0700705 # We get one error from libfdt, and a different one from fdtget.
706 self.AssertInList(["Couldn't open blob from 'missing_file'",
707 'No such file or directory'], str(e.exception))
708
709 def testBrokenDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600710 """Test that an invalid device-tree source file generates an error
Simon Glass57454f42016-11-25 20:15:52 -0700711
712 Since this is a source file it should be compiled and the error
713 will come from the device-tree compiler (dtc).
714 """
715 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600716 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700717 self.assertIn("FATAL ERROR: Unable to parse input tree",
718 str(e.exception))
719
720 def testMissingNode(self):
721 """Test that a device tree without a 'binman' node generates an error"""
722 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600723 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700724 self.assertIn("does not have a 'binman' node", str(e.exception))
725
726 def testEmpty(self):
727 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glassf46732a2019-07-08 14:25:29 -0600728 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700729 self.assertEqual(0, len(result.stderr))
730 self.assertEqual(0, result.return_code)
731
732 def testInvalidEntry(self):
733 """Test that an invalid entry is flagged"""
734 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600735 result = self._RunBinman('build', '-d',
Simon Glass511f6582018-10-01 12:22:30 -0600736 self.TestFile('004_invalid_entry.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700737 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
738 "'/binman/not-a-valid-type'", str(e.exception))
739
740 def testSimple(self):
741 """Test a simple binman with a single file"""
Simon Glass511f6582018-10-01 12:22:30 -0600742 data = self._DoReadFile('005_simple.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700743 self.assertEqual(U_BOOT_DATA, data)
744
Simon Glass075a45c2017-11-13 18:55:00 -0700745 def testSimpleDebug(self):
746 """Test a simple binman run with debugging enabled"""
Simon Glass52d06212019-07-08 14:25:53 -0600747 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass075a45c2017-11-13 18:55:00 -0700748
Simon Glass57454f42016-11-25 20:15:52 -0700749 def testDual(self):
750 """Test that we can handle creating two images
751
752 This also tests image padding.
753 """
Simon Glass511f6582018-10-01 12:22:30 -0600754 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700755 self.assertEqual(0, retcode)
756
757 image = control.images['image1']
Simon Glass39dd2152019-07-08 14:25:47 -0600758 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700759 fname = tools.GetOutputFilename('image1.bin')
760 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600761 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700762 data = fd.read()
763 self.assertEqual(U_BOOT_DATA, data)
764
765 image = control.images['image2']
Simon Glass39dd2152019-07-08 14:25:47 -0600766 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700767 fname = tools.GetOutputFilename('image2.bin')
768 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600769 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700770 data = fd.read()
771 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glassac0d4952019-05-14 15:53:47 -0600772 self.assertEqual(tools.GetBytes(0, 3), data[:3])
773 self.assertEqual(tools.GetBytes(0, 5), data[7:])
Simon Glass57454f42016-11-25 20:15:52 -0700774
775 def testBadAlign(self):
776 """Test that an invalid alignment value is detected"""
777 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600778 self._DoTestFile('007_bad_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700779 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
780 "of two", str(e.exception))
781
782 def testPackSimple(self):
783 """Test that packing works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -0600784 retcode = self._DoTestFile('008_pack.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700785 self.assertEqual(0, retcode)
786 self.assertIn('image', control.images)
787 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600788 entries = image.GetEntries()
Simon Glass57454f42016-11-25 20:15:52 -0700789 self.assertEqual(5, len(entries))
790
791 # First u-boot
792 self.assertIn('u-boot', entries)
793 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600794 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700795 self.assertEqual(len(U_BOOT_DATA), entry.size)
796
797 # Second u-boot, aligned to 16-byte boundary
798 self.assertIn('u-boot-align', entries)
799 entry = entries['u-boot-align']
Simon Glasse8561af2018-08-01 15:22:37 -0600800 self.assertEqual(16, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700801 self.assertEqual(len(U_BOOT_DATA), entry.size)
802
803 # Third u-boot, size 23 bytes
804 self.assertIn('u-boot-size', entries)
805 entry = entries['u-boot-size']
Simon Glasse8561af2018-08-01 15:22:37 -0600806 self.assertEqual(20, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700807 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
808 self.assertEqual(23, entry.size)
809
810 # Fourth u-boot, placed immediate after the above
811 self.assertIn('u-boot-next', entries)
812 entry = entries['u-boot-next']
Simon Glasse8561af2018-08-01 15:22:37 -0600813 self.assertEqual(43, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700814 self.assertEqual(len(U_BOOT_DATA), entry.size)
815
Simon Glasse8561af2018-08-01 15:22:37 -0600816 # Fifth u-boot, placed at a fixed offset
Simon Glass57454f42016-11-25 20:15:52 -0700817 self.assertIn('u-boot-fixed', entries)
818 entry = entries['u-boot-fixed']
Simon Glasse8561af2018-08-01 15:22:37 -0600819 self.assertEqual(61, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700820 self.assertEqual(len(U_BOOT_DATA), entry.size)
821
Simon Glass39dd2152019-07-08 14:25:47 -0600822 self.assertEqual(65, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700823
824 def testPackExtra(self):
825 """Test that extra packing feature works as expected"""
Simon Glassafb9caa2020-10-26 17:40:10 -0600826 data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
827 update_dtb=True)
Simon Glass57454f42016-11-25 20:15:52 -0700828
Simon Glass57454f42016-11-25 20:15:52 -0700829 self.assertIn('image', control.images)
830 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600831 entries = image.GetEntries()
Simon Glass57454f42016-11-25 20:15:52 -0700832 self.assertEqual(5, len(entries))
833
834 # First u-boot with padding before and after
835 self.assertIn('u-boot', entries)
836 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600837 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700838 self.assertEqual(3, entry.pad_before)
839 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600840 self.assertEqual(U_BOOT_DATA, entry.data)
841 self.assertEqual(tools.GetBytes(0, 3) + U_BOOT_DATA +
842 tools.GetBytes(0, 5), data[:entry.size])
843 pos = entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700844
845 # Second u-boot has an aligned size, but it has no effect
846 self.assertIn('u-boot-align-size-nop', entries)
847 entry = entries['u-boot-align-size-nop']
Simon Glass187202f2020-10-26 17:40:08 -0600848 self.assertEqual(pos, entry.offset)
849 self.assertEqual(len(U_BOOT_DATA), entry.size)
850 self.assertEqual(U_BOOT_DATA, entry.data)
851 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
852 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700853
854 # Third u-boot has an aligned size too
855 self.assertIn('u-boot-align-size', entries)
856 entry = entries['u-boot-align-size']
Simon Glass187202f2020-10-26 17:40:08 -0600857 self.assertEqual(pos, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700858 self.assertEqual(32, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600859 self.assertEqual(U_BOOT_DATA, entry.data)
860 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 32 - len(U_BOOT_DATA)),
861 data[pos:pos + entry.size])
862 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700863
864 # Fourth u-boot has an aligned end
865 self.assertIn('u-boot-align-end', entries)
866 entry = entries['u-boot-align-end']
Simon Glasse8561af2018-08-01 15:22:37 -0600867 self.assertEqual(48, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700868 self.assertEqual(16, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600869 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
870 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 16 - len(U_BOOT_DATA)),
871 data[pos:pos + entry.size])
872 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700873
874 # Fifth u-boot immediately afterwards
875 self.assertIn('u-boot-align-both', entries)
876 entry = entries['u-boot-align-both']
Simon Glasse8561af2018-08-01 15:22:37 -0600877 self.assertEqual(64, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700878 self.assertEqual(64, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600879 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
880 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 64 - len(U_BOOT_DATA)),
881 data[pos:pos + entry.size])
Simon Glass57454f42016-11-25 20:15:52 -0700882
883 self.CheckNoGaps(entries)
Simon Glass39dd2152019-07-08 14:25:47 -0600884 self.assertEqual(128, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700885
Simon Glassafb9caa2020-10-26 17:40:10 -0600886 dtb = fdt.Fdt(out_dtb_fname)
887 dtb.Scan()
888 props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
889 expected = {
890 'image-pos': 0,
891 'offset': 0,
892 'size': 128,
893
894 'u-boot:image-pos': 0,
895 'u-boot:offset': 0,
896 'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
897
898 'u-boot-align-size-nop:image-pos': 12,
899 'u-boot-align-size-nop:offset': 12,
900 'u-boot-align-size-nop:size': 4,
901
902 'u-boot-align-size:image-pos': 16,
903 'u-boot-align-size:offset': 16,
904 'u-boot-align-size:size': 32,
905
906 'u-boot-align-end:image-pos': 48,
907 'u-boot-align-end:offset': 48,
908 'u-boot-align-end:size': 16,
909
910 'u-boot-align-both:image-pos': 64,
911 'u-boot-align-both:offset': 64,
912 'u-boot-align-both:size': 64,
913 }
914 self.assertEqual(expected, props)
915
Simon Glass57454f42016-11-25 20:15:52 -0700916 def testPackAlignPowerOf2(self):
917 """Test that invalid entry alignment is detected"""
918 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600919 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700920 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
921 "of two", str(e.exception))
922
923 def testPackAlignSizePowerOf2(self):
924 """Test that invalid entry size alignment is detected"""
925 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600926 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700927 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
928 "power of two", str(e.exception))
929
930 def testPackInvalidAlign(self):
Simon Glasse8561af2018-08-01 15:22:37 -0600931 """Test detection of an offset that does not match its alignment"""
Simon Glass57454f42016-11-25 20:15:52 -0700932 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600933 self._DoTestFile('012_pack_inv_align.dts')
Simon Glasse8561af2018-08-01 15:22:37 -0600934 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass57454f42016-11-25 20:15:52 -0700935 "align 0x4 (4)", str(e.exception))
936
937 def testPackInvalidSizeAlign(self):
938 """Test that invalid entry size alignment is detected"""
939 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600940 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700941 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
942 "align-size 0x4 (4)", str(e.exception))
943
944 def testPackOverlap(self):
945 """Test that overlapping regions are detected"""
946 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600947 self._DoTestFile('014_pack_overlap.dts')
Simon Glasse8561af2018-08-01 15:22:37 -0600948 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -0700949 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
950 str(e.exception))
951
952 def testPackEntryOverflow(self):
953 """Test that entries that overflow their size are detected"""
954 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600955 self._DoTestFile('015_pack_overflow.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700956 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
957 "but entry size is 0x3 (3)", str(e.exception))
958
959 def testPackImageOverflow(self):
960 """Test that entries which overflow the image size are detected"""
961 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600962 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glasseca32212018-06-01 09:38:12 -0600963 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass57454f42016-11-25 20:15:52 -0700964 "size 0x3 (3)", str(e.exception))
965
966 def testPackImageSize(self):
967 """Test that the image size can be set"""
Simon Glass511f6582018-10-01 12:22:30 -0600968 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700969 self.assertEqual(0, retcode)
970 self.assertIn('image', control.images)
971 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -0600972 self.assertEqual(7, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700973
974 def testPackImageSizeAlign(self):
975 """Test that image size alignemnt works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -0600976 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700977 self.assertEqual(0, retcode)
978 self.assertIn('image', control.images)
979 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -0600980 self.assertEqual(16, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700981
982 def testPackInvalidImageAlign(self):
983 """Test that invalid image alignment is detected"""
984 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600985 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glasseca32212018-06-01 09:38:12 -0600986 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass57454f42016-11-25 20:15:52 -0700987 "align-size 0x8 (8)", str(e.exception))
988
989 def testPackAlignPowerOf2(self):
990 """Test that invalid image alignment is detected"""
991 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600992 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass39dd2152019-07-08 14:25:47 -0600993 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass57454f42016-11-25 20:15:52 -0700994 "two", str(e.exception))
995
996 def testImagePadByte(self):
997 """Test that the image pad byte can be specified"""
Simon Glass7057d022018-10-01 21:12:47 -0600998 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -0600999 data = self._DoReadFile('021_image_pad.dts')
Simon Glassac0d4952019-05-14 15:53:47 -06001000 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0xff, 1) +
1001 U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -07001002
1003 def testImageName(self):
1004 """Test that image files can be named"""
Simon Glass511f6582018-10-01 12:22:30 -06001005 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001006 self.assertEqual(0, retcode)
1007 image = control.images['image1']
1008 fname = tools.GetOutputFilename('test-name')
1009 self.assertTrue(os.path.exists(fname))
1010
1011 image = control.images['image2']
1012 fname = tools.GetOutputFilename('test-name.xx')
1013 self.assertTrue(os.path.exists(fname))
1014
1015 def testBlobFilename(self):
1016 """Test that generic blobs can be provided by filename"""
Simon Glass511f6582018-10-01 12:22:30 -06001017 data = self._DoReadFile('023_blob.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001018 self.assertEqual(BLOB_DATA, data)
1019
1020 def testPackSorted(self):
1021 """Test that entries can be sorted"""
Simon Glass7057d022018-10-01 21:12:47 -06001022 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001023 data = self._DoReadFile('024_sorted.dts')
Simon Glassac0d4952019-05-14 15:53:47 -06001024 self.assertEqual(tools.GetBytes(0, 1) + U_BOOT_SPL_DATA +
1025 tools.GetBytes(0, 2) + U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -07001026
Simon Glasse8561af2018-08-01 15:22:37 -06001027 def testPackZeroOffset(self):
1028 """Test that an entry at offset 0 is not given a new offset"""
Simon Glass57454f42016-11-25 20:15:52 -07001029 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001030 self._DoTestFile('025_pack_zero_size.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001031 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -07001032 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1033 str(e.exception))
1034
1035 def testPackUbootDtb(self):
1036 """Test that a device tree can be added to U-Boot"""
Simon Glass511f6582018-10-01 12:22:30 -06001037 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001038 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glass72232452016-11-25 20:15:53 -07001039
1040 def testPackX86RomNoSize(self):
1041 """Test that the end-at-4gb property requires a size property"""
1042 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001043 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001044 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glass72232452016-11-25 20:15:53 -07001045 "using end-at-4gb", str(e.exception))
1046
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301047 def test4gbAndSkipAtStartTogether(self):
1048 """Test that the end-at-4gb and skip-at-size property can't be used
1049 together"""
1050 with self.assertRaises(ValueError) as e:
Simon Glass11f2bd02019-08-24 07:23:02 -06001051 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001052 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301053 "'skip-at-start'", str(e.exception))
1054
Simon Glass72232452016-11-25 20:15:53 -07001055 def testPackX86RomOutside(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001056 """Test that the end-at-4gb property checks for offset boundaries"""
Simon Glass72232452016-11-25 20:15:53 -07001057 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001058 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glassd6179862020-10-26 17:40:05 -06001059 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
1060 "is outside the section '/binman' starting at "
1061 '0xffffffe0 (4294967264) of size 0x20 (32)',
Simon Glass72232452016-11-25 20:15:53 -07001062 str(e.exception))
1063
1064 def testPackX86Rom(self):
1065 """Test that a basic x86 ROM can be created"""
Simon Glass7057d022018-10-01 21:12:47 -06001066 self._SetupSplElf()
Simon Glass1d167762019-08-24 07:23:01 -06001067 data = self._DoReadFile('029_x86_rom.dts')
Simon Glass4e353e22019-08-24 07:23:04 -06001068 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 3) + U_BOOT_SPL_DATA +
Simon Glassac0d4952019-05-14 15:53:47 -06001069 tools.GetBytes(0, 2), data)
Simon Glass72232452016-11-25 20:15:53 -07001070
1071 def testPackX86RomMeNoDesc(self):
1072 """Test that an invalid Intel descriptor entry is detected"""
Simon Glasse88cef92020-07-09 18:39:41 -06001073 try:
Simon Glass14c596c2020-07-25 15:11:19 -06001074 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
Simon Glasse88cef92020-07-09 18:39:41 -06001075 with self.assertRaises(ValueError) as e:
Simon Glass14c596c2020-07-25 15:11:19 -06001076 self._DoTestFile('163_x86_rom_me_empty.dts')
Simon Glasse88cef92020-07-09 18:39:41 -06001077 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1078 str(e.exception))
1079 finally:
1080 self._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -07001081
1082 def testPackX86RomBadDesc(self):
1083 """Test that the Intel requires a descriptor entry"""
1084 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06001085 self._DoTestFile('030_x86_rom_me_no_desc.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001086 self.assertIn("Node '/binman/intel-me': No offset set with "
1087 "offset-unset: should another entry provide this correct "
1088 "offset?", str(e.exception))
Simon Glass72232452016-11-25 20:15:53 -07001089
1090 def testPackX86RomMe(self):
1091 """Test that an x86 ROM with an ME region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001092 data = self._DoReadFile('031_x86_rom_me.dts')
Simon Glass759af872019-07-08 13:18:54 -06001093 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
1094 if data[:0x1000] != expected_desc:
1095 self.fail('Expected descriptor binary at start of image')
Simon Glass72232452016-11-25 20:15:53 -07001096 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1097
1098 def testPackVga(self):
1099 """Test that an image with a VGA binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001100 data = self._DoReadFile('032_intel_vga.dts')
Simon Glass72232452016-11-25 20:15:53 -07001101 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1102
1103 def testPackStart16(self):
1104 """Test that an image with an x86 start16 region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001105 data = self._DoReadFile('033_x86_start16.dts')
Simon Glass72232452016-11-25 20:15:53 -07001106 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1107
Jagdish Gediya311d4842018-09-03 21:35:08 +05301108 def testPackPowerpcMpc85xxBootpgResetvec(self):
1109 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1110 created"""
Simon Glass11f2bd02019-08-24 07:23:02 -06001111 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
Jagdish Gediya311d4842018-09-03 21:35:08 +05301112 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1113
Simon Glass6ba679c2018-07-06 10:27:17 -06001114 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glass820af1d2018-07-06 10:27:16 -06001115 """Handle running a test for insertion of microcode
1116
1117 Args:
1118 dts_fname: Name of test .dts file
1119 nodtb_data: Data that we expect in the first section
Simon Glass6ba679c2018-07-06 10:27:17 -06001120 ucode_second: True if the microsecond entry is second instead of
1121 third
Simon Glass820af1d2018-07-06 10:27:16 -06001122
1123 Returns:
1124 Tuple:
1125 Contents of first region (U-Boot or SPL)
Simon Glasse8561af2018-08-01 15:22:37 -06001126 Offset and size components of microcode pointer, as inserted
Simon Glass820af1d2018-07-06 10:27:16 -06001127 in the above (two 4-byte words)
1128 """
Simon Glass3d274232017-11-12 21:52:27 -07001129 data = self._DoReadFile(dts_fname, True)
Simon Glass72232452016-11-25 20:15:53 -07001130
1131 # Now check the device tree has no microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001132 if ucode_second:
1133 ucode_content = data[len(nodtb_data):]
1134 ucode_pos = len(nodtb_data)
1135 dtb_with_ucode = ucode_content[16:]
1136 fdt_len = self.GetFdtLen(dtb_with_ucode)
1137 else:
1138 dtb_with_ucode = data[len(nodtb_data):]
1139 fdt_len = self.GetFdtLen(dtb_with_ucode)
1140 ucode_content = dtb_with_ucode[fdt_len:]
1141 ucode_pos = len(nodtb_data) + fdt_len
Simon Glass72232452016-11-25 20:15:53 -07001142 fname = tools.GetOutputFilename('test.dtb')
1143 with open(fname, 'wb') as fd:
Simon Glass820af1d2018-07-06 10:27:16 -06001144 fd.write(dtb_with_ucode)
Simon Glass22c92ca2017-05-27 07:38:29 -06001145 dtb = fdt.FdtScan(fname)
1146 ucode = dtb.GetNode('/microcode')
Simon Glass72232452016-11-25 20:15:53 -07001147 self.assertTrue(ucode)
1148 for node in ucode.subnodes:
1149 self.assertFalse(node.props.get('data'))
1150
Simon Glass72232452016-11-25 20:15:53 -07001151 # Check that the microcode appears immediately after the Fdt
1152 # This matches the concatenation of the data properties in
Simon Glasse83679d2017-11-12 21:52:26 -07001153 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glass72232452016-11-25 20:15:53 -07001154 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1155 0x78235609)
Simon Glass820af1d2018-07-06 10:27:16 -06001156 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glass72232452016-11-25 20:15:53 -07001157
1158 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001159 # expected offset and size
Simon Glass72232452016-11-25 20:15:53 -07001160 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1161 len(ucode_data))
Simon Glass6ba679c2018-07-06 10:27:17 -06001162 u_boot = data[:len(nodtb_data)]
1163 return u_boot, pos_and_size
Simon Glass3d274232017-11-12 21:52:27 -07001164
1165 def testPackUbootMicrocode(self):
1166 """Test that x86 microcode can be handled correctly
1167
1168 We expect to see the following in the image, in order:
1169 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1170 place
1171 u-boot.dtb with the microcode removed
1172 the microcode
1173 """
Simon Glass511f6582018-10-01 12:22:30 -06001174 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass3d274232017-11-12 21:52:27 -07001175 U_BOOT_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06001176 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1177 b' somewhere in here', first)
Simon Glass72232452016-11-25 20:15:53 -07001178
Simon Glassbac25c82017-05-27 07:38:26 -06001179 def _RunPackUbootSingleMicrocode(self):
Simon Glass72232452016-11-25 20:15:53 -07001180 """Test that x86 microcode can be handled correctly
1181
1182 We expect to see the following in the image, in order:
1183 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1184 place
1185 u-boot.dtb with the microcode
1186 an empty microcode region
1187 """
1188 # We need the libfdt library to run this test since only that allows
1189 # finding the offset of a property. This is required by
1190 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass511f6582018-10-01 12:22:30 -06001191 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glass72232452016-11-25 20:15:53 -07001192
1193 second = data[len(U_BOOT_NODTB_DATA):]
1194
1195 fdt_len = self.GetFdtLen(second)
1196 third = second[fdt_len:]
1197 second = second[:fdt_len]
1198
Simon Glassbac25c82017-05-27 07:38:26 -06001199 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1200 self.assertIn(ucode_data, second)
1201 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glass72232452016-11-25 20:15:53 -07001202
Simon Glassbac25c82017-05-27 07:38:26 -06001203 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001204 # expected offset and size
Simon Glassbac25c82017-05-27 07:38:26 -06001205 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1206 len(ucode_data))
1207 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glass303f62f2019-05-17 22:00:46 -06001208 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1209 b' somewhere in here', first)
Simon Glass996021e2016-11-25 20:15:54 -07001210
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001211 def testPackUbootSingleMicrocode(self):
1212 """Test that x86 microcode can be handled correctly with fdt_normal.
1213 """
Simon Glassbac25c82017-05-27 07:38:26 -06001214 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001215
Simon Glass996021e2016-11-25 20:15:54 -07001216 def testUBootImg(self):
1217 """Test that u-boot.img can be put in a file"""
Simon Glass511f6582018-10-01 12:22:30 -06001218 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glass996021e2016-11-25 20:15:54 -07001219 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001220
1221 def testNoMicrocode(self):
1222 """Test that a missing microcode region is detected"""
1223 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001224 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001225 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1226 "node found in ", str(e.exception))
1227
1228 def testMicrocodeWithoutNode(self):
1229 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1230 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001231 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001232 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1233 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1234
1235 def testMicrocodeWithoutNode2(self):
1236 """Test that a missing u-boot-ucode node is detected"""
1237 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001238 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001239 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1240 "microcode region u-boot-ucode", str(e.exception))
1241
1242 def testMicrocodeWithoutPtrInElf(self):
1243 """Test that a U-Boot binary without the microcode symbol is detected"""
1244 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001245 try:
Simon Glassfaaaa162019-08-24 07:22:55 -06001246 TestFunctional._MakeInputFile('u-boot',
1247 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001248
1249 with self.assertRaises(ValueError) as e:
Simon Glassbac25c82017-05-27 07:38:26 -06001250 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001251 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1252 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1253
1254 finally:
1255 # Put the original file back
Simon Glass4affd4b2019-08-24 07:22:54 -06001256 TestFunctional._MakeInputFile('u-boot',
1257 tools.ReadFile(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001258
1259 def testMicrocodeNotInImage(self):
1260 """Test that microcode must be placed within the image"""
1261 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001262 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001263 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1264 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glassad5a7712018-06-01 09:38:14 -06001265 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001266
1267 def testWithoutMicrocode(self):
1268 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glassfaaaa162019-08-24 07:22:55 -06001269 TestFunctional._MakeInputFile('u-boot',
1270 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass511f6582018-10-01 12:22:30 -06001271 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001272
1273 # Now check the device tree has no microcode
1274 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1275 second = data[len(U_BOOT_NODTB_DATA):]
1276
1277 fdt_len = self.GetFdtLen(second)
1278 self.assertEqual(dtb, second[:fdt_len])
1279
1280 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1281 third = data[used_len:]
Simon Glassac0d4952019-05-14 15:53:47 -06001282 self.assertEqual(tools.GetBytes(0, 0x200 - used_len), third)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001283
1284 def testUnknownPosSize(self):
1285 """Test that microcode must be placed within the image"""
1286 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001287 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glasse8561af2018-08-01 15:22:37 -06001288 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001289 "entry 'invalid-entry'", str(e.exception))
Simon Glassb4176d42016-11-25 20:15:56 -07001290
1291 def testPackFsp(self):
1292 """Test that an image with a FSP binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001293 data = self._DoReadFile('042_intel_fsp.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001294 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1295
1296 def testPackCmc(self):
Bin Mengd7bcdf52017-08-15 22:41:54 -07001297 """Test that an image with a CMC binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001298 data = self._DoReadFile('043_intel_cmc.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001299 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Mengd7bcdf52017-08-15 22:41:54 -07001300
1301 def testPackVbt(self):
1302 """Test that an image with a VBT binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001303 data = self._DoReadFile('046_intel_vbt.dts')
Bin Mengd7bcdf52017-08-15 22:41:54 -07001304 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glassac599912017-11-12 21:52:22 -07001305
Simon Glass7f94e832017-11-12 21:52:25 -07001306 def testSplBssPad(self):
1307 """Test that we can pad SPL's BSS with zeros"""
Simon Glass3d274232017-11-12 21:52:27 -07001308 # ELF file with a '__bss_size' symbol
Simon Glass7057d022018-10-01 21:12:47 -06001309 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001310 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassac0d4952019-05-14 15:53:47 -06001311 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
1312 data)
Simon Glass7f94e832017-11-12 21:52:25 -07001313
Simon Glass04cda032018-10-01 21:12:42 -06001314 def testSplBssPadMissing(self):
1315 """Test that a missing symbol is detected"""
Simon Glass7057d022018-10-01 21:12:47 -06001316 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass24ad3652017-11-13 18:54:54 -07001317 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001318 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass24ad3652017-11-13 18:54:54 -07001319 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1320 str(e.exception))
1321
Simon Glasse83679d2017-11-12 21:52:26 -07001322 def testPackStart16Spl(self):
Simon Glassed40e962018-09-14 04:57:10 -06001323 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001324 data = self._DoReadFile('048_x86_start16_spl.dts')
Simon Glasse83679d2017-11-12 21:52:26 -07001325 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1326
Simon Glass6ba679c2018-07-06 10:27:17 -06001327 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1328 """Helper function for microcode tests
Simon Glass3d274232017-11-12 21:52:27 -07001329
1330 We expect to see the following in the image, in order:
1331 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1332 correct place
1333 u-boot.dtb with the microcode removed
1334 the microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001335
1336 Args:
1337 dts: Device tree file to use for test
1338 ucode_second: True if the microsecond entry is second instead of
1339 third
Simon Glass3d274232017-11-12 21:52:27 -07001340 """
Simon Glass7057d022018-10-01 21:12:47 -06001341 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass6ba679c2018-07-06 10:27:17 -06001342 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1343 ucode_second=ucode_second)
Simon Glass303f62f2019-05-17 22:00:46 -06001344 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1345 b'ter somewhere in here', first)
Simon Glass3d274232017-11-12 21:52:27 -07001346
Simon Glass6ba679c2018-07-06 10:27:17 -06001347 def testPackUbootSplMicrocode(self):
1348 """Test that x86 microcode can be handled correctly in SPL"""
Simon Glass511f6582018-10-01 12:22:30 -06001349 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass6ba679c2018-07-06 10:27:17 -06001350
1351 def testPackUbootSplMicrocodeReorder(self):
1352 """Test that order doesn't matter for microcode entries
1353
1354 This is the same as testPackUbootSplMicrocode but when we process the
1355 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1356 entry, so we reply on binman to try later.
1357 """
Simon Glass511f6582018-10-01 12:22:30 -06001358 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass6ba679c2018-07-06 10:27:17 -06001359 ucode_second=True)
1360
Simon Glassa409c932017-11-12 21:52:28 -07001361 def testPackMrc(self):
1362 """Test that an image with an MRC binary can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001363 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassa409c932017-11-12 21:52:28 -07001364 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1365
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001366 def testSplDtb(self):
1367 """Test that an image with spl/u-boot-spl.dtb can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001368 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001369 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1370
Simon Glass0a6da312017-11-13 18:54:56 -07001371 def testSplNoDtb(self):
1372 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12001373 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001374 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass0a6da312017-11-13 18:54:56 -07001375 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1376
Simon Glass7098b7f2021-03-21 18:24:30 +13001377 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
1378 use_expanded=False):
Simon Glass31e04cb2021-03-18 20:24:56 +13001379 """Check the image contains the expected symbol values
1380
1381 Args:
1382 dts: Device tree file to use for test
1383 base_data: Data before and after 'u-boot' section
1384 u_boot_offset: Offset of 'u-boot' section in image
Simon Glass7098b7f2021-03-21 18:24:30 +13001385 entry_args: Dict of entry args to supply to binman
1386 key: arg name
1387 value: value of that arg
1388 use_expanded: True to use expanded entries where available, e.g.
1389 'u-boot-expanded' instead of 'u-boot'
Simon Glass31e04cb2021-03-18 20:24:56 +13001390 """
Simon Glass5d0c0262019-08-24 07:22:56 -06001391 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass4ca8e042017-11-13 18:55:01 -07001392 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1393 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Simon Glass31e04cb2021-03-18 20:24:56 +13001394 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
1395 addr)
Simon Glass4ca8e042017-11-13 18:55:01 -07001396
Simon Glass7057d022018-10-01 21:12:47 -06001397 self._SetupSplElf('u_boot_binman_syms')
Simon Glass7098b7f2021-03-21 18:24:30 +13001398 data = self._DoReadFileDtb(dts, entry_args=entry_args,
1399 use_expanded=use_expanded)[0]
Simon Glass31e04cb2021-03-18 20:24:56 +13001400 # The image should contain the symbols from u_boot_binman_syms.c
1401 # Note that image_pos is adjusted by the base address of the image,
1402 # which is 0x10 in our test image
1403 sym_values = struct.pack('<LQLL', 0x00,
1404 u_boot_offset + len(U_BOOT_DATA),
1405 0x10 + u_boot_offset, 0x04)
1406 expected = (sym_values + base_data[20:] +
Simon Glassac0d4952019-05-14 15:53:47 -06001407 tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
Simon Glass31e04cb2021-03-18 20:24:56 +13001408 base_data[20:])
Simon Glass4ca8e042017-11-13 18:55:01 -07001409 self.assertEqual(expected, data)
1410
Simon Glass31e04cb2021-03-18 20:24:56 +13001411 def testSymbols(self):
1412 """Test binman can assign symbols embedded in U-Boot"""
1413 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x18)
1414
1415 def testSymbolsNoDtb(self):
1416 """Test binman can assign symbols embedded in U-Boot SPL"""
Simon Glass3bbc9932021-03-21 18:24:29 +13001417 self.checkSymbols('196_symbols_nodtb.dts',
Simon Glass31e04cb2021-03-18 20:24:56 +13001418 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1419 0x38)
1420
Simon Glasse76a3e62018-06-01 09:38:11 -06001421 def testPackUnitAddress(self):
1422 """Test that we support multiple binaries with the same name"""
Simon Glass511f6582018-10-01 12:22:30 -06001423 data = self._DoReadFile('054_unit_address.dts')
Simon Glasse76a3e62018-06-01 09:38:11 -06001424 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1425
Simon Glassa91e1152018-06-01 09:38:16 -06001426 def testSections(self):
1427 """Basic test of sections"""
Simon Glass511f6582018-10-01 12:22:30 -06001428 data = self._DoReadFile('055_sections.dts')
Simon Glass303f62f2019-05-17 22:00:46 -06001429 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1430 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
1431 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
Simon Glassa91e1152018-06-01 09:38:16 -06001432 self.assertEqual(expected, data)
Simon Glassac599912017-11-12 21:52:22 -07001433
Simon Glass30732662018-06-01 09:38:20 -06001434 def testMap(self):
1435 """Tests outputting a map of the images"""
Simon Glass511f6582018-10-01 12:22:30 -06001436 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001437 self.assertEqual('''ImagePos Offset Size Name
143800000000 00000000 00000028 main-section
143900000000 00000000 00000010 section@0
144000000000 00000000 00000004 u-boot
144100000010 00000010 00000010 section@1
144200000010 00000000 00000004 u-boot
144300000020 00000020 00000004 section@2
144400000020 00000000 00000004 u-boot
Simon Glass30732662018-06-01 09:38:20 -06001445''', map_data)
1446
Simon Glass3b78d532018-06-01 09:38:21 -06001447 def testNamePrefix(self):
1448 """Tests that name prefixes are used"""
Simon Glass511f6582018-10-01 12:22:30 -06001449 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001450 self.assertEqual('''ImagePos Offset Size Name
145100000000 00000000 00000028 main-section
145200000000 00000000 00000010 section@0
145300000000 00000000 00000004 ro-u-boot
145400000010 00000010 00000010 section@1
145500000010 00000000 00000004 rw-u-boot
Simon Glass3b78d532018-06-01 09:38:21 -06001456''', map_data)
1457
Simon Glass6ba679c2018-07-06 10:27:17 -06001458 def testUnknownContents(self):
1459 """Test that obtaining the contents works as expected"""
1460 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001461 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass39dd2152019-07-08 14:25:47 -06001462 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glassc585dd42020-04-17 18:09:03 -06001463 "processing of contents: remaining ["
1464 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass6ba679c2018-07-06 10:27:17 -06001465
Simon Glass2e1169f2018-07-06 10:27:19 -06001466 def testBadChangeSize(self):
1467 """Test that trying to change the size of an entry fails"""
Simon Glasse61b6f62019-07-08 14:25:37 -06001468 try:
1469 state.SetAllowEntryExpansion(False)
1470 with self.assertRaises(ValueError) as e:
1471 self._DoReadFile('059_change_size.dts', True)
Simon Glass8c702fb2019-07-20 12:23:57 -06001472 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glasse61b6f62019-07-08 14:25:37 -06001473 str(e.exception))
1474 finally:
1475 state.SetAllowEntryExpansion(True)
Simon Glass2e1169f2018-07-06 10:27:19 -06001476
Simon Glassa87014e2018-07-06 10:27:42 -06001477 def testUpdateFdt(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001478 """Test that we can update the device tree with offset/size info"""
Simon Glass511f6582018-10-01 12:22:30 -06001479 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glassa87014e2018-07-06 10:27:42 -06001480 update_dtb=True)
Simon Glass5463a6a2018-07-17 13:25:52 -06001481 dtb = fdt.Fdt(out_dtb_fname)
1482 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06001483 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glassa87014e2018-07-06 10:27:42 -06001484 self.assertEqual({
Simon Glass9dcc8612018-08-01 15:22:42 -06001485 'image-pos': 0,
Simon Glass3a9a2b82018-07-17 13:25:28 -06001486 'offset': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001487 '_testing:offset': 32,
Simon Glass8c702fb2019-07-20 12:23:57 -06001488 '_testing:size': 2,
Simon Glass9dcc8612018-08-01 15:22:42 -06001489 '_testing:image-pos': 32,
Simon Glasse8561af2018-08-01 15:22:37 -06001490 'section@0/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001491 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001492 'section@0/u-boot:image-pos': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001493 'section@0:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001494 'section@0:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001495 'section@0:image-pos': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001496
Simon Glasse8561af2018-08-01 15:22:37 -06001497 'section@1/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001498 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001499 'section@1/u-boot:image-pos': 16,
Simon Glasse8561af2018-08-01 15:22:37 -06001500 'section@1:offset': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001501 'section@1:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001502 'section@1:image-pos': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001503 'size': 40
1504 }, props)
1505
1506 def testUpdateFdtBad(self):
1507 """Test that we detect when ProcessFdt never completes"""
1508 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001509 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glassa87014e2018-07-06 10:27:42 -06001510 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glassc585dd42020-04-17 18:09:03 -06001511 '[<binman.etype._testing.Entry__testing',
1512 str(e.exception))
Simon Glass2e1169f2018-07-06 10:27:19 -06001513
Simon Glass91710b32018-07-17 13:25:32 -06001514 def testEntryArgs(self):
1515 """Test passing arguments to entries from the command line"""
1516 entry_args = {
1517 'test-str-arg': 'test1',
1518 'test-int-arg': '456',
1519 }
Simon Glass511f6582018-10-01 12:22:30 -06001520 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001521 self.assertIn('image', control.images)
1522 entry = control.images['image'].GetEntries()['_testing']
1523 self.assertEqual('test0', entry.test_str_fdt)
1524 self.assertEqual('test1', entry.test_str_arg)
1525 self.assertEqual(123, entry.test_int_fdt)
1526 self.assertEqual(456, entry.test_int_arg)
1527
1528 def testEntryArgsMissing(self):
1529 """Test missing arguments and properties"""
1530 entry_args = {
1531 'test-int-arg': '456',
1532 }
Simon Glass511f6582018-10-01 12:22:30 -06001533 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001534 entry = control.images['image'].GetEntries()['_testing']
1535 self.assertEqual('test0', entry.test_str_fdt)
1536 self.assertEqual(None, entry.test_str_arg)
1537 self.assertEqual(None, entry.test_int_fdt)
1538 self.assertEqual(456, entry.test_int_arg)
1539
1540 def testEntryArgsRequired(self):
1541 """Test missing arguments and properties"""
1542 entry_args = {
1543 'test-int-arg': '456',
1544 }
1545 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001546 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass21db0ff2020-09-01 05:13:54 -06001547 self.assertIn("Node '/binman/_testing': "
1548 'Missing required properties/entry args: test-str-arg, '
1549 'test-int-fdt, test-int-arg',
Simon Glass91710b32018-07-17 13:25:32 -06001550 str(e.exception))
1551
1552 def testEntryArgsInvalidFormat(self):
1553 """Test that an invalid entry-argument format is detected"""
Simon Glassf46732a2019-07-08 14:25:29 -06001554 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1555 '-ano-value']
Simon Glass91710b32018-07-17 13:25:32 -06001556 with self.assertRaises(ValueError) as e:
1557 self._DoBinman(*args)
1558 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1559
1560 def testEntryArgsInvalidInteger(self):
1561 """Test that an invalid entry-argument integer is detected"""
1562 entry_args = {
1563 'test-int-arg': 'abc',
1564 }
1565 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001566 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001567 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1568 "'test-int-arg' (value 'abc') to integer",
1569 str(e.exception))
1570
1571 def testEntryArgsInvalidDatatype(self):
1572 """Test that an invalid entry-argument datatype is detected
1573
1574 This test could be written in entry_test.py except that it needs
1575 access to control.entry_args, which seems more than that module should
1576 be able to see.
1577 """
1578 entry_args = {
1579 'test-bad-datatype-arg': '12',
1580 }
1581 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001582 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass91710b32018-07-17 13:25:32 -06001583 entry_args=entry_args)
1584 self.assertIn('GetArg() internal error: Unknown data type ',
1585 str(e.exception))
1586
Simon Glass2ca52032018-07-17 13:25:33 -06001587 def testText(self):
1588 """Test for a text entry type"""
1589 entry_args = {
1590 'test-id': TEXT_DATA,
1591 'test-id2': TEXT_DATA2,
1592 'test-id3': TEXT_DATA3,
1593 }
Simon Glass511f6582018-10-01 12:22:30 -06001594 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glass2ca52032018-07-17 13:25:33 -06001595 entry_args=entry_args)
Simon Glass303f62f2019-05-17 22:00:46 -06001596 expected = (tools.ToBytes(TEXT_DATA) +
1597 tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1598 tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
Simon Glass47f6a622019-07-08 13:18:40 -06001599 b'some text' + b'more text')
Simon Glass2ca52032018-07-17 13:25:33 -06001600 self.assertEqual(expected, data)
1601
Simon Glass969616c2018-07-17 13:25:36 -06001602 def testEntryDocs(self):
1603 """Test for creation of entry documentation"""
1604 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001605 control.WriteEntryDocs(control.GetEntryModules())
Simon Glass969616c2018-07-17 13:25:36 -06001606 self.assertTrue(len(stdout.getvalue()) > 0)
1607
1608 def testEntryDocsMissing(self):
1609 """Test handling of missing entry documentation"""
1610 with self.assertRaises(ValueError) as e:
1611 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001612 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glass969616c2018-07-17 13:25:36 -06001613 self.assertIn('Documentation is missing for modules: u_boot',
1614 str(e.exception))
1615
Simon Glass704784b2018-07-17 13:25:38 -06001616 def testFmap(self):
1617 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06001618 data = self._DoReadFile('067_fmap.dts')
Simon Glass704784b2018-07-17 13:25:38 -06001619 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass303f62f2019-05-17 22:00:46 -06001620 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1621 U_BOOT_DATA + tools.GetBytes(ord('a'), 12))
Simon Glass704784b2018-07-17 13:25:38 -06001622 self.assertEqual(expected, data[:32])
Simon Glass303f62f2019-05-17 22:00:46 -06001623 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass704784b2018-07-17 13:25:38 -06001624 self.assertEqual(1, fhdr.ver_major)
1625 self.assertEqual(0, fhdr.ver_minor)
1626 self.assertEqual(0, fhdr.base)
Simon Glassb1d414c2021-04-03 11:05:10 +13001627 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 5
Simon Glass82059c22021-04-03 11:05:09 +13001628 self.assertEqual(16 + 16 + expect_size, fhdr.image_size)
Simon Glass303f62f2019-05-17 22:00:46 -06001629 self.assertEqual(b'FMAP', fhdr.name)
Simon Glassb1d414c2021-04-03 11:05:10 +13001630 self.assertEqual(5, fhdr.nareas)
Simon Glass82059c22021-04-03 11:05:09 +13001631 fiter = iter(fentries)
Simon Glass704784b2018-07-17 13:25:38 -06001632
Simon Glass82059c22021-04-03 11:05:09 +13001633 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001634 self.assertEqual(b'SECTION0', fentry.name)
1635 self.assertEqual(0, fentry.offset)
1636 self.assertEqual(16, fentry.size)
1637 self.assertEqual(0, fentry.flags)
1638
1639 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001640 self.assertEqual(b'RO_U_BOOT', fentry.name)
1641 self.assertEqual(0, fentry.offset)
1642 self.assertEqual(4, fentry.size)
1643 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001644
Simon Glass82059c22021-04-03 11:05:09 +13001645 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001646 self.assertEqual(b'SECTION1', fentry.name)
1647 self.assertEqual(16, fentry.offset)
1648 self.assertEqual(16, fentry.size)
1649 self.assertEqual(0, fentry.flags)
1650
1651 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001652 self.assertEqual(b'RW_U_BOOT', fentry.name)
1653 self.assertEqual(16, fentry.offset)
1654 self.assertEqual(4, fentry.size)
1655 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001656
Simon Glass82059c22021-04-03 11:05:09 +13001657 fentry = next(fiter)
1658 self.assertEqual(b'FMAP', fentry.name)
1659 self.assertEqual(32, fentry.offset)
1660 self.assertEqual(expect_size, fentry.size)
1661 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001662
Simon Glassdb168d42018-07-17 13:25:39 -06001663 def testBlobNamedByArg(self):
1664 """Test we can add a blob with the filename coming from an entry arg"""
1665 entry_args = {
1666 'cros-ec-rw-path': 'ecrw.bin',
1667 }
Simon Glass21db0ff2020-09-01 05:13:54 -06001668 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassdb168d42018-07-17 13:25:39 -06001669
Simon Glass53f53992018-07-17 13:25:40 -06001670 def testFill(self):
1671 """Test for an fill entry type"""
Simon Glass511f6582018-10-01 12:22:30 -06001672 data = self._DoReadFile('069_fill.dts')
Simon Glassac0d4952019-05-14 15:53:47 -06001673 expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
Simon Glass53f53992018-07-17 13:25:40 -06001674 self.assertEqual(expected, data)
1675
1676 def testFillNoSize(self):
1677 """Test for an fill entry type with no size"""
1678 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001679 self._DoReadFile('070_fill_no_size.dts')
Simon Glass53f53992018-07-17 13:25:40 -06001680 self.assertIn("'fill' entry must have a size property",
1681 str(e.exception))
1682
Simon Glassc1ae83c2018-07-17 13:25:44 -06001683 def _HandleGbbCommand(self, pipe_list):
1684 """Fake calls to the futility utility"""
1685 if pipe_list[0][0] == 'futility':
1686 fname = pipe_list[0][-1]
1687 # Append our GBB data to the file, which will happen every time the
1688 # futility command is called.
Simon Glass33486662019-05-14 15:53:42 -06001689 with open(fname, 'ab') as fd:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001690 fd.write(GBB_DATA)
1691 return command.CommandResult()
1692
1693 def testGbb(self):
1694 """Test for the Chromium OS Google Binary Block"""
1695 command.test_result = self._HandleGbbCommand
1696 entry_args = {
1697 'keydir': 'devkeys',
1698 'bmpblk': 'bmpblk.bin',
1699 }
Simon Glass511f6582018-10-01 12:22:30 -06001700 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glassc1ae83c2018-07-17 13:25:44 -06001701
1702 # Since futility
Simon Glassac0d4952019-05-14 15:53:47 -06001703 expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1704 tools.GetBytes(0, 0x2180 - 16))
Simon Glassc1ae83c2018-07-17 13:25:44 -06001705 self.assertEqual(expected, data)
1706
1707 def testGbbTooSmall(self):
1708 """Test for the Chromium OS Google Binary Block being large enough"""
1709 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001710 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001711 self.assertIn("Node '/binman/gbb': GBB is too small",
1712 str(e.exception))
1713
1714 def testGbbNoSize(self):
1715 """Test for the Chromium OS Google Binary Block having a size"""
1716 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001717 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001718 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1719 str(e.exception))
1720
Simon Glass5c350162018-07-17 13:25:47 -06001721 def _HandleVblockCommand(self, pipe_list):
Simon Glass220c6222021-01-06 21:35:17 -07001722 """Fake calls to the futility utility
1723
1724 The expected pipe is:
1725
1726 [('futility', 'vbutil_firmware', '--vblock',
1727 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1728 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1729 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1730 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1731
1732 This writes to the output file (here, 'vblock.vblock'). If
1733 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1734 of the input data (here, 'input.vblock').
1735 """
Simon Glass5c350162018-07-17 13:25:47 -06001736 if pipe_list[0][0] == 'futility':
1737 fname = pipe_list[0][3]
Simon Glass639505b2018-09-14 04:57:11 -06001738 with open(fname, 'wb') as fd:
Simon Glass220c6222021-01-06 21:35:17 -07001739 if self._hash_data:
1740 infile = pipe_list[0][11]
1741 m = hashlib.sha256()
1742 data = tools.ReadFile(infile)
1743 m.update(data)
1744 fd.write(m.digest())
1745 else:
1746 fd.write(VBLOCK_DATA)
1747
Simon Glass5c350162018-07-17 13:25:47 -06001748 return command.CommandResult()
1749
1750 def testVblock(self):
1751 """Test for the Chromium OS Verified Boot Block"""
Simon Glass220c6222021-01-06 21:35:17 -07001752 self._hash_data = False
Simon Glass5c350162018-07-17 13:25:47 -06001753 command.test_result = self._HandleVblockCommand
1754 entry_args = {
1755 'keydir': 'devkeys',
1756 }
Simon Glass511f6582018-10-01 12:22:30 -06001757 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass5c350162018-07-17 13:25:47 -06001758 entry_args=entry_args)
1759 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1760 self.assertEqual(expected, data)
1761
1762 def testVblockNoContent(self):
1763 """Test we detect a vblock which has no content to sign"""
1764 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001765 self._DoReadFile('075_vblock_no_content.dts')
Simon Glasse1915782021-03-21 18:24:31 +13001766 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
Simon Glass5c350162018-07-17 13:25:47 -06001767 'property', str(e.exception))
1768
1769 def testVblockBadPhandle(self):
1770 """Test that we detect a vblock with an invalid phandle in contents"""
1771 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001772 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001773 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1774 '1000', str(e.exception))
1775
1776 def testVblockBadEntry(self):
1777 """Test that we detect an entry that points to a non-entry"""
1778 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001779 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001780 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1781 "'other'", str(e.exception))
1782
Simon Glass220c6222021-01-06 21:35:17 -07001783 def testVblockContent(self):
1784 """Test that the vblock signs the right data"""
1785 self._hash_data = True
1786 command.test_result = self._HandleVblockCommand
1787 entry_args = {
1788 'keydir': 'devkeys',
1789 }
1790 data = self._DoReadFileDtb(
1791 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1792 entry_args=entry_args)[0]
1793 hashlen = 32 # SHA256 hash is 32 bytes
1794 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1795 hashval = data[-hashlen:]
1796 dtb = data[len(U_BOOT_DATA):-hashlen]
1797
1798 expected_data = U_BOOT_DATA + dtb
1799
1800 # The hashval should be a hash of the dtb
1801 m = hashlib.sha256()
1802 m.update(expected_data)
1803 expected_hashval = m.digest()
1804 self.assertEqual(expected_hashval, hashval)
1805
Simon Glass8425a1f2018-07-17 13:25:48 -06001806 def testTpl(self):
Simon Glass3eb5b202019-08-24 07:23:00 -06001807 """Test that an image with TPL and its device tree can be created"""
Simon Glass8425a1f2018-07-17 13:25:48 -06001808 # ELF file with a '__bss_size' symbol
Simon Glass3eb5b202019-08-24 07:23:00 -06001809 self._SetupTplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001810 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glass8425a1f2018-07-17 13:25:48 -06001811 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1812
Simon Glass24b97442018-07-17 13:25:51 -06001813 def testUsesPos(self):
1814 """Test that the 'pos' property cannot be used anymore"""
1815 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001816 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass24b97442018-07-17 13:25:51 -06001817 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1818 "'pos'", str(e.exception))
1819
Simon Glass274bf092018-09-14 04:57:08 -06001820 def testFillZero(self):
1821 """Test for an fill entry type with a size of 0"""
Simon Glass511f6582018-10-01 12:22:30 -06001822 data = self._DoReadFile('080_fill_empty.dts')
Simon Glassac0d4952019-05-14 15:53:47 -06001823 self.assertEqual(tools.GetBytes(0, 16), data)
Simon Glass274bf092018-09-14 04:57:08 -06001824
Simon Glass267de432018-09-14 04:57:09 -06001825 def testTextMissing(self):
1826 """Test for a text entry type where there is no text"""
1827 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001828 self._DoReadFileDtb('066_text.dts',)
Simon Glass267de432018-09-14 04:57:09 -06001829 self.assertIn("Node '/binman/text': No value provided for text label "
1830 "'test-id'", str(e.exception))
1831
Simon Glassed40e962018-09-14 04:57:10 -06001832 def testPackStart16Tpl(self):
1833 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001834 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glassed40e962018-09-14 04:57:10 -06001835 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1836
Simon Glass3b376c32018-09-14 04:57:12 -06001837 def testSelectImage(self):
1838 """Test that we can select which images to build"""
Simon Glassb4595d82019-04-25 21:58:34 -06001839 expected = 'Skipping images: image1'
1840
1841 # We should only get the expected message in verbose mode
Simon Glass8a50b4a2019-07-08 13:18:48 -06001842 for verbosity in (0, 2):
Simon Glassb4595d82019-04-25 21:58:34 -06001843 with test_util.capture_sys_output() as (stdout, stderr):
1844 retcode = self._DoTestFile('006_dual_image.dts',
1845 verbosity=verbosity,
1846 images=['image2'])
1847 self.assertEqual(0, retcode)
1848 if verbosity:
1849 self.assertIn(expected, stdout.getvalue())
1850 else:
1851 self.assertNotIn(expected, stdout.getvalue())
Simon Glass3b376c32018-09-14 04:57:12 -06001852
Simon Glassb4595d82019-04-25 21:58:34 -06001853 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1854 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
Simon Glassb3d6fc72019-07-20 12:24:10 -06001855 self._CleanupOutputDir()
Simon Glass3b376c32018-09-14 04:57:12 -06001856
Simon Glasse219aa42018-09-14 04:57:24 -06001857 def testUpdateFdtAll(self):
1858 """Test that all device trees are updated with offset/size info"""
Simon Glass5b4bce32019-07-08 14:25:26 -06001859 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glasse219aa42018-09-14 04:57:24 -06001860
1861 base_expected = {
1862 'section:image-pos': 0,
1863 'u-boot-tpl-dtb:size': 513,
1864 'u-boot-spl-dtb:size': 513,
1865 'u-boot-spl-dtb:offset': 493,
1866 'image-pos': 0,
1867 'section/u-boot-dtb:image-pos': 0,
1868 'u-boot-spl-dtb:image-pos': 493,
1869 'section/u-boot-dtb:size': 493,
1870 'u-boot-tpl-dtb:image-pos': 1006,
1871 'section/u-boot-dtb:offset': 0,
1872 'section:size': 493,
1873 'offset': 0,
1874 'section:offset': 0,
1875 'u-boot-tpl-dtb:offset': 1006,
1876 'size': 1519
1877 }
1878
1879 # We expect three device-tree files in the output, one after the other.
1880 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1881 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1882 # main U-Boot tree. All three should have the same postions and offset.
1883 start = 0
1884 for item in ['', 'spl', 'tpl']:
1885 dtb = fdt.Fdt.FromData(data[start:])
1886 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06001887 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
1888 ['spl', 'tpl'])
Simon Glasse219aa42018-09-14 04:57:24 -06001889 expected = dict(base_expected)
1890 if item:
1891 expected[item] = 0
1892 self.assertEqual(expected, props)
1893 start += dtb._fdt_obj.totalsize()
1894
1895 def testUpdateFdtOutput(self):
1896 """Test that output DTB files are updated"""
1897 try:
Simon Glass511f6582018-10-01 12:22:30 -06001898 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glasse219aa42018-09-14 04:57:24 -06001899 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1900
1901 # Unfortunately, compiling a source file always results in a file
1902 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass511f6582018-10-01 12:22:30 -06001903 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glasse219aa42018-09-14 04:57:24 -06001904 # binman as a file called u-boot.dtb. To fix this, copy the file
1905 # over to the expected place.
Simon Glasse219aa42018-09-14 04:57:24 -06001906 start = 0
1907 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1908 'tpl/u-boot-tpl.dtb.out']:
1909 dtb = fdt.Fdt.FromData(data[start:])
1910 size = dtb._fdt_obj.totalsize()
1911 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1912 outdata = tools.ReadFile(pathname)
1913 name = os.path.split(fname)[0]
1914
1915 if name:
1916 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1917 else:
1918 orig_indata = dtb_data
1919 self.assertNotEqual(outdata, orig_indata,
1920 "Expected output file '%s' be updated" % pathname)
1921 self.assertEqual(outdata, data[start:start + size],
1922 "Expected output file '%s' to match output image" %
1923 pathname)
1924 start += size
1925 finally:
1926 self._ResetDtbs()
1927
Simon Glass7ba33592018-09-14 04:57:26 -06001928 def _decompress(self, data):
Simon Glassccec0262019-07-08 13:18:42 -06001929 return tools.Decompress(data, 'lz4')
Simon Glass7ba33592018-09-14 04:57:26 -06001930
1931 def testCompress(self):
1932 """Test compression of blobs"""
Simon Glass1de34482019-07-08 13:18:53 -06001933 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06001934 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass7ba33592018-09-14 04:57:26 -06001935 use_real_dtb=True, update_dtb=True)
1936 dtb = fdt.Fdt(out_dtb_fname)
1937 dtb.Scan()
1938 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1939 orig = self._decompress(data)
1940 self.assertEquals(COMPRESS_DATA, orig)
Simon Glass789b34402020-10-26 17:40:15 -06001941
1942 # Do a sanity check on various fields
1943 image = control.images['image']
1944 entries = image.GetEntries()
1945 self.assertEqual(1, len(entries))
1946
1947 entry = entries['blob']
1948 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
1949 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
1950 orig = self._decompress(entry.data)
1951 self.assertEqual(orig, entry.uncomp_data)
1952
Simon Glass72eeff12020-10-26 17:40:16 -06001953 self.assertEqual(image.data, entry.data)
1954
Simon Glass7ba33592018-09-14 04:57:26 -06001955 expected = {
1956 'blob:uncomp-size': len(COMPRESS_DATA),
1957 'blob:size': len(data),
1958 'size': len(data),
1959 }
1960 self.assertEqual(expected, props)
1961
Simon Glassac6328c2018-09-14 04:57:28 -06001962 def testFiles(self):
1963 """Test bringing in multiple files"""
Simon Glass511f6582018-10-01 12:22:30 -06001964 data = self._DoReadFile('084_files.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06001965 self.assertEqual(FILES_DATA, data)
1966
1967 def testFilesCompress(self):
1968 """Test bringing in multiple files and compressing them"""
Simon Glass1de34482019-07-08 13:18:53 -06001969 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06001970 data = self._DoReadFile('085_files_compress.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06001971
1972 image = control.images['image']
1973 entries = image.GetEntries()
1974 files = entries['files']
Simon Glass39dd2152019-07-08 14:25:47 -06001975 entries = files._entries
Simon Glassac6328c2018-09-14 04:57:28 -06001976
Simon Glass303f62f2019-05-17 22:00:46 -06001977 orig = b''
Simon Glassac6328c2018-09-14 04:57:28 -06001978 for i in range(1, 3):
1979 key = '%d.dat' % i
1980 start = entries[key].image_pos
1981 len = entries[key].size
1982 chunk = data[start:start + len]
1983 orig += self._decompress(chunk)
1984
1985 self.assertEqual(FILES_DATA, orig)
1986
1987 def testFilesMissing(self):
1988 """Test missing files"""
1989 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001990 data = self._DoReadFile('086_files_none.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06001991 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1992 'no files', str(e.exception))
1993
1994 def testFilesNoPattern(self):
1995 """Test missing files"""
1996 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001997 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06001998 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1999 str(e.exception))
2000
Simon Glassfa79a812018-09-14 04:57:29 -06002001 def testExpandSize(self):
2002 """Test an expanding entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002003 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
Simon Glassfa79a812018-09-14 04:57:29 -06002004 map=True)
Simon Glass303f62f2019-05-17 22:00:46 -06002005 expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA +
2006 MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA +
2007 tools.GetBytes(ord('c'), 8) + U_BOOT_DATA +
2008 tools.GetBytes(ord('d'), 8))
Simon Glassfa79a812018-09-14 04:57:29 -06002009 self.assertEqual(expect, data)
2010 self.assertEqual('''ImagePos Offset Size Name
201100000000 00000000 00000028 main-section
201200000000 00000000 00000008 fill
201300000008 00000008 00000004 u-boot
20140000000c 0000000c 00000004 section
20150000000c 00000000 00000003 intel-mrc
201600000010 00000010 00000004 u-boot2
201700000014 00000014 0000000c section2
201800000014 00000000 00000008 fill
20190000001c 00000008 00000004 u-boot
202000000020 00000020 00000008 fill2
2021''', map_data)
2022
2023 def testExpandSizeBad(self):
2024 """Test an expanding entry which fails to provide contents"""
Simon Glasscd817d52018-09-14 04:57:36 -06002025 with test_util.capture_sys_output() as (stdout, stderr):
2026 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002027 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
Simon Glassfa79a812018-09-14 04:57:29 -06002028 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
2029 'expanding entry', str(e.exception))
2030
Simon Glassae7cf032018-09-14 04:57:31 -06002031 def testHash(self):
2032 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002033 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002034 use_real_dtb=True, update_dtb=True)
2035 dtb = fdt.Fdt(out_dtb_fname)
2036 dtb.Scan()
2037 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
2038 m = hashlib.sha256()
2039 m.update(U_BOOT_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002040 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002041
2042 def testHashNoAlgo(self):
2043 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002044 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glassae7cf032018-09-14 04:57:31 -06002045 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2046 'hash node', str(e.exception))
2047
2048 def testHashBadAlgo(self):
2049 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002050 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glassae7cf032018-09-14 04:57:31 -06002051 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
2052 str(e.exception))
2053
2054 def testHashSection(self):
2055 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002056 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002057 use_real_dtb=True, update_dtb=True)
2058 dtb = fdt.Fdt(out_dtb_fname)
2059 dtb.Scan()
2060 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2061 m = hashlib.sha256()
2062 m.update(U_BOOT_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002063 m.update(tools.GetBytes(ord('a'), 16))
2064 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002065
Simon Glass3fb4f422018-09-14 04:57:32 -06002066 def testPackUBootTplMicrocode(self):
2067 """Test that x86 microcode can be handled correctly in TPL
2068
2069 We expect to see the following in the image, in order:
2070 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2071 place
2072 u-boot-tpl.dtb with the microcode removed
2073 the microcode
2074 """
Simon Glass3eb5b202019-08-24 07:23:00 -06002075 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass511f6582018-10-01 12:22:30 -06002076 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glass3fb4f422018-09-14 04:57:32 -06002077 U_BOOT_TPL_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002078 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2079 b'ter somewhere in here', first)
Simon Glass3fb4f422018-09-14 04:57:32 -06002080
Simon Glassc64aea52018-09-14 04:57:34 -06002081 def testFmapX86(self):
2082 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002083 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassc64aea52018-09-14 04:57:34 -06002084 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass303f62f2019-05-17 22:00:46 -06002085 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002086 self.assertEqual(expected, data[:32])
2087 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2088
2089 self.assertEqual(0x100, fhdr.image_size)
2090
2091 self.assertEqual(0, fentries[0].offset)
2092 self.assertEqual(4, fentries[0].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002093 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002094
2095 self.assertEqual(4, fentries[1].offset)
2096 self.assertEqual(3, fentries[1].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002097 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002098
2099 self.assertEqual(32, fentries[2].offset)
2100 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2101 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002102 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002103
2104 def testFmapX86Section(self):
2105 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002106 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glass303f62f2019-05-17 22:00:46 -06002107 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002108 self.assertEqual(expected, data[:32])
2109 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2110
Simon Glassb1d414c2021-04-03 11:05:10 +13002111 self.assertEqual(0x180, fhdr.image_size)
2112 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
Simon Glass82059c22021-04-03 11:05:09 +13002113 fiter = iter(fentries)
Simon Glassc64aea52018-09-14 04:57:34 -06002114
Simon Glass82059c22021-04-03 11:05:09 +13002115 fentry = next(fiter)
2116 self.assertEqual(b'U_BOOT', fentry.name)
2117 self.assertEqual(0, fentry.offset)
2118 self.assertEqual(4, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002119
Simon Glass82059c22021-04-03 11:05:09 +13002120 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13002121 self.assertEqual(b'SECTION', fentry.name)
2122 self.assertEqual(4, fentry.offset)
2123 self.assertEqual(0x20 + expect_size, fentry.size)
2124
2125 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13002126 self.assertEqual(b'INTEL_MRC', fentry.name)
2127 self.assertEqual(4, fentry.offset)
2128 self.assertEqual(3, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002129
Simon Glass82059c22021-04-03 11:05:09 +13002130 fentry = next(fiter)
2131 self.assertEqual(b'FMAP', fentry.name)
2132 self.assertEqual(36, fentry.offset)
2133 self.assertEqual(expect_size, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002134
Simon Glassb1714232018-09-14 04:57:35 -06002135 def testElf(self):
2136 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002137 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002138 self._SetupTplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002139 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002140 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002141 data = self._DoReadFile('096_elf.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002142
Simon Glass0d673792019-07-08 13:18:25 -06002143 def testElfStrip(self):
Simon Glassb1714232018-09-14 04:57:35 -06002144 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002145 self._SetupSplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002146 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002147 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002148 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002149
Simon Glasscd817d52018-09-14 04:57:36 -06002150 def testPackOverlapMap(self):
2151 """Test that overlapping regions are detected"""
2152 with test_util.capture_sys_output() as (stdout, stderr):
2153 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002154 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glasscd817d52018-09-14 04:57:36 -06002155 map_fname = tools.GetOutputFilename('image.map')
2156 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2157 stdout.getvalue())
2158
2159 # We should not get an inmage, but there should be a map file
2160 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
2161 self.assertTrue(os.path.exists(map_fname))
Simon Glassb3774752019-05-17 22:00:51 -06002162 map_data = tools.ReadFile(map_fname, binary=False)
Simon Glasscd817d52018-09-14 04:57:36 -06002163 self.assertEqual('''ImagePos Offset Size Name
Simon Glassd99850b2020-10-26 17:40:24 -06002164<none> 00000000 00000008 main-section
Simon Glasscd817d52018-09-14 04:57:36 -06002165<none> 00000000 00000004 u-boot
2166<none> 00000003 00000004 u-boot-align
2167''', map_data)
2168
Simon Glass0d673792019-07-08 13:18:25 -06002169 def testPackRefCode(self):
Simon Glass41902e42018-10-01 12:22:31 -06002170 """Test that an image with an Intel Reference code binary works"""
2171 data = self._DoReadFile('100_intel_refcode.dts')
2172 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2173
Simon Glasseb023b32019-04-25 21:58:39 -06002174 def testSectionOffset(self):
2175 """Tests use of a section with an offset"""
2176 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2177 map=True)
2178 self.assertEqual('''ImagePos Offset Size Name
217900000000 00000000 00000038 main-section
218000000004 00000004 00000010 section@0
218100000004 00000000 00000004 u-boot
218200000018 00000018 00000010 section@1
218300000018 00000000 00000004 u-boot
21840000002c 0000002c 00000004 section@2
21850000002c 00000000 00000004 u-boot
2186''', map_data)
2187 self.assertEqual(data,
Simon Glassac0d4952019-05-14 15:53:47 -06002188 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2189 tools.GetBytes(0x21, 12) +
2190 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2191 tools.GetBytes(0x61, 12) +
2192 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2193 tools.GetBytes(0x26, 8))
Simon Glasseb023b32019-04-25 21:58:39 -06002194
Simon Glass1de34482019-07-08 13:18:53 -06002195 def testCbfsRaw(self):
2196 """Test base handling of a Coreboot Filesystem (CBFS)
2197
2198 The exact contents of the CBFS is verified by similar tests in
2199 cbfs_util_test.py. The tests here merely check that the files added to
2200 the CBFS can be found in the final image.
2201 """
2202 data = self._DoReadFile('102_cbfs_raw.dts')
2203 size = 0xb0
2204
2205 cbfs = cbfs_util.CbfsReader(data)
2206 self.assertEqual(size, cbfs.rom_size)
2207
2208 self.assertIn('u-boot-dtb', cbfs.files)
2209 cfile = cbfs.files['u-boot-dtb']
2210 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2211
2212 def testCbfsArch(self):
2213 """Test on non-x86 architecture"""
2214 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2215 size = 0x100
2216
2217 cbfs = cbfs_util.CbfsReader(data)
2218 self.assertEqual(size, cbfs.rom_size)
2219
2220 self.assertIn('u-boot-dtb', cbfs.files)
2221 cfile = cbfs.files['u-boot-dtb']
2222 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2223
2224 def testCbfsStage(self):
2225 """Tests handling of a Coreboot Filesystem (CBFS)"""
2226 if not elf.ELF_TOOLS:
2227 self.skipTest('Python elftools not available')
2228 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2229 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2230 size = 0xb0
2231
2232 data = self._DoReadFile('104_cbfs_stage.dts')
2233 cbfs = cbfs_util.CbfsReader(data)
2234 self.assertEqual(size, cbfs.rom_size)
2235
2236 self.assertIn('u-boot', cbfs.files)
2237 cfile = cbfs.files['u-boot']
2238 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2239
2240 def testCbfsRawCompress(self):
2241 """Test handling of compressing raw files"""
2242 self._CheckLz4()
2243 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2244 size = 0x140
2245
2246 cbfs = cbfs_util.CbfsReader(data)
2247 self.assertIn('u-boot', cbfs.files)
2248 cfile = cbfs.files['u-boot']
2249 self.assertEqual(COMPRESS_DATA, cfile.data)
2250
2251 def testCbfsBadArch(self):
2252 """Test handling of a bad architecture"""
2253 with self.assertRaises(ValueError) as e:
2254 self._DoReadFile('106_cbfs_bad_arch.dts')
2255 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2256
2257 def testCbfsNoSize(self):
2258 """Test handling of a missing size property"""
2259 with self.assertRaises(ValueError) as e:
2260 self._DoReadFile('107_cbfs_no_size.dts')
2261 self.assertIn('entry must have a size property', str(e.exception))
2262
Simon Glass3e28f4f2021-11-23 11:03:54 -07002263 def testCbfsNoContents(self):
Simon Glass1de34482019-07-08 13:18:53 -06002264 """Test handling of a CBFS entry which does not provide contentsy"""
2265 with self.assertRaises(ValueError) as e:
2266 self._DoReadFile('108_cbfs_no_contents.dts')
2267 self.assertIn('Could not complete processing of contents',
2268 str(e.exception))
2269
2270 def testCbfsBadCompress(self):
2271 """Test handling of a bad architecture"""
2272 with self.assertRaises(ValueError) as e:
2273 self._DoReadFile('109_cbfs_bad_compress.dts')
2274 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2275 str(e.exception))
2276
2277 def testCbfsNamedEntries(self):
2278 """Test handling of named entries"""
2279 data = self._DoReadFile('110_cbfs_name.dts')
2280
2281 cbfs = cbfs_util.CbfsReader(data)
2282 self.assertIn('FRED', cbfs.files)
2283 cfile1 = cbfs.files['FRED']
2284 self.assertEqual(U_BOOT_DATA, cfile1.data)
2285
2286 self.assertIn('hello', cbfs.files)
2287 cfile2 = cbfs.files['hello']
2288 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2289
Simon Glass759af872019-07-08 13:18:54 -06002290 def _SetupIfwi(self, fname):
2291 """Set up to run an IFWI test
2292
2293 Args:
2294 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2295 """
2296 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002297 self._SetupTplElf()
Simon Glass759af872019-07-08 13:18:54 -06002298
2299 # Intel Integrated Firmware Image (IFWI) file
2300 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2301 data = fd.read()
2302 TestFunctional._MakeInputFile(fname,data)
2303
2304 def _CheckIfwi(self, data):
2305 """Check that an image with an IFWI contains the correct output
2306
2307 Args:
2308 data: Conents of output file
2309 """
2310 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
2311 if data[:0x1000] != expected_desc:
2312 self.fail('Expected descriptor binary at start of image')
2313
2314 # We expect to find the TPL wil in subpart IBBP entry IBBL
2315 image_fname = tools.GetOutputFilename('image.bin')
2316 tpl_fname = tools.GetOutputFilename('tpl.out')
Simon Glass57c7a482022-01-09 20:14:01 -07002317 ifwitool = bintool.Bintool.create('ifwitool')
2318 ifwitool.extract(image_fname, 'IBBP', 'IBBL', tpl_fname)
Simon Glass759af872019-07-08 13:18:54 -06002319
2320 tpl_data = tools.ReadFile(tpl_fname)
Simon Glassf55bd692019-08-24 07:22:51 -06002321 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glass759af872019-07-08 13:18:54 -06002322
2323 def testPackX86RomIfwi(self):
2324 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2325 self._SetupIfwi('fitimage.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002326 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glass759af872019-07-08 13:18:54 -06002327 self._CheckIfwi(data)
2328
2329 def testPackX86RomIfwiNoDesc(self):
2330 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2331 self._SetupIfwi('ifwi.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002332 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glass759af872019-07-08 13:18:54 -06002333 self._CheckIfwi(data)
2334
2335 def testPackX86RomIfwiNoData(self):
2336 """Test that an x86 ROM with IFWI handles missing data"""
2337 self._SetupIfwi('ifwi.bin')
2338 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06002339 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glass759af872019-07-08 13:18:54 -06002340 self.assertIn('Could not complete processing of contents',
2341 str(e.exception))
Simon Glass91710b32018-07-17 13:25:32 -06002342
Simon Glassc2f1aed2019-07-08 13:18:56 -06002343 def testCbfsOffset(self):
2344 """Test a CBFS with files at particular offsets
2345
2346 Like all CFBS tests, this is just checking the logic that calls
2347 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2348 """
2349 data = self._DoReadFile('114_cbfs_offset.dts')
2350 size = 0x200
2351
2352 cbfs = cbfs_util.CbfsReader(data)
2353 self.assertEqual(size, cbfs.rom_size)
2354
2355 self.assertIn('u-boot', cbfs.files)
2356 cfile = cbfs.files['u-boot']
2357 self.assertEqual(U_BOOT_DATA, cfile.data)
2358 self.assertEqual(0x40, cfile.cbfs_offset)
2359
2360 self.assertIn('u-boot-dtb', cbfs.files)
2361 cfile2 = cbfs.files['u-boot-dtb']
2362 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2363 self.assertEqual(0x140, cfile2.cbfs_offset)
2364
Simon Glass0f621332019-07-08 14:25:27 -06002365 def testFdtmap(self):
2366 """Test an FDT map can be inserted in the image"""
2367 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2368 fdtmap_data = data[len(U_BOOT_DATA):]
2369 magic = fdtmap_data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002370 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass0f621332019-07-08 14:25:27 -06002371 self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
2372
2373 fdt_data = fdtmap_data[16:]
2374 dtb = fdt.Fdt.FromData(fdt_data)
2375 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002376 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass0f621332019-07-08 14:25:27 -06002377 self.assertEqual({
2378 'image-pos': 0,
2379 'offset': 0,
2380 'u-boot:offset': 0,
2381 'u-boot:size': len(U_BOOT_DATA),
2382 'u-boot:image-pos': 0,
2383 'fdtmap:image-pos': 4,
2384 'fdtmap:offset': 4,
2385 'fdtmap:size': len(fdtmap_data),
2386 'size': len(data),
2387 }, props)
2388
2389 def testFdtmapNoMatch(self):
2390 """Check handling of an FDT map when the section cannot be found"""
2391 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2392
2393 # Mangle the section name, which should cause a mismatch between the
2394 # correct FDT path and the one expected by the section
2395 image = control.images['image']
Simon Glasscec34ba2019-07-08 14:25:28 -06002396 image._node.path += '-suffix'
Simon Glass0f621332019-07-08 14:25:27 -06002397 entries = image.GetEntries()
2398 fdtmap = entries['fdtmap']
2399 with self.assertRaises(ValueError) as e:
2400 fdtmap._GetFdtmap()
2401 self.assertIn("Cannot locate node for path '/binman-suffix'",
2402 str(e.exception))
2403
Simon Glasscec34ba2019-07-08 14:25:28 -06002404 def testFdtmapHeader(self):
2405 """Test an FDT map and image header can be inserted in the image"""
2406 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2407 fdtmap_pos = len(U_BOOT_DATA)
2408 fdtmap_data = data[fdtmap_pos:]
2409 fdt_data = fdtmap_data[16:]
2410 dtb = fdt.Fdt.FromData(fdt_data)
2411 fdt_size = dtb.GetFdtObj().totalsize()
2412 hdr_data = data[-8:]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002413 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002414 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2415 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2416
2417 def testFdtmapHeaderStart(self):
2418 """Test an image header can be inserted at the image start"""
2419 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2420 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2421 hdr_data = data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002422 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002423 offset = struct.unpack('<I', hdr_data[4:])[0]
2424 self.assertEqual(fdtmap_pos, offset)
2425
2426 def testFdtmapHeaderPos(self):
2427 """Test an image header can be inserted at a chosen position"""
2428 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2429 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2430 hdr_data = data[0x80:0x88]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002431 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002432 offset = struct.unpack('<I', hdr_data[4:])[0]
2433 self.assertEqual(fdtmap_pos, offset)
2434
2435 def testHeaderMissingFdtmap(self):
2436 """Test an image header requires an fdtmap"""
2437 with self.assertRaises(ValueError) as e:
2438 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2439 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2440 str(e.exception))
2441
2442 def testHeaderNoLocation(self):
2443 """Test an image header with a no specified location is detected"""
2444 with self.assertRaises(ValueError) as e:
2445 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2446 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2447 str(e.exception))
2448
Simon Glasse61b6f62019-07-08 14:25:37 -06002449 def testEntryExpand(self):
2450 """Test expanding an entry after it is packed"""
2451 data = self._DoReadFile('121_entry_expand.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002452 self.assertEqual(b'aaa', data[:3])
2453 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2454 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002455
2456 def testEntryExpandBad(self):
2457 """Test expanding an entry after it is packed, twice"""
2458 with self.assertRaises(ValueError) as e:
2459 self._DoReadFile('122_entry_expand_twice.dts')
Simon Glass9d8ee322019-07-20 12:23:58 -06002460 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glasse61b6f62019-07-08 14:25:37 -06002461 str(e.exception))
2462
2463 def testEntryExpandSection(self):
2464 """Test expanding an entry within a section after it is packed"""
2465 data = self._DoReadFile('123_entry_expand_section.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002466 self.assertEqual(b'aaa', data[:3])
2467 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2468 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002469
Simon Glass90d29682019-07-08 14:25:38 -06002470 def testCompressDtb(self):
2471 """Test that compress of device-tree files is supported"""
2472 self._CheckLz4()
2473 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2474 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2475 comp_data = data[len(U_BOOT_DATA):]
2476 orig = self._decompress(comp_data)
2477 dtb = fdt.Fdt.FromData(orig)
2478 dtb.Scan()
2479 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2480 expected = {
2481 'u-boot:size': len(U_BOOT_DATA),
2482 'u-boot-dtb:uncomp-size': len(orig),
2483 'u-boot-dtb:size': len(comp_data),
2484 'size': len(data),
2485 }
2486 self.assertEqual(expected, props)
2487
Simon Glass151bbbf2019-07-08 14:25:41 -06002488 def testCbfsUpdateFdt(self):
2489 """Test that we can update the device tree with CBFS offset/size info"""
2490 self._CheckLz4()
2491 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2492 update_dtb=True)
2493 dtb = fdt.Fdt(out_dtb_fname)
2494 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002495 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass151bbbf2019-07-08 14:25:41 -06002496 del props['cbfs/u-boot:size']
2497 self.assertEqual({
2498 'offset': 0,
2499 'size': len(data),
2500 'image-pos': 0,
2501 'cbfs:offset': 0,
2502 'cbfs:size': len(data),
2503 'cbfs:image-pos': 0,
2504 'cbfs/u-boot:offset': 0x38,
2505 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2506 'cbfs/u-boot:image-pos': 0x38,
2507 'cbfs/u-boot-dtb:offset': 0xb8,
2508 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2509 'cbfs/u-boot-dtb:image-pos': 0xb8,
2510 }, props)
2511
Simon Glass3c9b4f22019-07-08 14:25:42 -06002512 def testCbfsBadType(self):
2513 """Test an image header with a no specified location is detected"""
2514 with self.assertRaises(ValueError) as e:
2515 self._DoReadFile('126_cbfs_bad_type.dts')
2516 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2517
Simon Glass6b156f82019-07-08 14:25:43 -06002518 def testList(self):
2519 """Test listing the files in an image"""
2520 self._CheckLz4()
2521 data = self._DoReadFile('127_list.dts')
2522 image = control.images['image']
2523 entries = image.BuildEntryList()
2524 self.assertEqual(7, len(entries))
2525
2526 ent = entries[0]
2527 self.assertEqual(0, ent.indent)
2528 self.assertEqual('main-section', ent.name)
2529 self.assertEqual('section', ent.etype)
2530 self.assertEqual(len(data), ent.size)
2531 self.assertEqual(0, ent.image_pos)
2532 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002533 self.assertEqual(0, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002534
2535 ent = entries[1]
2536 self.assertEqual(1, ent.indent)
2537 self.assertEqual('u-boot', ent.name)
2538 self.assertEqual('u-boot', ent.etype)
2539 self.assertEqual(len(U_BOOT_DATA), ent.size)
2540 self.assertEqual(0, ent.image_pos)
2541 self.assertEqual(None, ent.uncomp_size)
2542 self.assertEqual(0, ent.offset)
2543
2544 ent = entries[2]
2545 self.assertEqual(1, ent.indent)
2546 self.assertEqual('section', ent.name)
2547 self.assertEqual('section', ent.etype)
2548 section_size = ent.size
2549 self.assertEqual(0x100, ent.image_pos)
2550 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002551 self.assertEqual(0x100, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002552
2553 ent = entries[3]
2554 self.assertEqual(2, ent.indent)
2555 self.assertEqual('cbfs', ent.name)
2556 self.assertEqual('cbfs', ent.etype)
2557 self.assertEqual(0x400, ent.size)
2558 self.assertEqual(0x100, ent.image_pos)
2559 self.assertEqual(None, ent.uncomp_size)
2560 self.assertEqual(0, ent.offset)
2561
2562 ent = entries[4]
2563 self.assertEqual(3, ent.indent)
2564 self.assertEqual('u-boot', ent.name)
2565 self.assertEqual('u-boot', ent.etype)
2566 self.assertEqual(len(U_BOOT_DATA), ent.size)
2567 self.assertEqual(0x138, ent.image_pos)
2568 self.assertEqual(None, ent.uncomp_size)
2569 self.assertEqual(0x38, ent.offset)
2570
2571 ent = entries[5]
2572 self.assertEqual(3, ent.indent)
2573 self.assertEqual('u-boot-dtb', ent.name)
2574 self.assertEqual('text', ent.etype)
2575 self.assertGreater(len(COMPRESS_DATA), ent.size)
2576 self.assertEqual(0x178, ent.image_pos)
2577 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2578 self.assertEqual(0x78, ent.offset)
2579
2580 ent = entries[6]
2581 self.assertEqual(2, ent.indent)
2582 self.assertEqual('u-boot-dtb', ent.name)
2583 self.assertEqual('u-boot-dtb', ent.etype)
2584 self.assertEqual(0x500, ent.image_pos)
2585 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2586 dtb_size = ent.size
2587 # Compressing this data expands it since headers are added
2588 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2589 self.assertEqual(0x400, ent.offset)
2590
2591 self.assertEqual(len(data), 0x100 + section_size)
2592 self.assertEqual(section_size, 0x400 + dtb_size)
2593
Simon Glass8d8bf4e2019-07-08 14:25:44 -06002594 def testFindFdtmap(self):
2595 """Test locating an FDT map in an image"""
2596 self._CheckLz4()
2597 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2598 image = control.images['image']
2599 entries = image.GetEntries()
2600 entry = entries['fdtmap']
2601 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2602
2603 def testFindFdtmapMissing(self):
2604 """Test failing to locate an FDP map"""
2605 data = self._DoReadFile('005_simple.dts')
2606 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2607
Simon Glassed39a3c2019-07-08 14:25:45 -06002608 def testFindImageHeader(self):
2609 """Test locating a image header"""
2610 self._CheckLz4()
Simon Glassb8424fa2019-07-08 14:25:46 -06002611 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002612 image = control.images['image']
2613 entries = image.GetEntries()
2614 entry = entries['fdtmap']
2615 # The header should point to the FDT map
2616 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2617
2618 def testFindImageHeaderStart(self):
2619 """Test locating a image header located at the start of an image"""
Simon Glassb8424fa2019-07-08 14:25:46 -06002620 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002621 image = control.images['image']
2622 entries = image.GetEntries()
2623 entry = entries['fdtmap']
2624 # The header should point to the FDT map
2625 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2626
2627 def testFindImageHeaderMissing(self):
2628 """Test failing to locate an image header"""
2629 data = self._DoReadFile('005_simple.dts')
2630 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2631
Simon Glassb8424fa2019-07-08 14:25:46 -06002632 def testReadImage(self):
2633 """Test reading an image and accessing its FDT map"""
2634 self._CheckLz4()
2635 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2636 image_fname = tools.GetOutputFilename('image.bin')
2637 orig_image = control.images['image']
2638 image = Image.FromFile(image_fname)
2639 self.assertEqual(orig_image.GetEntries().keys(),
2640 image.GetEntries().keys())
2641
2642 orig_entry = orig_image.GetEntries()['fdtmap']
2643 entry = image.GetEntries()['fdtmap']
2644 self.assertEquals(orig_entry.offset, entry.offset)
2645 self.assertEquals(orig_entry.size, entry.size)
2646 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2647
2648 def testReadImageNoHeader(self):
2649 """Test accessing an image's FDT map without an image header"""
2650 self._CheckLz4()
2651 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
2652 image_fname = tools.GetOutputFilename('image.bin')
2653 image = Image.FromFile(image_fname)
2654 self.assertTrue(isinstance(image, Image))
Simon Glass072959a2019-07-20 12:23:50 -06002655 self.assertEqual('image', image.image_name[-5:])
Simon Glassb8424fa2019-07-08 14:25:46 -06002656
2657 def testReadImageFail(self):
2658 """Test failing to read an image image's FDT map"""
2659 self._DoReadFile('005_simple.dts')
2660 image_fname = tools.GetOutputFilename('image.bin')
2661 with self.assertRaises(ValueError) as e:
2662 image = Image.FromFile(image_fname)
2663 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glassc2f1aed2019-07-08 13:18:56 -06002664
Simon Glassb2fd11d2019-07-08 14:25:48 -06002665 def testListCmd(self):
2666 """Test listing the files in an image using an Fdtmap"""
2667 self._CheckLz4()
2668 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2669
2670 # lz4 compression size differs depending on the version
2671 image = control.images['image']
2672 entries = image.GetEntries()
2673 section_size = entries['section'].size
2674 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2675 fdtmap_offset = entries['fdtmap'].offset
2676
Simon Glassb3d6fc72019-07-20 12:24:10 -06002677 try:
2678 tmpdir, updated_fname = self._SetupImageInTmpdir()
2679 with test_util.capture_sys_output() as (stdout, stderr):
2680 self._DoBinman('ls', '-i', updated_fname)
2681 finally:
2682 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002683 lines = stdout.getvalue().splitlines()
2684 expected = [
2685'Name Image-pos Size Entry-type Offset Uncomp-size',
2686'----------------------------------------------------------------------',
2687'main-section 0 c00 section 0',
2688' u-boot 0 4 u-boot 0',
2689' section 100 %x section 100' % section_size,
2690' cbfs 100 400 cbfs 0',
2691' u-boot 138 4 u-boot 38',
Simon Glassc5fd10a2019-10-31 07:43:03 -06002692' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002693' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassc5fd10a2019-10-31 07:43:03 -06002694' fdtmap %x 3bd fdtmap %x' %
Simon Glassb2fd11d2019-07-08 14:25:48 -06002695 (fdtmap_offset, fdtmap_offset),
2696' image-header bf8 8 image-header bf8',
2697 ]
2698 self.assertEqual(expected, lines)
2699
2700 def testListCmdFail(self):
2701 """Test failing to list an image"""
2702 self._DoReadFile('005_simple.dts')
Simon Glassb3d6fc72019-07-20 12:24:10 -06002703 try:
2704 tmpdir, updated_fname = self._SetupImageInTmpdir()
2705 with self.assertRaises(ValueError) as e:
2706 self._DoBinman('ls', '-i', updated_fname)
2707 finally:
2708 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002709 self.assertIn("Cannot find FDT map in image", str(e.exception))
2710
2711 def _RunListCmd(self, paths, expected):
2712 """List out entries and check the result
2713
2714 Args:
2715 paths: List of paths to pass to the list command
2716 expected: Expected list of filenames to be returned, in order
2717 """
2718 self._CheckLz4()
2719 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2720 image_fname = tools.GetOutputFilename('image.bin')
2721 image = Image.FromFile(image_fname)
2722 lines = image.GetListEntries(paths)[1]
2723 files = [line[0].strip() for line in lines[1:]]
2724 self.assertEqual(expected, files)
2725
2726 def testListCmdSection(self):
2727 """Test listing the files in a section"""
2728 self._RunListCmd(['section'],
2729 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2730
2731 def testListCmdFile(self):
2732 """Test listing a particular file"""
2733 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2734
2735 def testListCmdWildcard(self):
2736 """Test listing a wildcarded file"""
2737 self._RunListCmd(['*boot*'],
2738 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2739
2740 def testListCmdWildcardMulti(self):
2741 """Test listing a wildcarded file"""
2742 self._RunListCmd(['*cb*', '*head*'],
2743 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2744
2745 def testListCmdEmpty(self):
2746 """Test listing a wildcarded file"""
2747 self._RunListCmd(['nothing'], [])
2748
2749 def testListCmdPath(self):
2750 """Test listing the files in a sub-entry of a section"""
2751 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2752
Simon Glass4c613bf2019-07-08 14:25:50 -06002753 def _RunExtractCmd(self, entry_name, decomp=True):
2754 """Extract an entry from an image
2755
2756 Args:
2757 entry_name: Entry name to extract
2758 decomp: True to decompress the data if compressed, False to leave
2759 it in its raw uncompressed format
2760
2761 Returns:
2762 data from entry
2763 """
2764 self._CheckLz4()
2765 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2766 image_fname = tools.GetOutputFilename('image.bin')
2767 return control.ReadEntry(image_fname, entry_name, decomp)
2768
2769 def testExtractSimple(self):
2770 """Test extracting a single file"""
2771 data = self._RunExtractCmd('u-boot')
2772 self.assertEqual(U_BOOT_DATA, data)
2773
Simon Glass980a2842019-07-08 14:25:52 -06002774 def testExtractSection(self):
2775 """Test extracting the files in a section"""
2776 data = self._RunExtractCmd('section')
2777 cbfs_data = data[:0x400]
2778 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassc5fd10a2019-10-31 07:43:03 -06002779 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass980a2842019-07-08 14:25:52 -06002780 dtb_data = data[0x400:]
2781 dtb = self._decompress(dtb_data)
2782 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2783
2784 def testExtractCompressed(self):
2785 """Test extracting compressed data"""
2786 data = self._RunExtractCmd('section/u-boot-dtb')
2787 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2788
2789 def testExtractRaw(self):
2790 """Test extracting compressed data without decompressing it"""
2791 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2792 dtb = self._decompress(data)
2793 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2794
2795 def testExtractCbfs(self):
2796 """Test extracting CBFS data"""
2797 data = self._RunExtractCmd('section/cbfs/u-boot')
2798 self.assertEqual(U_BOOT_DATA, data)
2799
2800 def testExtractCbfsCompressed(self):
2801 """Test extracting CBFS compressed data"""
2802 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2803 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2804
2805 def testExtractCbfsRaw(self):
2806 """Test extracting CBFS compressed data without decompressing it"""
2807 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Simon Glass37fdd142019-07-20 12:24:06 -06002808 dtb = tools.Decompress(data, 'lzma', with_header=False)
Simon Glass980a2842019-07-08 14:25:52 -06002809 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2810
Simon Glass4c613bf2019-07-08 14:25:50 -06002811 def testExtractBadEntry(self):
2812 """Test extracting a bad section path"""
2813 with self.assertRaises(ValueError) as e:
2814 self._RunExtractCmd('section/does-not-exist')
2815 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2816 str(e.exception))
2817
2818 def testExtractMissingFile(self):
2819 """Test extracting file that does not exist"""
2820 with self.assertRaises(IOError) as e:
2821 control.ReadEntry('missing-file', 'name')
2822
2823 def testExtractBadFile(self):
2824 """Test extracting an invalid file"""
2825 fname = os.path.join(self._indir, 'badfile')
2826 tools.WriteFile(fname, b'')
2827 with self.assertRaises(ValueError) as e:
2828 control.ReadEntry(fname, 'name')
2829
Simon Glass980a2842019-07-08 14:25:52 -06002830 def testExtractCmd(self):
2831 """Test extracting a file fron an image on the command line"""
2832 self._CheckLz4()
2833 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass980a2842019-07-08 14:25:52 -06002834 fname = os.path.join(self._indir, 'output.extact')
Simon Glassb3d6fc72019-07-20 12:24:10 -06002835 try:
2836 tmpdir, updated_fname = self._SetupImageInTmpdir()
2837 with test_util.capture_sys_output() as (stdout, stderr):
2838 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2839 '-f', fname)
2840 finally:
2841 shutil.rmtree(tmpdir)
Simon Glass980a2842019-07-08 14:25:52 -06002842 data = tools.ReadFile(fname)
2843 self.assertEqual(U_BOOT_DATA, data)
2844
2845 def testExtractOneEntry(self):
2846 """Test extracting a single entry fron an image """
2847 self._CheckLz4()
2848 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2849 image_fname = tools.GetOutputFilename('image.bin')
2850 fname = os.path.join(self._indir, 'output.extact')
2851 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
2852 data = tools.ReadFile(fname)
2853 self.assertEqual(U_BOOT_DATA, data)
2854
2855 def _CheckExtractOutput(self, decomp):
2856 """Helper to test file output with and without decompression
2857
2858 Args:
2859 decomp: True to decompress entry data, False to output it raw
2860 """
2861 def _CheckPresent(entry_path, expect_data, expect_size=None):
2862 """Check and remove expected file
2863
2864 This checks the data/size of a file and removes the file both from
2865 the outfiles set and from the output directory. Once all files are
2866 processed, both the set and directory should be empty.
2867
2868 Args:
2869 entry_path: Entry path
2870 expect_data: Data to expect in file, or None to skip check
2871 expect_size: Size of data to expect in file, or None to skip
2872 """
2873 path = os.path.join(outdir, entry_path)
2874 data = tools.ReadFile(path)
2875 os.remove(path)
2876 if expect_data:
2877 self.assertEqual(expect_data, data)
2878 elif expect_size:
2879 self.assertEqual(expect_size, len(data))
2880 outfiles.remove(path)
2881
2882 def _CheckDirPresent(name):
2883 """Remove expected directory
2884
2885 This gives an error if the directory does not exist as expected
2886
2887 Args:
2888 name: Name of directory to remove
2889 """
2890 path = os.path.join(outdir, name)
2891 os.rmdir(path)
2892
2893 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2894 image_fname = tools.GetOutputFilename('image.bin')
2895 outdir = os.path.join(self._indir, 'extract')
2896 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2897
2898 # Create a set of all file that were output (should be 9)
2899 outfiles = set()
2900 for root, dirs, files in os.walk(outdir):
2901 outfiles |= set([os.path.join(root, fname) for fname in files])
2902 self.assertEqual(9, len(outfiles))
2903 self.assertEqual(9, len(einfos))
2904
2905 image = control.images['image']
2906 entries = image.GetEntries()
2907
2908 # Check the 9 files in various ways
2909 section = entries['section']
2910 section_entries = section.GetEntries()
2911 cbfs_entries = section_entries['cbfs'].GetEntries()
2912 _CheckPresent('u-boot', U_BOOT_DATA)
2913 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
2914 dtb_len = EXTRACT_DTB_SIZE
2915 if not decomp:
2916 dtb_len = cbfs_entries['u-boot-dtb'].size
2917 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
2918 if not decomp:
2919 dtb_len = section_entries['u-boot-dtb'].size
2920 _CheckPresent('section/u-boot-dtb', None, dtb_len)
2921
2922 fdtmap = entries['fdtmap']
2923 _CheckPresent('fdtmap', fdtmap.data)
2924 hdr = entries['image-header']
2925 _CheckPresent('image-header', hdr.data)
2926
2927 _CheckPresent('section/root', section.data)
2928 cbfs = section_entries['cbfs']
2929 _CheckPresent('section/cbfs/root', cbfs.data)
2930 data = tools.ReadFile(image_fname)
2931 _CheckPresent('root', data)
2932
2933 # There should be no files left. Remove all the directories to check.
2934 # If there are any files/dirs remaining, one of these checks will fail.
2935 self.assertEqual(0, len(outfiles))
2936 _CheckDirPresent('section/cbfs')
2937 _CheckDirPresent('section')
2938 _CheckDirPresent('')
2939 self.assertFalse(os.path.exists(outdir))
2940
2941 def testExtractAllEntries(self):
2942 """Test extracting all entries"""
2943 self._CheckLz4()
2944 self._CheckExtractOutput(decomp=True)
2945
2946 def testExtractAllEntriesRaw(self):
2947 """Test extracting all entries without decompressing them"""
2948 self._CheckLz4()
2949 self._CheckExtractOutput(decomp=False)
2950
2951 def testExtractSelectedEntries(self):
2952 """Test extracting some entries"""
2953 self._CheckLz4()
2954 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2955 image_fname = tools.GetOutputFilename('image.bin')
2956 outdir = os.path.join(self._indir, 'extract')
2957 einfos = control.ExtractEntries(image_fname, None, outdir,
2958 ['*cb*', '*head*'])
2959
2960 # File output is tested by testExtractAllEntries(), so just check that
2961 # the expected entries are selected
2962 names = [einfo.name for einfo in einfos]
2963 self.assertEqual(names,
2964 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2965
2966 def testExtractNoEntryPaths(self):
2967 """Test extracting some entries"""
2968 self._CheckLz4()
2969 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2970 image_fname = tools.GetOutputFilename('image.bin')
2971 with self.assertRaises(ValueError) as e:
2972 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassa772d3f2019-07-20 12:24:14 -06002973 self.assertIn('Must specify an entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06002974 str(e.exception))
2975
2976 def testExtractTooManyEntryPaths(self):
2977 """Test extracting some entries"""
2978 self._CheckLz4()
2979 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2980 image_fname = tools.GetOutputFilename('image.bin')
2981 with self.assertRaises(ValueError) as e:
2982 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassa772d3f2019-07-20 12:24:14 -06002983 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06002984 str(e.exception))
2985
Simon Glass52d06212019-07-08 14:25:53 -06002986 def testPackAlignSection(self):
2987 """Test that sections can have alignment"""
2988 self._DoReadFile('131_pack_align_section.dts')
2989
2990 self.assertIn('image', control.images)
2991 image = control.images['image']
2992 entries = image.GetEntries()
2993 self.assertEqual(3, len(entries))
2994
2995 # First u-boot
2996 self.assertIn('u-boot', entries)
2997 entry = entries['u-boot']
2998 self.assertEqual(0, entry.offset)
2999 self.assertEqual(0, entry.image_pos)
3000 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3001 self.assertEqual(len(U_BOOT_DATA), entry.size)
3002
3003 # Section0
3004 self.assertIn('section0', entries)
3005 section0 = entries['section0']
3006 self.assertEqual(0x10, section0.offset)
3007 self.assertEqual(0x10, section0.image_pos)
3008 self.assertEqual(len(U_BOOT_DATA), section0.size)
3009
3010 # Second u-boot
3011 section_entries = section0.GetEntries()
3012 self.assertIn('u-boot', section_entries)
3013 entry = section_entries['u-boot']
3014 self.assertEqual(0, entry.offset)
3015 self.assertEqual(0x10, entry.image_pos)
3016 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3017 self.assertEqual(len(U_BOOT_DATA), entry.size)
3018
3019 # Section1
3020 self.assertIn('section1', entries)
3021 section1 = entries['section1']
3022 self.assertEqual(0x14, section1.offset)
3023 self.assertEqual(0x14, section1.image_pos)
3024 self.assertEqual(0x20, section1.size)
3025
3026 # Second u-boot
3027 section_entries = section1.GetEntries()
3028 self.assertIn('u-boot', section_entries)
3029 entry = section_entries['u-boot']
3030 self.assertEqual(0, entry.offset)
3031 self.assertEqual(0x14, entry.image_pos)
3032 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3033 self.assertEqual(len(U_BOOT_DATA), entry.size)
3034
3035 # Section2
3036 self.assertIn('section2', section_entries)
3037 section2 = section_entries['section2']
3038 self.assertEqual(0x4, section2.offset)
3039 self.assertEqual(0x18, section2.image_pos)
3040 self.assertEqual(4, section2.size)
3041
3042 # Third u-boot
3043 section_entries = section2.GetEntries()
3044 self.assertIn('u-boot', section_entries)
3045 entry = section_entries['u-boot']
3046 self.assertEqual(0, entry.offset)
3047 self.assertEqual(0x18, entry.image_pos)
3048 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3049 self.assertEqual(len(U_BOOT_DATA), entry.size)
3050
Simon Glassf8a54bc2019-07-20 12:23:56 -06003051 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3052 dts='132_replace.dts'):
Simon Glass072959a2019-07-20 12:23:50 -06003053 """Replace an entry in an image
3054
3055 This writes the entry data to update it, then opens the updated file and
3056 returns the value that it now finds there.
3057
3058 Args:
3059 entry_name: Entry name to replace
3060 data: Data to replace it with
3061 decomp: True to compress the data if needed, False if data is
3062 already compressed so should be used as is
Simon Glassf8a54bc2019-07-20 12:23:56 -06003063 allow_resize: True to allow entries to change size, False to raise
3064 an exception
Simon Glass072959a2019-07-20 12:23:50 -06003065
3066 Returns:
3067 Tuple:
3068 data from entry
3069 data from fdtmap (excluding header)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003070 Image object that was modified
Simon Glass072959a2019-07-20 12:23:50 -06003071 """
Simon Glassf8a54bc2019-07-20 12:23:56 -06003072 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass072959a2019-07-20 12:23:50 -06003073 update_dtb=True)[1]
3074
3075 self.assertIn('image', control.images)
3076 image = control.images['image']
3077 entries = image.GetEntries()
3078 orig_dtb_data = entries['u-boot-dtb'].data
3079 orig_fdtmap_data = entries['fdtmap'].data
3080
3081 image_fname = tools.GetOutputFilename('image.bin')
3082 updated_fname = tools.GetOutputFilename('image-updated.bin')
3083 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
Simon Glassf8a54bc2019-07-20 12:23:56 -06003084 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3085 allow_resize)
Simon Glass072959a2019-07-20 12:23:50 -06003086 data = control.ReadEntry(updated_fname, entry_name, decomp)
3087
Simon Glassf8a54bc2019-07-20 12:23:56 -06003088 # The DT data should not change unless resized:
3089 if not allow_resize:
3090 new_dtb_data = entries['u-boot-dtb'].data
3091 self.assertEqual(new_dtb_data, orig_dtb_data)
3092 new_fdtmap_data = entries['fdtmap'].data
3093 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass072959a2019-07-20 12:23:50 -06003094
Simon Glassf8a54bc2019-07-20 12:23:56 -06003095 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass072959a2019-07-20 12:23:50 -06003096
3097 def testReplaceSimple(self):
3098 """Test replacing a single file"""
3099 expected = b'x' * len(U_BOOT_DATA)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003100 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3101 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003102 self.assertEqual(expected, data)
3103
3104 # Test that the state looks right. There should be an FDT for the fdtmap
3105 # that we jsut read back in, and it should match what we find in the
3106 # 'control' tables. Checking for an FDT that does not exist should
3107 # return None.
3108 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glassf8a54bc2019-07-20 12:23:56 -06003109 self.assertIsNotNone(path)
Simon Glass072959a2019-07-20 12:23:50 -06003110 self.assertEqual(expected_fdtmap, fdtmap)
3111
3112 dtb = state.GetFdtForEtype('fdtmap')
3113 self.assertEqual(dtb.GetContents(), fdtmap)
3114
3115 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3116 self.assertIsNone(missing_path)
3117 self.assertIsNone(missing_fdtmap)
3118
3119 missing_dtb = state.GetFdtForEtype('missing')
3120 self.assertIsNone(missing_dtb)
3121
3122 self.assertEqual('/binman', state.fdt_path_prefix)
3123
3124 def testReplaceResizeFail(self):
3125 """Test replacing a file by something larger"""
3126 expected = U_BOOT_DATA + b'x'
3127 with self.assertRaises(ValueError) as e:
Simon Glassf8a54bc2019-07-20 12:23:56 -06003128 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3129 dts='139_replace_repack.dts')
Simon Glass072959a2019-07-20 12:23:50 -06003130 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3131 str(e.exception))
3132
3133 def testReplaceMulti(self):
3134 """Test replacing entry data where multiple images are generated"""
3135 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3136 update_dtb=True)[0]
3137 expected = b'x' * len(U_BOOT_DATA)
3138 updated_fname = tools.GetOutputFilename('image-updated.bin')
3139 tools.WriteFile(updated_fname, data)
3140 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003141 control.WriteEntry(updated_fname, entry_name, expected,
3142 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003143 data = control.ReadEntry(updated_fname, entry_name)
3144 self.assertEqual(expected, data)
3145
3146 # Check the state looks right.
3147 self.assertEqual('/binman/image', state.fdt_path_prefix)
3148
3149 # Now check we can write the first image
3150 image_fname = tools.GetOutputFilename('first-image.bin')
3151 updated_fname = tools.GetOutputFilename('first-updated.bin')
3152 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
3153 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003154 control.WriteEntry(updated_fname, entry_name, expected,
3155 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003156 data = control.ReadEntry(updated_fname, entry_name)
3157 self.assertEqual(expected, data)
3158
3159 # Check the state looks right.
3160 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass39dd2152019-07-08 14:25:47 -06003161
Simon Glassfb30e292019-07-20 12:23:51 -06003162 def testUpdateFdtAllRepack(self):
3163 """Test that all device trees are updated with offset/size info"""
3164 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3165 SECTION_SIZE = 0x300
3166 DTB_SIZE = 602
3167 FDTMAP_SIZE = 608
3168 base_expected = {
3169 'offset': 0,
3170 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3171 'image-pos': 0,
3172 'section:offset': 0,
3173 'section:size': SECTION_SIZE,
3174 'section:image-pos': 0,
3175 'section/u-boot-dtb:offset': 4,
3176 'section/u-boot-dtb:size': 636,
3177 'section/u-boot-dtb:image-pos': 4,
3178 'u-boot-spl-dtb:offset': SECTION_SIZE,
3179 'u-boot-spl-dtb:size': DTB_SIZE,
3180 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3181 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3182 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3183 'u-boot-tpl-dtb:size': DTB_SIZE,
3184 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3185 'fdtmap:size': FDTMAP_SIZE,
3186 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3187 }
3188 main_expected = {
3189 'section:orig-size': SECTION_SIZE,
3190 'section/u-boot-dtb:orig-offset': 4,
3191 }
3192
3193 # We expect three device-tree files in the output, with the first one
3194 # within a fixed-size section.
3195 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3196 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3197 # main U-Boot tree. All three should have the same positions and offset
3198 # except that the main tree should include the main_expected properties
3199 start = 4
3200 for item in ['', 'spl', 'tpl', None]:
3201 if item is None:
3202 start += 16 # Move past fdtmap header
3203 dtb = fdt.Fdt.FromData(data[start:])
3204 dtb.Scan()
3205 props = self._GetPropTree(dtb,
3206 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3207 prefix='/' if item is None else '/binman/')
3208 expected = dict(base_expected)
3209 if item:
3210 expected[item] = 0
3211 else:
3212 # Main DTB and fdtdec should include the 'orig-' properties
3213 expected.update(main_expected)
3214 # Helpful for debugging:
3215 #for prop in sorted(props):
3216 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3217 self.assertEqual(expected, props)
3218 if item == '':
3219 start = SECTION_SIZE
3220 else:
3221 start += dtb._fdt_obj.totalsize()
3222
Simon Glass11453762019-07-20 12:23:55 -06003223 def testFdtmapHeaderMiddle(self):
3224 """Test an FDT map in the middle of an image when it should be at end"""
3225 with self.assertRaises(ValueError) as e:
3226 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3227 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3228 str(e.exception))
3229
3230 def testFdtmapHeaderStartBad(self):
3231 """Test an FDT map in middle of an image when it should be at start"""
3232 with self.assertRaises(ValueError) as e:
3233 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3234 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3235 str(e.exception))
3236
3237 def testFdtmapHeaderEndBad(self):
3238 """Test an FDT map at the start of an image when it should be at end"""
3239 with self.assertRaises(ValueError) as e:
3240 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3241 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3242 str(e.exception))
3243
3244 def testFdtmapHeaderNoSize(self):
3245 """Test an image header at the end of an image with undefined size"""
3246 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3247
Simon Glassf8a54bc2019-07-20 12:23:56 -06003248 def testReplaceResize(self):
3249 """Test replacing a single file in an entry with a larger file"""
3250 expected = U_BOOT_DATA + b'x'
3251 data, _, image = self._RunReplaceCmd('u-boot', expected,
3252 dts='139_replace_repack.dts')
3253 self.assertEqual(expected, data)
3254
3255 entries = image.GetEntries()
3256 dtb_data = entries['u-boot-dtb'].data
3257 dtb = fdt.Fdt.FromData(dtb_data)
3258 dtb.Scan()
3259
3260 # The u-boot section should now be larger in the dtb
3261 node = dtb.GetNode('/binman/u-boot')
3262 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3263
3264 # Same for the fdtmap
3265 fdata = entries['fdtmap'].data
3266 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3267 fdtb.Scan()
3268 fnode = fdtb.GetNode('/u-boot')
3269 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3270
3271 def testReplaceResizeNoRepack(self):
3272 """Test replacing an entry with a larger file when not allowed"""
3273 expected = U_BOOT_DATA + b'x'
3274 with self.assertRaises(ValueError) as e:
3275 self._RunReplaceCmd('u-boot', expected)
3276 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3277 str(e.exception))
3278
Simon Glass9d8ee322019-07-20 12:23:58 -06003279 def testEntryShrink(self):
3280 """Test contracting an entry after it is packed"""
3281 try:
3282 state.SetAllowEntryContraction(True)
3283 data = self._DoReadFileDtb('140_entry_shrink.dts',
3284 update_dtb=True)[0]
3285 finally:
3286 state.SetAllowEntryContraction(False)
3287 self.assertEqual(b'a', data[:1])
3288 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3289 self.assertEqual(b'a', data[-1:])
3290
3291 def testEntryShrinkFail(self):
3292 """Test not being allowed to contract an entry after it is packed"""
3293 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3294
3295 # In this case there is a spare byte at the end of the data. The size of
3296 # the contents is only 1 byte but we still have the size before it
3297 # shrunk.
3298 self.assertEqual(b'a\0', data[:2])
3299 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3300 self.assertEqual(b'a\0', data[-2:])
3301
Simon Glass70e32982019-07-20 12:24:01 -06003302 def testDescriptorOffset(self):
3303 """Test that the Intel descriptor is always placed at at the start"""
3304 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3305 image = control.images['image']
3306 entries = image.GetEntries()
3307 desc = entries['intel-descriptor']
3308 self.assertEqual(0xff800000, desc.offset);
3309 self.assertEqual(0xff800000, desc.image_pos);
3310
Simon Glass37fdd142019-07-20 12:24:06 -06003311 def testReplaceCbfs(self):
3312 """Test replacing a single file in CBFS without changing the size"""
3313 self._CheckLz4()
3314 expected = b'x' * len(U_BOOT_DATA)
3315 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3316 updated_fname = tools.GetOutputFilename('image-updated.bin')
3317 tools.WriteFile(updated_fname, data)
3318 entry_name = 'section/cbfs/u-boot'
3319 control.WriteEntry(updated_fname, entry_name, expected,
3320 allow_resize=True)
3321 data = control.ReadEntry(updated_fname, entry_name)
3322 self.assertEqual(expected, data)
3323
3324 def testReplaceResizeCbfs(self):
3325 """Test replacing a single file in CBFS with one of a different size"""
3326 self._CheckLz4()
3327 expected = U_BOOT_DATA + b'x'
3328 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3329 updated_fname = tools.GetOutputFilename('image-updated.bin')
3330 tools.WriteFile(updated_fname, data)
3331 entry_name = 'section/cbfs/u-boot'
3332 control.WriteEntry(updated_fname, entry_name, expected,
3333 allow_resize=True)
3334 data = control.ReadEntry(updated_fname, entry_name)
3335 self.assertEqual(expected, data)
3336
Simon Glass30033c22019-07-20 12:24:15 -06003337 def _SetupForReplace(self):
3338 """Set up some files to use to replace entries
3339
3340 This generates an image, copies it to a new file, extracts all the files
3341 in it and updates some of them
3342
3343 Returns:
3344 List
3345 Image filename
3346 Output directory
3347 Expected values for updated entries, each a string
3348 """
3349 data = self._DoReadFileRealDtb('143_replace_all.dts')
3350
3351 updated_fname = tools.GetOutputFilename('image-updated.bin')
3352 tools.WriteFile(updated_fname, data)
3353
3354 outdir = os.path.join(self._indir, 'extract')
3355 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3356
3357 expected1 = b'x' + U_BOOT_DATA + b'y'
3358 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3359 tools.WriteFile(u_boot_fname1, expected1)
3360
3361 expected2 = b'a' + U_BOOT_DATA + b'b'
3362 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
3363 tools.WriteFile(u_boot_fname2, expected2)
3364
3365 expected_text = b'not the same text'
3366 text_fname = os.path.join(outdir, 'text')
3367 tools.WriteFile(text_fname, expected_text)
3368
3369 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3370 dtb = fdt.FdtScan(dtb_fname)
3371 node = dtb.GetNode('/binman/text')
3372 node.AddString('my-property', 'the value')
3373 dtb.Sync(auto_resize=True)
3374 dtb.Flush()
3375
3376 return updated_fname, outdir, expected1, expected2, expected_text
3377
3378 def _CheckReplaceMultiple(self, entry_paths):
3379 """Handle replacing the contents of multiple entries
3380
3381 Args:
3382 entry_paths: List of entry paths to replace
3383
3384 Returns:
3385 List
3386 Dict of entries in the image:
3387 key: Entry name
3388 Value: Entry object
3389 Expected values for updated entries, each a string
3390 """
3391 updated_fname, outdir, expected1, expected2, expected_text = (
3392 self._SetupForReplace())
3393 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3394
3395 image = Image.FromFile(updated_fname)
3396 image.LoadData()
3397 return image.GetEntries(), expected1, expected2, expected_text
3398
3399 def testReplaceAll(self):
3400 """Test replacing the contents of all entries"""
3401 entries, expected1, expected2, expected_text = (
3402 self._CheckReplaceMultiple([]))
3403 data = entries['u-boot'].data
3404 self.assertEqual(expected1, data)
3405
3406 data = entries['u-boot2'].data
3407 self.assertEqual(expected2, data)
3408
3409 data = entries['text'].data
3410 self.assertEqual(expected_text, data)
3411
3412 # Check that the device tree is updated
3413 data = entries['u-boot-dtb'].data
3414 dtb = fdt.Fdt.FromData(data)
3415 dtb.Scan()
3416 node = dtb.GetNode('/binman/text')
3417 self.assertEqual('the value', node.props['my-property'].value)
3418
3419 def testReplaceSome(self):
3420 """Test replacing the contents of a few entries"""
3421 entries, expected1, expected2, expected_text = (
3422 self._CheckReplaceMultiple(['u-boot2', 'text']))
3423
3424 # This one should not change
3425 data = entries['u-boot'].data
3426 self.assertEqual(U_BOOT_DATA, data)
3427
3428 data = entries['u-boot2'].data
3429 self.assertEqual(expected2, data)
3430
3431 data = entries['text'].data
3432 self.assertEqual(expected_text, data)
3433
3434 def testReplaceCmd(self):
3435 """Test replacing a file fron an image on the command line"""
3436 self._DoReadFileRealDtb('143_replace_all.dts')
3437
3438 try:
3439 tmpdir, updated_fname = self._SetupImageInTmpdir()
3440
3441 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3442 expected = b'x' * len(U_BOOT_DATA)
3443 tools.WriteFile(fname, expected)
3444
3445 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
3446 data = tools.ReadFile(updated_fname)
3447 self.assertEqual(expected, data[:len(expected)])
3448 map_fname = os.path.join(tmpdir, 'image-updated.map')
3449 self.assertFalse(os.path.exists(map_fname))
3450 finally:
3451 shutil.rmtree(tmpdir)
3452
3453 def testReplaceCmdSome(self):
3454 """Test replacing some files fron an image on the command line"""
3455 updated_fname, outdir, expected1, expected2, expected_text = (
3456 self._SetupForReplace())
3457
3458 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3459 'u-boot2', 'text')
3460
3461 tools.PrepareOutputDir(None)
3462 image = Image.FromFile(updated_fname)
3463 image.LoadData()
3464 entries = image.GetEntries()
3465
3466 # This one should not change
3467 data = entries['u-boot'].data
3468 self.assertEqual(U_BOOT_DATA, data)
3469
3470 data = entries['u-boot2'].data
3471 self.assertEqual(expected2, data)
3472
3473 data = entries['text'].data
3474 self.assertEqual(expected_text, data)
3475
3476 def testReplaceMissing(self):
3477 """Test replacing entries where the file is missing"""
3478 updated_fname, outdir, expected1, expected2, expected_text = (
3479 self._SetupForReplace())
3480
3481 # Remove one of the files, to generate a warning
3482 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3483 os.remove(u_boot_fname1)
3484
3485 with test_util.capture_sys_output() as (stdout, stderr):
3486 control.ReplaceEntries(updated_fname, None, outdir, [])
3487 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass6e02f7c2020-07-09 18:39:39 -06003488 stderr.getvalue())
Simon Glass30033c22019-07-20 12:24:15 -06003489
3490 def testReplaceCmdMap(self):
3491 """Test replacing a file fron an image on the command line"""
3492 self._DoReadFileRealDtb('143_replace_all.dts')
3493
3494 try:
3495 tmpdir, updated_fname = self._SetupImageInTmpdir()
3496
3497 fname = os.path.join(self._indir, 'update-u-boot.bin')
3498 expected = b'x' * len(U_BOOT_DATA)
3499 tools.WriteFile(fname, expected)
3500
3501 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3502 '-f', fname, '-m')
3503 map_fname = os.path.join(tmpdir, 'image-updated.map')
3504 self.assertTrue(os.path.exists(map_fname))
3505 finally:
3506 shutil.rmtree(tmpdir)
3507
3508 def testReplaceNoEntryPaths(self):
3509 """Test replacing an entry without an entry path"""
3510 self._DoReadFileRealDtb('143_replace_all.dts')
3511 image_fname = tools.GetOutputFilename('image.bin')
3512 with self.assertRaises(ValueError) as e:
3513 control.ReplaceEntries(image_fname, 'fname', None, [])
3514 self.assertIn('Must specify an entry path to read with -f',
3515 str(e.exception))
3516
3517 def testReplaceTooManyEntryPaths(self):
3518 """Test extracting some entries"""
3519 self._DoReadFileRealDtb('143_replace_all.dts')
3520 image_fname = tools.GetOutputFilename('image.bin')
3521 with self.assertRaises(ValueError) as e:
3522 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3523 self.assertIn('Must specify exactly one entry path to write with -f',
3524 str(e.exception))
3525
Simon Glass0b074d62019-08-24 07:22:48 -06003526 def testPackReset16(self):
3527 """Test that an image with an x86 reset16 region can be created"""
3528 data = self._DoReadFile('144_x86_reset16.dts')
3529 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3530
3531 def testPackReset16Spl(self):
3532 """Test that an image with an x86 reset16-spl region can be created"""
3533 data = self._DoReadFile('145_x86_reset16_spl.dts')
3534 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3535
3536 def testPackReset16Tpl(self):
3537 """Test that an image with an x86 reset16-tpl region can be created"""
3538 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3539 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3540
Simon Glass232f90c2019-08-24 07:22:50 -06003541 def testPackIntelFit(self):
3542 """Test that an image with an Intel FIT and pointer can be created"""
3543 data = self._DoReadFile('147_intel_fit.dts')
3544 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3545 fit = data[16:32];
3546 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3547 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3548
3549 image = control.images['image']
3550 entries = image.GetEntries()
3551 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3552 self.assertEqual(expected_ptr, ptr)
3553
3554 def testPackIntelFitMissing(self):
3555 """Test detection of a FIT pointer with not FIT region"""
3556 with self.assertRaises(ValueError) as e:
3557 self._DoReadFile('148_intel_fit_missing.dts')
3558 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3559 str(e.exception))
3560
Simon Glass72555fa2019-11-06 17:22:44 -07003561 def _CheckSymbolsTplSection(self, dts, expected_vals):
3562 data = self._DoReadFile(dts)
3563 sym_values = struct.pack('<LQLL', *expected_vals)
Simon Glass3eb5b202019-08-24 07:23:00 -06003564 upto1 = 4 + len(U_BOOT_SPL_DATA)
Simon Glass3f8ff012019-08-24 07:23:05 -06003565 expected1 = tools.GetBytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[20:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003566 self.assertEqual(expected1, data[:upto1])
3567
3568 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Simon Glass3f8ff012019-08-24 07:23:05 -06003569 expected2 = tools.GetBytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[20:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003570 self.assertEqual(expected2, data[upto1:upto2])
3571
Simon Glass4e353e22019-08-24 07:23:04 -06003572 upto3 = 0x34 + len(U_BOOT_DATA)
3573 expected3 = tools.GetBytes(0xff, 1) + U_BOOT_DATA
Simon Glass3eb5b202019-08-24 07:23:00 -06003574 self.assertEqual(expected3, data[upto2:upto3])
3575
Simon Glass3f8ff012019-08-24 07:23:05 -06003576 expected4 = sym_values + U_BOOT_TPL_DATA[20:]
Simon Glass72555fa2019-11-06 17:22:44 -07003577 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3578
3579 def testSymbolsTplSection(self):
3580 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3581 self._SetupSplElf('u_boot_binman_syms')
3582 self._SetupTplElf('u_boot_binman_syms')
3583 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
3584 [0x04, 0x1c, 0x10 + 0x34, 0x04])
3585
3586 def testSymbolsTplSectionX86(self):
3587 """Test binman can assign symbols in a section with end-at-4gb"""
3588 self._SetupSplElf('u_boot_binman_syms_x86')
3589 self._SetupTplElf('u_boot_binman_syms_x86')
3590 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
3591 [0xffffff04, 0xffffff1c, 0xffffff34,
3592 0x04])
Simon Glass3eb5b202019-08-24 07:23:00 -06003593
Simon Glass98c59572019-08-24 07:23:03 -06003594 def testPackX86RomIfwiSectiom(self):
3595 """Test that a section can be placed in an IFWI region"""
3596 self._SetupIfwi('fitimage.bin')
3597 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3598 self._CheckIfwi(data)
3599
Simon Glassba7985d2019-08-24 07:23:07 -06003600 def testPackFspM(self):
3601 """Test that an image with a FSP memory-init binary can be created"""
3602 data = self._DoReadFile('152_intel_fsp_m.dts')
3603 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3604
Simon Glass4d9086d2019-10-20 21:31:35 -06003605 def testPackFspS(self):
3606 """Test that an image with a FSP silicon-init binary can be created"""
3607 data = self._DoReadFile('153_intel_fsp_s.dts')
3608 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassba7985d2019-08-24 07:23:07 -06003609
Simon Glass9ea87b22019-10-20 21:31:36 -06003610 def testPackFspT(self):
3611 """Test that an image with a FSP temp-ram-init binary can be created"""
3612 data = self._DoReadFile('154_intel_fsp_t.dts')
3613 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3614
Simon Glass48f3aad2020-07-09 18:39:31 -06003615 def testMkimage(self):
3616 """Test using mkimage to build an image"""
3617 data = self._DoReadFile('156_mkimage.dts')
3618
3619 # Just check that the data appears in the file somewhere
3620 self.assertIn(U_BOOT_SPL_DATA, data)
3621
Simon Glass5e560182020-07-09 18:39:36 -06003622 def testExtblob(self):
3623 """Test an image with an external blob"""
3624 data = self._DoReadFile('157_blob_ext.dts')
3625 self.assertEqual(REFCODE_DATA, data)
3626
3627 def testExtblobMissing(self):
3628 """Test an image with a missing external blob"""
3629 with self.assertRaises(ValueError) as e:
3630 self._DoReadFile('158_blob_ext_missing.dts')
3631 self.assertIn("Filename 'missing-file' not found in input path",
3632 str(e.exception))
3633
Simon Glass5d94cc62020-07-09 18:39:38 -06003634 def testExtblobMissingOk(self):
3635 """Test an image with an missing external blob that is allowed"""
Simon Glassa003cd32020-07-09 18:39:40 -06003636 with test_util.capture_sys_output() as (stdout, stderr):
3637 self._DoTestFile('158_blob_ext_missing.dts', allow_missing=True)
3638 err = stderr.getvalue()
3639 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
3640
3641 def testExtblobMissingOkSect(self):
3642 """Test an image with an missing external blob that is allowed"""
3643 with test_util.capture_sys_output() as (stdout, stderr):
3644 self._DoTestFile('159_blob_ext_missing_sect.dts',
3645 allow_missing=True)
3646 err = stderr.getvalue()
3647 self.assertRegex(err, "Image 'main-section'.*missing.*: "
3648 "blob-ext blob-ext2")
Simon Glass5d94cc62020-07-09 18:39:38 -06003649
Simon Glasse88cef92020-07-09 18:39:41 -06003650 def testPackX86RomMeMissingDesc(self):
3651 """Test that an missing Intel descriptor entry is allowed"""
Simon Glasse88cef92020-07-09 18:39:41 -06003652 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass14c596c2020-07-25 15:11:19 -06003653 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glasse88cef92020-07-09 18:39:41 -06003654 err = stderr.getvalue()
3655 self.assertRegex(err,
3656 "Image 'main-section'.*missing.*: intel-descriptor")
3657
3658 def testPackX86RomMissingIfwi(self):
3659 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3660 self._SetupIfwi('fitimage.bin')
3661 pathname = os.path.join(self._indir, 'fitimage.bin')
3662 os.remove(pathname)
3663 with test_util.capture_sys_output() as (stdout, stderr):
3664 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3665 err = stderr.getvalue()
3666 self.assertRegex(err, "Image 'main-section'.*missing.*: intel-ifwi")
3667
Simon Glassd70829a2020-07-09 18:39:42 -06003668 def testPackOverlap(self):
3669 """Test that zero-size overlapping regions are ignored"""
3670 self._DoTestFile('160_pack_overlap_zero.dts')
3671
Simon Glass45d556d2020-07-09 18:39:45 -06003672 def testSimpleFit(self):
3673 """Test an image with a FIT inside"""
3674 data = self._DoReadFile('161_fit.dts')
3675 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3676 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3677 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3678
3679 # The data should be inside the FIT
3680 dtb = fdt.Fdt.FromData(fit_data)
3681 dtb.Scan()
3682 fnode = dtb.GetNode('/images/kernel')
3683 self.assertIn('data', fnode.props)
3684
3685 fname = os.path.join(self._indir, 'fit_data.fit')
3686 tools.WriteFile(fname, fit_data)
3687 out = tools.Run('dumpimage', '-l', fname)
3688
3689 # Check a few features to make sure the plumbing works. We don't need
3690 # to test the operation of mkimage or dumpimage here. First convert the
3691 # output into a dict where the keys are the fields printed by dumpimage
3692 # and the values are a list of values for each field
3693 lines = out.splitlines()
3694
3695 # Converts "Compression: gzip compressed" into two groups:
3696 # 'Compression' and 'gzip compressed'
3697 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3698 vals = collections.defaultdict(list)
3699 for line in lines:
3700 mat = re_line.match(line)
3701 vals[mat.group(1)].append(mat.group(2))
3702
3703 self.assertEquals('FIT description: test-desc', lines[0])
3704 self.assertIn('Created:', lines[1])
3705 self.assertIn('Image 0 (kernel)', vals)
3706 self.assertIn('Hash value', vals)
3707 data_sizes = vals.get('Data Size')
3708 self.assertIsNotNone(data_sizes)
3709 self.assertEqual(2, len(data_sizes))
3710 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
3711 self.assertEqual(len(U_BOOT_DATA), int(data_sizes[0].split()[0]))
3712 self.assertEqual(len(U_BOOT_SPL_DTB_DATA), int(data_sizes[1].split()[0]))
3713
3714 def testFitExternal(self):
Simon Glass31ee50f2020-09-01 05:13:55 -06003715 """Test an image with an FIT with external images"""
Simon Glass45d556d2020-07-09 18:39:45 -06003716 data = self._DoReadFile('162_fit_external.dts')
3717 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3718
Simon Glass7932c882022-01-09 20:13:39 -07003719 # Size of the external-data region as set up by mkimage
3720 external_data_size = len(U_BOOT_DATA) + 2
3721 expected_size = (len(U_BOOT_DATA) + 0x400 +
3722 tools.Align(external_data_size, 4) +
3723 len(U_BOOT_NODTB_DATA))
3724
Simon Glass45d556d2020-07-09 18:39:45 -06003725 # The data should be outside the FIT
3726 dtb = fdt.Fdt.FromData(fit_data)
3727 dtb.Scan()
3728 fnode = dtb.GetNode('/images/kernel')
3729 self.assertNotIn('data', fnode.props)
Simon Glass7932c882022-01-09 20:13:39 -07003730 self.assertEqual(len(U_BOOT_DATA),
3731 fdt_util.fdt32_to_cpu(fnode.props['data-size'].value))
3732 fit_pos = 0x400;
3733 self.assertEqual(
3734 fit_pos,
3735 fdt_util.fdt32_to_cpu(fnode.props['data-position'].value))
3736
3737 self.assertEquals(expected_size, len(data))
3738 actual_pos = len(U_BOOT_DATA) + fit_pos
3739 self.assertEqual(U_BOOT_DATA + b'aa',
3740 data[actual_pos:actual_pos + external_data_size])
Simon Glassfb30e292019-07-20 12:23:51 -06003741
Alper Nebi Yasak6aae2392020-08-31 12:58:18 +03003742 def testSectionIgnoreHashSignature(self):
3743 """Test that sections ignore hash, signature nodes for its data"""
3744 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
3745 expected = (U_BOOT_DATA + U_BOOT_DATA)
3746 self.assertEqual(expected, data)
3747
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03003748 def testPadInSections(self):
3749 """Test pad-before, pad-after for entries in sections"""
Simon Glassd12599d2020-10-26 17:40:09 -06003750 data, _, _, out_dtb_fname = self._DoReadFileDtb(
3751 '166_pad_in_sections.dts', update_dtb=True)
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03003752 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
3753 U_BOOT_DATA + tools.GetBytes(ord('!'), 6) +
3754 U_BOOT_DATA)
3755 self.assertEqual(expected, data)
3756
Simon Glassd12599d2020-10-26 17:40:09 -06003757 dtb = fdt.Fdt(out_dtb_fname)
3758 dtb.Scan()
3759 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
3760 expected = {
3761 'image-pos': 0,
3762 'offset': 0,
3763 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
3764
3765 'section:image-pos': 0,
3766 'section:offset': 0,
3767 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
3768
3769 'section/before:image-pos': 0,
3770 'section/before:offset': 0,
3771 'section/before:size': len(U_BOOT_DATA),
3772
3773 'section/u-boot:image-pos': 4,
3774 'section/u-boot:offset': 4,
3775 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
3776
3777 'section/after:image-pos': 26,
3778 'section/after:offset': 26,
3779 'section/after:size': len(U_BOOT_DATA),
3780 }
3781 self.assertEqual(expected, props)
3782
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03003783 def testFitImageSubentryAlignment(self):
3784 """Test relative alignability of FIT image subentries"""
3785 entry_args = {
3786 'test-id': TEXT_DATA,
3787 }
3788 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
3789 entry_args=entry_args)
3790 dtb = fdt.Fdt.FromData(data)
3791 dtb.Scan()
3792
3793 node = dtb.GetNode('/images/kernel')
3794 data = dtb.GetProps(node)["data"].bytes
3795 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
3796 expected = (tools.GetBytes(0, 0x20) + U_BOOT_SPL_DATA +
3797 tools.GetBytes(0, align_pad) + U_BOOT_DATA)
3798 self.assertEqual(expected, data)
3799
3800 node = dtb.GetNode('/images/fdt-1')
3801 data = dtb.GetProps(node)["data"].bytes
3802 expected = (U_BOOT_SPL_DTB_DATA + tools.GetBytes(0, 20) +
3803 tools.ToBytes(TEXT_DATA) + tools.GetBytes(0, 30) +
3804 U_BOOT_DTB_DATA)
3805 self.assertEqual(expected, data)
3806
3807 def testFitExtblobMissingOk(self):
3808 """Test a FIT with a missing external blob that is allowed"""
3809 with test_util.capture_sys_output() as (stdout, stderr):
3810 self._DoTestFile('168_fit_missing_blob.dts',
3811 allow_missing=True)
3812 err = stderr.getvalue()
Simon Glassa820af72020-09-06 10:39:09 -06003813 self.assertRegex(err, "Image 'main-section'.*missing.*: atf-bl31")
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03003814
Simon Glass21db0ff2020-09-01 05:13:54 -06003815 def testBlobNamedByArgMissing(self):
3816 """Test handling of a missing entry arg"""
3817 with self.assertRaises(ValueError) as e:
3818 self._DoReadFile('068_blob_named_by_arg.dts')
3819 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
3820 str(e.exception))
3821
Simon Glass559c4de2020-09-01 05:13:58 -06003822 def testPackBl31(self):
3823 """Test that an image with an ATF BL31 binary can be created"""
3824 data = self._DoReadFile('169_atf_bl31.dts')
3825 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
3826
Samuel Holland9d8cc632020-10-21 21:12:15 -05003827 def testPackScp(self):
3828 """Test that an image with an SCP binary can be created"""
3829 data = self._DoReadFile('172_scp.dts')
3830 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
3831
Simon Glassa435cd12020-09-01 05:13:59 -06003832 def testFitFdt(self):
3833 """Test an image with an FIT with multiple FDT images"""
3834 def _CheckFdt(seq, expected_data):
3835 """Check the FDT nodes
3836
3837 Args:
3838 seq: Sequence number to check (0 or 1)
3839 expected_data: Expected contents of 'data' property
3840 """
3841 name = 'fdt-%d' % seq
3842 fnode = dtb.GetNode('/images/%s' % name)
3843 self.assertIsNotNone(fnode)
3844 self.assertEqual({'description','type', 'compression', 'data'},
3845 set(fnode.props.keys()))
3846 self.assertEqual(expected_data, fnode.props['data'].bytes)
3847 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
3848 fnode.props['description'].value)
3849
3850 def _CheckConfig(seq, expected_data):
3851 """Check the configuration nodes
3852
3853 Args:
3854 seq: Sequence number to check (0 or 1)
3855 expected_data: Expected contents of 'data' property
3856 """
3857 cnode = dtb.GetNode('/configurations')
3858 self.assertIn('default', cnode.props)
Simon Glass1032acc2020-09-06 10:39:08 -06003859 self.assertEqual('config-2', cnode.props['default'].value)
Simon Glassa435cd12020-09-01 05:13:59 -06003860
3861 name = 'config-%d' % seq
3862 fnode = dtb.GetNode('/configurations/%s' % name)
3863 self.assertIsNotNone(fnode)
3864 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
3865 set(fnode.props.keys()))
3866 self.assertEqual('conf-test-fdt%d.dtb' % seq,
3867 fnode.props['description'].value)
3868 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
3869
3870 entry_args = {
3871 'of-list': 'test-fdt1 test-fdt2',
Simon Glass1032acc2020-09-06 10:39:08 -06003872 'default-dt': 'test-fdt2',
Simon Glassa435cd12020-09-01 05:13:59 -06003873 }
3874 data = self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08003875 '170_fit_fdt.dts',
Simon Glassa435cd12020-09-01 05:13:59 -06003876 entry_args=entry_args,
3877 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3878 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3879 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3880
3881 dtb = fdt.Fdt.FromData(fit_data)
3882 dtb.Scan()
3883 fnode = dtb.GetNode('/images/kernel')
3884 self.assertIn('data', fnode.props)
3885
3886 # Check all the properties in fdt-1 and fdt-2
3887 _CheckFdt(1, TEST_FDT1_DATA)
3888 _CheckFdt(2, TEST_FDT2_DATA)
3889
3890 # Check configurations
3891 _CheckConfig(1, TEST_FDT1_DATA)
3892 _CheckConfig(2, TEST_FDT2_DATA)
3893
3894 def testFitFdtMissingList(self):
3895 """Test handling of a missing 'of-list' entry arg"""
3896 with self.assertRaises(ValueError) as e:
Bin Meng16cf5662021-05-10 20:23:32 +08003897 self._DoReadFile('170_fit_fdt.dts')
Simon Glassa435cd12020-09-01 05:13:59 -06003898 self.assertIn("Generator node requires 'of-list' entry argument",
3899 str(e.exception))
3900
3901 def testFitFdtEmptyList(self):
3902 """Test handling of an empty 'of-list' entry arg"""
3903 entry_args = {
3904 'of-list': '',
3905 }
3906 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
3907
3908 def testFitFdtMissingProp(self):
3909 """Test handling of a missing 'fit,fdt-list' property"""
3910 with self.assertRaises(ValueError) as e:
3911 self._DoReadFile('171_fit_fdt_missing_prop.dts')
3912 self.assertIn("Generator node requires 'fit,fdt-list' property",
3913 str(e.exception))
Simon Glass559c4de2020-09-01 05:13:58 -06003914
Simon Glass1032acc2020-09-06 10:39:08 -06003915 def testFitFdtEmptyList(self):
3916 """Test handling of an empty 'of-list' entry arg"""
3917 entry_args = {
3918 'of-list': '',
3919 }
Bin Meng16cf5662021-05-10 20:23:32 +08003920 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
Simon Glass1032acc2020-09-06 10:39:08 -06003921
3922 def testFitFdtMissing(self):
3923 """Test handling of a missing 'default-dt' entry arg"""
3924 entry_args = {
3925 'of-list': 'test-fdt1 test-fdt2',
3926 }
3927 with self.assertRaises(ValueError) as e:
3928 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08003929 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06003930 entry_args=entry_args,
3931 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3932 self.assertIn("Generated 'default' node requires default-dt entry argument",
3933 str(e.exception))
3934
3935 def testFitFdtNotInList(self):
3936 """Test handling of a default-dt that is not in the of-list"""
3937 entry_args = {
3938 'of-list': 'test-fdt1 test-fdt2',
3939 'default-dt': 'test-fdt3',
3940 }
3941 with self.assertRaises(ValueError) as e:
3942 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08003943 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06003944 entry_args=entry_args,
3945 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3946 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
3947 str(e.exception))
3948
Simon Glassa820af72020-09-06 10:39:09 -06003949 def testFitExtblobMissingHelp(self):
3950 """Test display of help messages when an external blob is missing"""
3951 control.missing_blob_help = control._ReadMissingBlobHelp()
3952 control.missing_blob_help['wibble'] = 'Wibble test'
3953 control.missing_blob_help['another'] = 'Another test'
3954 with test_util.capture_sys_output() as (stdout, stderr):
3955 self._DoTestFile('168_fit_missing_blob.dts',
3956 allow_missing=True)
3957 err = stderr.getvalue()
3958
3959 # We can get the tag from the name, the type or the missing-msg
3960 # property. Check all three.
3961 self.assertIn('You may need to build ARM Trusted', err)
3962 self.assertIn('Wibble test', err)
3963 self.assertIn('Another test', err)
3964
Simon Glass6f1f4d42020-09-06 10:35:32 -06003965 def testMissingBlob(self):
3966 """Test handling of a blob containing a missing file"""
3967 with self.assertRaises(ValueError) as e:
3968 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
3969 self.assertIn("Filename 'missing' not found in input path",
3970 str(e.exception))
3971
Simon Glassa0729502020-09-06 10:35:33 -06003972 def testEnvironment(self):
3973 """Test adding a U-Boot environment"""
3974 data = self._DoReadFile('174_env.dts')
3975 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3976 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3977 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3978 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
3979 env)
3980
3981 def testEnvironmentNoSize(self):
3982 """Test that a missing 'size' property is detected"""
3983 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06003984 self._DoTestFile('175_env_no_size.dts')
Simon Glassa0729502020-09-06 10:35:33 -06003985 self.assertIn("'u-boot-env' entry must have a size property",
3986 str(e.exception))
3987
3988 def testEnvironmentTooSmall(self):
3989 """Test handling of an environment that does not fit"""
3990 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06003991 self._DoTestFile('176_env_too_small.dts')
Simon Glassa0729502020-09-06 10:35:33 -06003992
3993 # checksum, start byte, environment with \0 terminator, final \0
3994 need = 4 + 1 + len(ENV_DATA) + 1 + 1
3995 short = need - 0x8
3996 self.assertIn("too small to hold data (need %#x more bytes)" % short,
3997 str(e.exception))
3998
Simon Glassd1fdf752020-10-26 17:40:01 -06003999 def testSkipAtStart(self):
4000 """Test handling of skip-at-start section"""
4001 data = self._DoReadFile('177_skip_at_start.dts')
4002 self.assertEqual(U_BOOT_DATA, data)
4003
4004 image = control.images['image']
4005 entries = image.GetEntries()
4006 section = entries['section']
4007 self.assertEqual(0, section.offset)
4008 self.assertEqual(len(U_BOOT_DATA), section.size)
4009 self.assertEqual(U_BOOT_DATA, section.GetData())
4010
4011 entry = section.GetEntries()['u-boot']
4012 self.assertEqual(16, entry.offset)
4013 self.assertEqual(len(U_BOOT_DATA), entry.size)
4014 self.assertEqual(U_BOOT_DATA, entry.data)
4015
4016 def testSkipAtStartPad(self):
4017 """Test handling of skip-at-start section with padded entry"""
4018 data = self._DoReadFile('178_skip_at_start_pad.dts')
4019 before = tools.GetBytes(0, 8)
4020 after = tools.GetBytes(0, 4)
4021 all = before + U_BOOT_DATA + after
4022 self.assertEqual(all, data)
4023
4024 image = control.images['image']
4025 entries = image.GetEntries()
4026 section = entries['section']
4027 self.assertEqual(0, section.offset)
4028 self.assertEqual(len(all), section.size)
4029 self.assertEqual(all, section.GetData())
4030
4031 entry = section.GetEntries()['u-boot']
4032 self.assertEqual(16, entry.offset)
4033 self.assertEqual(len(all), entry.size)
4034 self.assertEqual(U_BOOT_DATA, entry.data)
4035
4036 def testSkipAtStartSectionPad(self):
4037 """Test handling of skip-at-start section with padding"""
4038 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
4039 before = tools.GetBytes(0, 8)
4040 after = tools.GetBytes(0, 4)
4041 all = before + U_BOOT_DATA + after
Simon Glass510ef0f2020-10-26 17:40:13 -06004042 self.assertEqual(all, data)
Simon Glassd1fdf752020-10-26 17:40:01 -06004043
4044 image = control.images['image']
4045 entries = image.GetEntries()
4046 section = entries['section']
4047 self.assertEqual(0, section.offset)
4048 self.assertEqual(len(all), section.size)
Simon Glass72eeff12020-10-26 17:40:16 -06004049 self.assertEqual(U_BOOT_DATA, section.data)
Simon Glass510ef0f2020-10-26 17:40:13 -06004050 self.assertEqual(all, section.GetPaddedData())
Simon Glassd1fdf752020-10-26 17:40:01 -06004051
4052 entry = section.GetEntries()['u-boot']
4053 self.assertEqual(16, entry.offset)
4054 self.assertEqual(len(U_BOOT_DATA), entry.size)
4055 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassa0729502020-09-06 10:35:33 -06004056
Simon Glassbb395742020-10-26 17:40:14 -06004057 def testSectionPad(self):
4058 """Testing padding with sections"""
4059 data = self._DoReadFile('180_section_pad.dts')
4060 expected = (tools.GetBytes(ord('&'), 3) +
4061 tools.GetBytes(ord('!'), 5) +
4062 U_BOOT_DATA +
4063 tools.GetBytes(ord('!'), 1) +
4064 tools.GetBytes(ord('&'), 2))
4065 self.assertEqual(expected, data)
4066
4067 def testSectionAlign(self):
4068 """Testing alignment with sections"""
4069 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4070 expected = (b'\0' + # fill section
4071 tools.GetBytes(ord('&'), 1) + # padding to section align
4072 b'\0' + # fill section
4073 tools.GetBytes(ord('!'), 3) + # padding to u-boot align
4074 U_BOOT_DATA +
4075 tools.GetBytes(ord('!'), 4) + # padding to u-boot size
4076 tools.GetBytes(ord('!'), 4)) # padding to section size
4077 self.assertEqual(expected, data)
4078
Simon Glassd92c8362020-10-26 17:40:25 -06004079 def testCompressImage(self):
4080 """Test compression of the entire image"""
4081 self._CheckLz4()
4082 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4083 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4084 dtb = fdt.Fdt(out_dtb_fname)
4085 dtb.Scan()
4086 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4087 'uncomp-size'])
4088 orig = self._decompress(data)
4089 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4090
4091 # Do a sanity check on various fields
4092 image = control.images['image']
4093 entries = image.GetEntries()
4094 self.assertEqual(2, len(entries))
4095
4096 entry = entries['blob']
4097 self.assertEqual(COMPRESS_DATA, entry.data)
4098 self.assertEqual(len(COMPRESS_DATA), entry.size)
4099
4100 entry = entries['u-boot']
4101 self.assertEqual(U_BOOT_DATA, entry.data)
4102 self.assertEqual(len(U_BOOT_DATA), entry.size)
4103
4104 self.assertEqual(len(data), image.size)
4105 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4106 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4107 orig = self._decompress(image.data)
4108 self.assertEqual(orig, image.uncomp_data)
4109
4110 expected = {
4111 'blob:offset': 0,
4112 'blob:size': len(COMPRESS_DATA),
4113 'u-boot:offset': len(COMPRESS_DATA),
4114 'u-boot:size': len(U_BOOT_DATA),
4115 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4116 'offset': 0,
4117 'image-pos': 0,
4118 'size': len(data),
4119 }
4120 self.assertEqual(expected, props)
4121
4122 def testCompressImageLess(self):
4123 """Test compression where compression reduces the image size"""
4124 self._CheckLz4()
4125 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4126 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4127 dtb = fdt.Fdt(out_dtb_fname)
4128 dtb.Scan()
4129 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4130 'uncomp-size'])
4131 orig = self._decompress(data)
4132
4133 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
4134
4135 # Do a sanity check on various fields
4136 image = control.images['image']
4137 entries = image.GetEntries()
4138 self.assertEqual(2, len(entries))
4139
4140 entry = entries['blob']
4141 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4142 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4143
4144 entry = entries['u-boot']
4145 self.assertEqual(U_BOOT_DATA, entry.data)
4146 self.assertEqual(len(U_BOOT_DATA), entry.size)
4147
4148 self.assertEqual(len(data), image.size)
4149 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4150 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4151 image.uncomp_size)
4152 orig = self._decompress(image.data)
4153 self.assertEqual(orig, image.uncomp_data)
4154
4155 expected = {
4156 'blob:offset': 0,
4157 'blob:size': len(COMPRESS_DATA_BIG),
4158 'u-boot:offset': len(COMPRESS_DATA_BIG),
4159 'u-boot:size': len(U_BOOT_DATA),
4160 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4161 'offset': 0,
4162 'image-pos': 0,
4163 'size': len(data),
4164 }
4165 self.assertEqual(expected, props)
4166
4167 def testCompressSectionSize(self):
4168 """Test compression of a section with a fixed size"""
4169 self._CheckLz4()
4170 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4171 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4172 dtb = fdt.Fdt(out_dtb_fname)
4173 dtb.Scan()
4174 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4175 'uncomp-size'])
4176 orig = self._decompress(data)
4177 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4178 expected = {
4179 'section/blob:offset': 0,
4180 'section/blob:size': len(COMPRESS_DATA),
4181 'section/u-boot:offset': len(COMPRESS_DATA),
4182 'section/u-boot:size': len(U_BOOT_DATA),
4183 'section:offset': 0,
4184 'section:image-pos': 0,
4185 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4186 'section:size': 0x30,
4187 'offset': 0,
4188 'image-pos': 0,
4189 'size': 0x30,
4190 }
4191 self.assertEqual(expected, props)
4192
4193 def testCompressSection(self):
4194 """Test compression of a section with no fixed size"""
4195 self._CheckLz4()
4196 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4197 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4198 dtb = fdt.Fdt(out_dtb_fname)
4199 dtb.Scan()
4200 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4201 'uncomp-size'])
4202 orig = self._decompress(data)
4203 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4204 expected = {
4205 'section/blob:offset': 0,
4206 'section/blob:size': len(COMPRESS_DATA),
4207 'section/u-boot:offset': len(COMPRESS_DATA),
4208 'section/u-boot:size': len(U_BOOT_DATA),
4209 'section:offset': 0,
4210 'section:image-pos': 0,
4211 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4212 'section:size': len(data),
4213 'offset': 0,
4214 'image-pos': 0,
4215 'size': len(data),
4216 }
4217 self.assertEqual(expected, props)
4218
4219 def testCompressExtra(self):
4220 """Test compression of a section with no fixed size"""
4221 self._CheckLz4()
4222 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4223 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4224 dtb = fdt.Fdt(out_dtb_fname)
4225 dtb.Scan()
4226 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4227 'uncomp-size'])
4228
4229 base = data[len(U_BOOT_DATA):]
4230 self.assertEquals(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
4231 rest = base[len(U_BOOT_DATA):]
4232
4233 # Check compressed data
4234 section1 = self._decompress(rest)
4235 expect1 = tools.Compress(COMPRESS_DATA + U_BOOT_DATA, 'lz4')
4236 self.assertEquals(expect1, rest[:len(expect1)])
4237 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, section1)
4238 rest1 = rest[len(expect1):]
4239
4240 section2 = self._decompress(rest1)
4241 expect2 = tools.Compress(COMPRESS_DATA + COMPRESS_DATA, 'lz4')
4242 self.assertEquals(expect2, rest1[:len(expect2)])
4243 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA, section2)
4244 rest2 = rest1[len(expect2):]
4245
4246 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4247 len(expect2) + len(U_BOOT_DATA))
4248 #self.assertEquals(expect_size, len(data))
4249
4250 #self.assertEquals(U_BOOT_DATA, rest2)
4251
4252 self.maxDiff = None
4253 expected = {
4254 'u-boot:offset': 0,
4255 'u-boot:image-pos': 0,
4256 'u-boot:size': len(U_BOOT_DATA),
4257
4258 'base:offset': len(U_BOOT_DATA),
4259 'base:image-pos': len(U_BOOT_DATA),
4260 'base:size': len(data) - len(U_BOOT_DATA),
4261 'base/u-boot:offset': 0,
4262 'base/u-boot:image-pos': len(U_BOOT_DATA),
4263 'base/u-boot:size': len(U_BOOT_DATA),
4264 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4265 len(expect2),
4266 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4267 len(expect2),
4268 'base/u-boot2:size': len(U_BOOT_DATA),
4269
4270 'base/section:offset': len(U_BOOT_DATA),
4271 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4272 'base/section:size': len(expect1),
4273 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4274 'base/section/blob:offset': 0,
4275 'base/section/blob:size': len(COMPRESS_DATA),
4276 'base/section/u-boot:offset': len(COMPRESS_DATA),
4277 'base/section/u-boot:size': len(U_BOOT_DATA),
4278
4279 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4280 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4281 'base/section2:size': len(expect2),
4282 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4283 'base/section2/blob:offset': 0,
4284 'base/section2/blob:size': len(COMPRESS_DATA),
4285 'base/section2/blob2:offset': len(COMPRESS_DATA),
4286 'base/section2/blob2:size': len(COMPRESS_DATA),
4287
4288 'offset': 0,
4289 'image-pos': 0,
4290 'size': len(data),
4291 }
4292 self.assertEqual(expected, props)
4293
Simon Glassecbe4732021-01-06 21:35:15 -07004294 def testSymbolsSubsection(self):
4295 """Test binman can assign symbols from a subsection"""
Simon Glass31e04cb2021-03-18 20:24:56 +13004296 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x18)
Simon Glassecbe4732021-01-06 21:35:15 -07004297
Simon Glass3fb25402021-01-06 21:35:16 -07004298 def testReadImageEntryArg(self):
4299 """Test reading an image that would need an entry arg to generate"""
4300 entry_args = {
4301 'cros-ec-rw-path': 'ecrw.bin',
4302 }
4303 data = self.data = self._DoReadFileDtb(
4304 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4305 entry_args=entry_args)
4306
4307 image_fname = tools.GetOutputFilename('image.bin')
4308 orig_image = control.images['image']
4309
4310 # This should not generate an error about the missing 'cros-ec-rw-path'
4311 # since we are reading the image from a file. Compare with
4312 # testEntryArgsRequired()
4313 image = Image.FromFile(image_fname)
4314 self.assertEqual(orig_image.GetEntries().keys(),
4315 image.GetEntries().keys())
4316
Simon Glassa2af7302021-01-06 21:35:18 -07004317 def testFilesAlign(self):
4318 """Test alignment with files"""
4319 data = self._DoReadFile('190_files_align.dts')
4320
4321 # The first string is 15 bytes so will align to 16
4322 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4323 self.assertEqual(expect, data)
4324
Simon Glassdb84b562021-01-06 21:35:19 -07004325 def testReadImageSkip(self):
4326 """Test reading an image and accessing its FDT map"""
4327 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
4328 image_fname = tools.GetOutputFilename('image.bin')
4329 orig_image = control.images['image']
4330 image = Image.FromFile(image_fname)
4331 self.assertEqual(orig_image.GetEntries().keys(),
4332 image.GetEntries().keys())
4333
4334 orig_entry = orig_image.GetEntries()['fdtmap']
4335 entry = image.GetEntries()['fdtmap']
4336 self.assertEqual(orig_entry.offset, entry.offset)
4337 self.assertEqual(orig_entry.size, entry.size)
4338 self.assertEqual(16, entry.image_pos)
4339
4340 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4341
4342 self.assertEquals(U_BOOT_DATA, u_boot.ReadData())
4343
Simon Glassc98de972021-03-18 20:24:57 +13004344 def testTplNoDtb(self):
4345 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12004346 self._SetupTplElf()
Simon Glassc98de972021-03-18 20:24:57 +13004347 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4348 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4349 data[:len(U_BOOT_TPL_NODTB_DATA)])
4350
Simon Glass63f41d42021-03-18 20:24:58 +13004351 def testTplBssPad(self):
4352 """Test that we can pad TPL's BSS with zeros"""
4353 # ELF file with a '__bss_size' symbol
4354 self._SetupTplElf()
4355 data = self._DoReadFile('193_tpl_bss_pad.dts')
4356 self.assertEqual(U_BOOT_TPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
4357 data)
4358
4359 def testTplBssPadMissing(self):
4360 """Test that a missing symbol is detected"""
4361 self._SetupTplElf('u_boot_ucode_ptr')
4362 with self.assertRaises(ValueError) as e:
4363 self._DoReadFile('193_tpl_bss_pad.dts')
4364 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4365 str(e.exception))
4366
Simon Glass718b5292021-03-18 20:25:07 +13004367 def checkDtbSizes(self, data, pad_len, start):
4368 """Check the size arguments in a dtb embedded in an image
4369
4370 Args:
4371 data: The image data
4372 pad_len: Length of the pad section in the image, in bytes
4373 start: Start offset of the devicetree to examine, within the image
4374
4375 Returns:
4376 Size of the devicetree in bytes
4377 """
4378 dtb_data = data[start:]
4379 dtb = fdt.Fdt.FromData(dtb_data)
4380 fdt_size = dtb.GetFdtObj().totalsize()
4381 dtb.Scan()
4382 props = self._GetPropTree(dtb, 'size')
4383 self.assertEqual({
4384 'size': len(data),
4385 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4386 'u-boot-spl/u-boot-spl-dtb:size': 801,
4387 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4388 'u-boot-spl:size': 860,
4389 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4390 'u-boot/u-boot-dtb:size': 781,
4391 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4392 'u-boot:size': 827,
4393 }, props)
4394 return fdt_size
4395
4396 def testExpanded(self):
4397 """Test that an expanded entry type is selected when needed"""
4398 self._SetupSplElf()
4399 self._SetupTplElf()
4400
4401 # SPL has a devicetree, TPL does not
4402 entry_args = {
4403 'spl-dtb': '1',
4404 'spl-bss-pad': 'y',
4405 'tpl-dtb': '',
4406 }
4407 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4408 entry_args=entry_args)
4409 image = control.images['image']
4410 entries = image.GetEntries()
4411 self.assertEqual(3, len(entries))
4412
4413 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4414 self.assertIn('u-boot', entries)
4415 entry = entries['u-boot']
4416 self.assertEqual('u-boot-expanded', entry.etype)
4417 subent = entry.GetEntries()
4418 self.assertEqual(2, len(subent))
4419 self.assertIn('u-boot-nodtb', subent)
4420 self.assertIn('u-boot-dtb', subent)
4421
4422 # Second, u-boot-spl, which should be expanded into three parts
4423 self.assertIn('u-boot-spl', entries)
4424 entry = entries['u-boot-spl']
4425 self.assertEqual('u-boot-spl-expanded', entry.etype)
4426 subent = entry.GetEntries()
4427 self.assertEqual(3, len(subent))
4428 self.assertIn('u-boot-spl-nodtb', subent)
4429 self.assertIn('u-boot-spl-bss-pad', subent)
4430 self.assertIn('u-boot-spl-dtb', subent)
4431
4432 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4433 # devicetree
4434 self.assertIn('u-boot-tpl', entries)
4435 entry = entries['u-boot-tpl']
4436 self.assertEqual('u-boot-tpl', entry.etype)
4437 self.assertEqual(None, entry.GetEntries())
4438
4439 def testExpandedTpl(self):
4440 """Test that an expanded entry type is selected for TPL when needed"""
4441 self._SetupTplElf()
4442
4443 entry_args = {
4444 'tpl-bss-pad': 'y',
4445 'tpl-dtb': 'y',
4446 }
4447 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4448 entry_args=entry_args)
4449 image = control.images['image']
4450 entries = image.GetEntries()
4451 self.assertEqual(1, len(entries))
4452
4453 # We only have u-boot-tpl, which be expanded
4454 self.assertIn('u-boot-tpl', entries)
4455 entry = entries['u-boot-tpl']
4456 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4457 subent = entry.GetEntries()
4458 self.assertEqual(3, len(subent))
4459 self.assertIn('u-boot-tpl-nodtb', subent)
4460 self.assertIn('u-boot-tpl-bss-pad', subent)
4461 self.assertIn('u-boot-tpl-dtb', subent)
4462
4463 def testExpandedNoPad(self):
4464 """Test an expanded entry without BSS pad enabled"""
4465 self._SetupSplElf()
4466 self._SetupTplElf()
4467
4468 # SPL has a devicetree, TPL does not
4469 entry_args = {
4470 'spl-dtb': 'something',
4471 'spl-bss-pad': 'n',
4472 'tpl-dtb': '',
4473 }
4474 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4475 entry_args=entry_args)
4476 image = control.images['image']
4477 entries = image.GetEntries()
4478
4479 # Just check u-boot-spl, which should be expanded into two parts
4480 self.assertIn('u-boot-spl', entries)
4481 entry = entries['u-boot-spl']
4482 self.assertEqual('u-boot-spl-expanded', entry.etype)
4483 subent = entry.GetEntries()
4484 self.assertEqual(2, len(subent))
4485 self.assertIn('u-boot-spl-nodtb', subent)
4486 self.assertIn('u-boot-spl-dtb', subent)
4487
4488 def testExpandedTplNoPad(self):
4489 """Test that an expanded entry type with padding disabled in TPL"""
4490 self._SetupTplElf()
4491
4492 entry_args = {
4493 'tpl-bss-pad': '',
4494 'tpl-dtb': 'y',
4495 }
4496 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4497 entry_args=entry_args)
4498 image = control.images['image']
4499 entries = image.GetEntries()
4500 self.assertEqual(1, len(entries))
4501
4502 # We only have u-boot-tpl, which be expanded
4503 self.assertIn('u-boot-tpl', entries)
4504 entry = entries['u-boot-tpl']
4505 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4506 subent = entry.GetEntries()
4507 self.assertEqual(2, len(subent))
4508 self.assertIn('u-boot-tpl-nodtb', subent)
4509 self.assertIn('u-boot-tpl-dtb', subent)
4510
4511 def testFdtInclude(self):
4512 """Test that an Fdt is update within all binaries"""
4513 self._SetupSplElf()
4514 self._SetupTplElf()
4515
4516 # SPL has a devicetree, TPL does not
4517 self.maxDiff = None
4518 entry_args = {
4519 'spl-dtb': '1',
4520 'spl-bss-pad': 'y',
4521 'tpl-dtb': '',
4522 }
4523 # Build the image. It includes two separate devicetree binaries, each
4524 # with their own contents, but all contain the binman definition.
4525 data = self._DoReadFileDtb(
4526 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4527 update_dtb=True, entry_args=entry_args)[0]
4528 pad_len = 10
4529
4530 # Check the U-Boot dtb
4531 start = len(U_BOOT_NODTB_DATA)
4532 fdt_size = self.checkDtbSizes(data, pad_len, start)
4533
4534 # Now check SPL
4535 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4536 fdt_size = self.checkDtbSizes(data, pad_len, start)
4537
4538 # TPL has no devicetree
4539 start += fdt_size + len(U_BOOT_TPL_DATA)
4540 self.assertEqual(len(data), start)
Simon Glassbb395742020-10-26 17:40:14 -06004541
Simon Glass7098b7f2021-03-21 18:24:30 +13004542 def testSymbolsExpanded(self):
4543 """Test binman can assign symbols in expanded entries"""
4544 entry_args = {
4545 'spl-dtb': '1',
4546 }
4547 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4548 U_BOOT_SPL_DTB_DATA, 0x38,
4549 entry_args=entry_args, use_expanded=True)
4550
Simon Glasse1915782021-03-21 18:24:31 +13004551 def testCollection(self):
4552 """Test a collection"""
4553 data = self._DoReadFile('198_collection.dts')
4554 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
4555 tools.GetBytes(0xff, 2) + U_BOOT_NODTB_DATA +
4556 tools.GetBytes(0xfe, 3) + U_BOOT_DTB_DATA,
4557 data)
4558
Simon Glass27a7f772021-03-21 18:24:32 +13004559 def testCollectionSection(self):
4560 """Test a collection where a section must be built first"""
4561 # Sections never have their contents when GetData() is called, but when
Simon Glass7e3f89f2021-11-23 11:03:47 -07004562 # BuildSectionData() is called with required=True, a section will force
Simon Glass27a7f772021-03-21 18:24:32 +13004563 # building the contents, producing an error is anything is still
4564 # missing.
4565 data = self._DoReadFile('199_collection_section.dts')
4566 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
4567 self.assertEqual(section + U_BOOT_DATA + tools.GetBytes(0xff, 2) +
4568 section + tools.GetBytes(0xfe, 3) + U_BOOT_DATA,
4569 data)
4570
Simon Glassf427c5f2021-03-21 18:24:33 +13004571 def testAlignDefault(self):
4572 """Test that default alignment works on sections"""
4573 data = self._DoReadFile('200_align_default.dts')
4574 expected = (U_BOOT_DATA + tools.GetBytes(0, 8 - len(U_BOOT_DATA)) +
4575 U_BOOT_DATA)
4576 # Special alignment for section
4577 expected += tools.GetBytes(0, 32 - len(expected))
4578 # No alignment within the nested section
4579 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
4580 # Now the final piece, which should be default-aligned
4581 expected += tools.GetBytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
4582 self.assertEqual(expected, data)
Simon Glass27a7f772021-03-21 18:24:32 +13004583
Bin Mengc0b15742021-05-10 20:23:33 +08004584 def testPackOpenSBI(self):
4585 """Test that an image with an OpenSBI binary can be created"""
4586 data = self._DoReadFile('201_opensbi.dts')
4587 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
4588
Simon Glass76f496d2021-07-06 10:36:37 -06004589 def testSectionsSingleThread(self):
4590 """Test sections without multithreading"""
4591 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
4592 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
4593 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
4594 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
4595 self.assertEqual(expected, data)
4596
4597 def testThreadTimeout(self):
4598 """Test handling a thread that takes too long"""
4599 with self.assertRaises(ValueError) as e:
4600 self._DoTestFile('202_section_timeout.dts',
4601 test_section_timeout=True)
Simon Glass2d59d152021-10-18 12:13:15 -06004602 self.assertIn("Timed out obtaining contents", str(e.exception))
Simon Glass76f496d2021-07-06 10:36:37 -06004603
Simon Glass748a1d42021-07-06 10:36:41 -06004604 def testTiming(self):
4605 """Test output of timing information"""
4606 data = self._DoReadFile('055_sections.dts')
4607 with test_util.capture_sys_output() as (stdout, stderr):
4608 state.TimingShow()
4609 self.assertIn('read:', stdout.getvalue())
4610 self.assertIn('compress:', stdout.getvalue())
4611
Simon Glassadfb8492021-11-03 21:09:18 -06004612 def testUpdateFdtInElf(self):
4613 """Test that we can update the devicetree in an ELF file"""
4614 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4615 outfile = os.path.join(self._indir, 'u-boot.out')
4616 begin_sym = 'dtb_embed_begin'
4617 end_sym = 'dtb_embed_end'
4618 retcode = self._DoTestFile(
4619 '060_fdt_update.dts', update_dtb=True,
4620 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4621 self.assertEqual(0, retcode)
4622
4623 # Check that the output file does in fact contact a dtb with the binman
4624 # definition in the correct place
4625 syms = elf.GetSymbolFileOffset(infile,
4626 ['dtb_embed_begin', 'dtb_embed_end'])
4627 data = tools.ReadFile(outfile)
4628 dtb_data = data[syms['dtb_embed_begin'].offset:
4629 syms['dtb_embed_end'].offset]
4630
4631 dtb = fdt.Fdt.FromData(dtb_data)
4632 dtb.Scan()
4633 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4634 self.assertEqual({
4635 'image-pos': 0,
4636 'offset': 0,
4637 '_testing:offset': 32,
4638 '_testing:size': 2,
4639 '_testing:image-pos': 32,
4640 'section@0/u-boot:offset': 0,
4641 'section@0/u-boot:size': len(U_BOOT_DATA),
4642 'section@0/u-boot:image-pos': 0,
4643 'section@0:offset': 0,
4644 'section@0:size': 16,
4645 'section@0:image-pos': 0,
4646
4647 'section@1/u-boot:offset': 0,
4648 'section@1/u-boot:size': len(U_BOOT_DATA),
4649 'section@1/u-boot:image-pos': 16,
4650 'section@1:offset': 16,
4651 'section@1:size': 16,
4652 'section@1:image-pos': 16,
4653 'size': 40
4654 }, props)
4655
4656 def testUpdateFdtInElfInvalid(self):
4657 """Test that invalid args are detected with --update-fdt-in-elf"""
4658 with self.assertRaises(ValueError) as e:
4659 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
4660 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
4661 str(e.exception))
4662
4663 def testUpdateFdtInElfNoSyms(self):
4664 """Test that missing symbols are detected with --update-fdt-in-elf"""
4665 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4666 outfile = ''
4667 begin_sym = 'wrong_begin'
4668 end_sym = 'wrong_end'
4669 with self.assertRaises(ValueError) as e:
4670 self._DoTestFile(
4671 '060_fdt_update.dts',
4672 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4673 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
4674 str(e.exception))
4675
4676 def testUpdateFdtInElfTooSmall(self):
4677 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
4678 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
4679 outfile = os.path.join(self._indir, 'u-boot.out')
4680 begin_sym = 'dtb_embed_begin'
4681 end_sym = 'dtb_embed_end'
4682 with self.assertRaises(ValueError) as e:
4683 self._DoTestFile(
4684 '060_fdt_update.dts', update_dtb=True,
4685 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4686 self.assertRegex(
4687 str(e.exception),
4688 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
4689
Simon Glass88e04da2021-11-23 11:03:42 -07004690 def testVersion(self):
4691 """Test we can get the binman version"""
4692 version = '(unreleased)'
4693 self.assertEqual(version, state.GetVersion(self._indir))
4694
4695 with self.assertRaises(SystemExit):
4696 with test_util.capture_sys_output() as (_, stderr):
4697 self._DoBinman('-V')
4698 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
4699
4700 # Try running the tool too, just to be safe
4701 result = self._RunBinman('-V')
4702 self.assertEqual('Binman %s\n' % version, result.stderr)
4703
4704 # Set up a version file to make sure that works
4705 version = 'v2025.01-rc2'
4706 tools.WriteFile(os.path.join(self._indir, 'version'), version,
4707 binary=False)
4708 self.assertEqual(version, state.GetVersion(self._indir))
4709
Simon Glass637958f2021-11-23 21:09:50 -07004710 def testAltFormat(self):
4711 """Test that alternative formats can be used to extract"""
4712 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
4713
4714 try:
4715 tmpdir, updated_fname = self._SetupImageInTmpdir()
4716 with test_util.capture_sys_output() as (stdout, _):
4717 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
4718 self.assertEqual(
4719 '''Flag (-F) Entry type Description
4720fdt fdtmap Extract the devicetree blob from the fdtmap
4721''',
4722 stdout.getvalue())
4723
4724 dtb = os.path.join(tmpdir, 'fdt.dtb')
4725 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
4726 dtb, 'fdtmap')
4727
4728 # Check that we can read it and it can be scanning, meaning it does
4729 # not have a 16-byte fdtmap header
4730 data = tools.ReadFile(dtb)
4731 dtb = fdt.Fdt.FromData(data)
4732 dtb.Scan()
4733
4734 # Now check u-boot which has no alt_format
4735 fname = os.path.join(tmpdir, 'fdt.dtb')
4736 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
4737 '-f', fname, 'u-boot')
4738 data = tools.ReadFile(fname)
4739 self.assertEqual(U_BOOT_DATA, data)
4740
4741 finally:
4742 shutil.rmtree(tmpdir)
4743
Simon Glass0b00ae62021-11-23 21:09:52 -07004744 def testExtblobList(self):
4745 """Test an image with an external blob list"""
4746 data = self._DoReadFile('215_blob_ext_list.dts')
4747 self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
4748
4749 def testExtblobListMissing(self):
4750 """Test an image with a missing external blob"""
4751 with self.assertRaises(ValueError) as e:
4752 self._DoReadFile('216_blob_ext_list_missing.dts')
4753 self.assertIn("Filename 'missing-file' not found in input path",
4754 str(e.exception))
4755
4756 def testExtblobListMissingOk(self):
4757 """Test an image with an missing external blob that is allowed"""
4758 with test_util.capture_sys_output() as (stdout, stderr):
4759 self._DoTestFile('216_blob_ext_list_missing.dts',
4760 allow_missing=True)
4761 err = stderr.getvalue()
4762 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
4763
Simon Glass3efb2972021-11-23 21:08:59 -07004764 def testFip(self):
4765 """Basic test of generation of an ARM Firmware Image Package (FIP)"""
4766 data = self._DoReadFile('203_fip.dts')
4767 hdr, fents = fip_util.decode_fip(data)
4768 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
4769 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
4770 self.assertEqual(0x123, hdr.flags)
4771
4772 self.assertEqual(2, len(fents))
4773
4774 fent = fents[0]
4775 self.assertEqual(
4776 bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
4777 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
4778 self.assertEqual('soc-fw', fent.fip_type)
4779 self.assertEqual(0x88, fent.offset)
4780 self.assertEqual(len(ATF_BL31_DATA), fent.size)
4781 self.assertEqual(0x123456789abcdef, fent.flags)
4782 self.assertEqual(ATF_BL31_DATA, fent.data)
4783 self.assertEqual(True, fent.valid)
4784
4785 fent = fents[1]
4786 self.assertEqual(
4787 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
4788 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
4789 self.assertEqual('scp-fwu-cfg', fent.fip_type)
4790 self.assertEqual(0x8c, fent.offset)
4791 self.assertEqual(len(ATF_BL31_DATA), fent.size)
4792 self.assertEqual(0, fent.flags)
4793 self.assertEqual(ATF_BL2U_DATA, fent.data)
4794 self.assertEqual(True, fent.valid)
4795
4796 def testFipOther(self):
4797 """Basic FIP with something that isn't a external blob"""
4798 data = self._DoReadFile('204_fip_other.dts')
4799 hdr, fents = fip_util.decode_fip(data)
4800
4801 self.assertEqual(2, len(fents))
4802 fent = fents[1]
4803 self.assertEqual('rot-cert', fent.fip_type)
4804 self.assertEqual(b'aa', fent.data)
4805
4806 def testFipOther(self):
4807 """Basic FIP with something that isn't a external blob"""
4808 data = self._DoReadFile('204_fip_other.dts')
4809 hdr, fents = fip_util.decode_fip(data)
4810
4811 self.assertEqual(2, len(fents))
4812 fent = fents[1]
4813 self.assertEqual('rot-cert', fent.fip_type)
4814 self.assertEqual(b'aa', fent.data)
4815
4816 def testFipNoType(self):
4817 """FIP with an entry of an unknown type"""
4818 with self.assertRaises(ValueError) as e:
4819 self._DoReadFile('205_fip_no_type.dts')
4820 self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
4821 str(e.exception))
4822
4823 def testFipUuid(self):
4824 """Basic FIP with a manual uuid"""
4825 data = self._DoReadFile('206_fip_uuid.dts')
4826 hdr, fents = fip_util.decode_fip(data)
4827
4828 self.assertEqual(2, len(fents))
4829 fent = fents[1]
4830 self.assertEqual(None, fent.fip_type)
4831 self.assertEqual(
4832 bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
4833 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
4834 fent.uuid)
4835 self.assertEqual(U_BOOT_DATA, fent.data)
4836
4837 def testFipLs(self):
4838 """Test listing a FIP"""
4839 data = self._DoReadFileRealDtb('207_fip_ls.dts')
4840 hdr, fents = fip_util.decode_fip(data)
4841
4842 try:
4843 tmpdir, updated_fname = self._SetupImageInTmpdir()
4844 with test_util.capture_sys_output() as (stdout, stderr):
4845 self._DoBinman('ls', '-i', updated_fname)
4846 finally:
4847 shutil.rmtree(tmpdir)
4848 lines = stdout.getvalue().splitlines()
4849 expected = [
4850'Name Image-pos Size Entry-type Offset Uncomp-size',
4851'----------------------------------------------------------------',
4852'main-section 0 2d3 section 0',
4853' atf-fip 0 90 atf-fip 0',
4854' soc-fw 88 4 blob-ext 88',
4855' u-boot 8c 4 u-boot 8c',
4856' fdtmap 90 243 fdtmap 90',
4857]
4858 self.assertEqual(expected, lines)
4859
4860 image = control.images['image']
4861 entries = image.GetEntries()
4862 fdtmap = entries['fdtmap']
4863
4864 fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
4865 magic = fdtmap_data[:8]
4866 self.assertEqual(b'_FDTMAP_', magic)
4867 self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
4868
4869 fdt_data = fdtmap_data[16:]
4870 dtb = fdt.Fdt.FromData(fdt_data)
4871 dtb.Scan()
4872 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
4873 self.assertEqual({
4874 'atf-fip/soc-fw:image-pos': 136,
4875 'atf-fip/soc-fw:offset': 136,
4876 'atf-fip/soc-fw:size': 4,
4877 'atf-fip/u-boot:image-pos': 140,
4878 'atf-fip/u-boot:offset': 140,
4879 'atf-fip/u-boot:size': 4,
4880 'atf-fip:image-pos': 0,
4881 'atf-fip:offset': 0,
4882 'atf-fip:size': 144,
4883 'image-pos': 0,
4884 'offset': 0,
4885 'fdtmap:image-pos': fdtmap.image_pos,
4886 'fdtmap:offset': fdtmap.offset,
4887 'fdtmap:size': len(fdtmap_data),
4888 'size': len(data),
4889 }, props)
4890
4891 def testFipExtractOneEntry(self):
4892 """Test extracting a single entry fron an FIP"""
4893 self._DoReadFileRealDtb('207_fip_ls.dts')
4894 image_fname = tools.GetOutputFilename('image.bin')
4895 fname = os.path.join(self._indir, 'output.extact')
4896 control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
4897 data = tools.ReadFile(fname)
4898 self.assertEqual(U_BOOT_DATA, data)
4899
4900 def testFipReplace(self):
4901 """Test replacing a single file in a FIP"""
4902 expected = U_BOOT_DATA + tools.GetBytes(0x78, 50)
4903 data = self._DoReadFileRealDtb('208_fip_replace.dts')
4904 updated_fname = tools.GetOutputFilename('image-updated.bin')
4905 tools.WriteFile(updated_fname, data)
4906 entry_name = 'atf-fip/u-boot'
4907 control.WriteEntry(updated_fname, entry_name, expected,
4908 allow_resize=True)
4909 actual = control.ReadEntry(updated_fname, entry_name)
4910 self.assertEqual(expected, actual)
4911
4912 new_data = tools.ReadFile(updated_fname)
4913 hdr, fents = fip_util.decode_fip(new_data)
4914
4915 self.assertEqual(2, len(fents))
4916
4917 # Check that the FIP entry is updated
4918 fent = fents[1]
4919 self.assertEqual(0x8c, fent.offset)
4920 self.assertEqual(len(expected), fent.size)
4921 self.assertEqual(0, fent.flags)
4922 self.assertEqual(expected, fent.data)
4923 self.assertEqual(True, fent.valid)
4924
4925 def testFipMissing(self):
4926 with test_util.capture_sys_output() as (stdout, stderr):
4927 self._DoTestFile('209_fip_missing.dts', allow_missing=True)
4928 err = stderr.getvalue()
4929 self.assertRegex(err, "Image 'main-section'.*missing.*: rmm-fw")
4930
4931 def testFipSize(self):
4932 """Test a FIP with a size property"""
4933 data = self._DoReadFile('210_fip_size.dts')
4934 self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
4935 hdr, fents = fip_util.decode_fip(data)
4936 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
4937 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
4938
4939 self.assertEqual(1, len(fents))
4940
4941 fent = fents[0]
4942 self.assertEqual('soc-fw', fent.fip_type)
4943 self.assertEqual(0x60, fent.offset)
4944 self.assertEqual(len(ATF_BL31_DATA), fent.size)
4945 self.assertEqual(ATF_BL31_DATA, fent.data)
4946 self.assertEqual(True, fent.valid)
4947
4948 rest = data[0x60 + len(ATF_BL31_DATA):0x100]
4949 self.assertEqual(tools.GetBytes(0xff, len(rest)), rest)
4950
4951 def testFipBadAlign(self):
4952 """Test that an invalid alignment value in a FIP is detected"""
4953 with self.assertRaises(ValueError) as e:
4954 self._DoTestFile('211_fip_bad_align.dts')
4955 self.assertIn(
4956 "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
4957 str(e.exception))
4958
4959 def testFipCollection(self):
4960 """Test using a FIP in a collection"""
4961 data = self._DoReadFile('212_fip_collection.dts')
4962 entry1 = control.images['image'].GetEntries()['collection']
4963 data1 = data[:entry1.size]
4964 hdr1, fents2 = fip_util.decode_fip(data1)
4965
4966 entry2 = control.images['image'].GetEntries()['atf-fip']
4967 data2 = data[entry2.offset:entry2.offset + entry2.size]
4968 hdr1, fents2 = fip_util.decode_fip(data2)
4969
4970 # The 'collection' entry should have U-Boot included at the end
4971 self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
4972 self.assertEqual(data1, data2 + U_BOOT_DATA)
4973 self.assertEqual(U_BOOT_DATA, data1[-4:])
4974
4975 # There should be a U-Boot after the final FIP
4976 self.assertEqual(U_BOOT_DATA, data[-4:])
Simon Glass76f496d2021-07-06 10:36:37 -06004977
Simon Glassccae6862022-01-12 13:10:35 -07004978 def testFakeBlob(self):
4979 """Test handling of faking an external blob"""
4980 with test_util.capture_sys_output() as (stdout, stderr):
4981 self._DoTestFile('217_fake_blob.dts', allow_missing=True,
4982 allow_fake_blobs=True)
4983 err = stderr.getvalue()
4984 self.assertRegex(
4985 err,
4986 "Image '.*' has faked external blobs and is non-functional: .*")
Simon Glassccae6862022-01-12 13:10:35 -07004987
Simon Glassceb5f912022-01-09 20:13:46 -07004988 def testExtblobListFaked(self):
4989 """Test an extblob with missing external blob that are faked"""
4990 with test_util.capture_sys_output() as (stdout, stderr):
4991 self._DoTestFile('216_blob_ext_list_missing.dts',
4992 allow_fake_blobs=True)
4993 err = stderr.getvalue()
4994 self.assertRegex(err, "Image 'main-section'.*faked.*: blob-ext-list")
4995
Simon Glass162017b2022-01-09 20:13:57 -07004996 def testListBintools(self):
4997 args = ['tool', '--list']
4998 with test_util.capture_sys_output() as (stdout, _):
4999 self._DoBinman(*args)
5000 out = stdout.getvalue().splitlines()
5001 self.assertTrue(len(out) >= 2)
5002
5003 def testFetchBintools(self):
5004 def fail_download(url):
5005 """Take the tools.Download() function by raising an exception"""
5006 raise urllib.error.URLError('my error')
5007
5008 args = ['tool']
5009 with self.assertRaises(ValueError) as e:
5010 self._DoBinman(*args)
5011 self.assertIn("Invalid arguments to 'tool' subcommand",
5012 str(e.exception))
5013
5014 args = ['tool', '--fetch']
5015 with self.assertRaises(ValueError) as e:
5016 self._DoBinman(*args)
5017 self.assertIn('Please specify bintools to fetch', str(e.exception))
5018
5019 args = ['tool', '--fetch', '_testing']
5020 with unittest.mock.patch.object(tools, 'Download',
5021 side_effect=fail_download):
5022 with test_util.capture_sys_output() as (stdout, _):
5023 self._DoBinman(*args)
5024 self.assertIn('failed to fetch with all methods', stdout.getvalue())
5025
Simon Glassccae6862022-01-12 13:10:35 -07005026
Simon Glassac599912017-11-12 21:52:22 -07005027if __name__ == "__main__":
5028 unittest.main()