blob: cea3ebf2b9f7512a8b1c6e5d58c6072b2b53c8de [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
20
Simon Glassc585dd42020-04-17 18:09:03 -060021from binman import cbfs_util
22from binman import cmdline
23from binman import control
24from binman import elf
25from binman import elf_test
26from binman import fmap_util
Simon Glassc585dd42020-04-17 18:09:03 -060027from binman import state
28from dtoc import fdt
29from dtoc import fdt_util
30from binman.etype import fdtmap
31from binman.etype import image_header
Simon Glass90cd6f02020-08-05 13:27:47 -060032from binman.image import Image
Simon Glassa997ea52020-04-17 18:09:04 -060033from patman import command
34from patman import test_util
35from patman import tools
36from patman import tout
Simon Glass57454f42016-11-25 20:15:52 -070037
38# Contents of test files, corresponding to different entry types
Simon Glass303f62f2019-05-17 22:00:46 -060039U_BOOT_DATA = b'1234'
40U_BOOT_IMG_DATA = b'img'
Simon Glass4e353e22019-08-24 07:23:04 -060041U_BOOT_SPL_DATA = b'56780123456789abcdefghi'
42U_BOOT_TPL_DATA = b'tpl9876543210fedcbazyw'
Simon Glass303f62f2019-05-17 22:00:46 -060043BLOB_DATA = b'89'
44ME_DATA = b'0abcd'
45VGA_DATA = b'vga'
46U_BOOT_DTB_DATA = b'udtb'
47U_BOOT_SPL_DTB_DATA = b'spldtb'
48U_BOOT_TPL_DTB_DATA = b'tpldtb'
49X86_START16_DATA = b'start16'
50X86_START16_SPL_DATA = b'start16spl'
51X86_START16_TPL_DATA = b'start16tpl'
Simon Glass0b074d62019-08-24 07:22:48 -060052X86_RESET16_DATA = b'reset16'
53X86_RESET16_SPL_DATA = b'reset16spl'
54X86_RESET16_TPL_DATA = b'reset16tpl'
Simon Glass303f62f2019-05-17 22:00:46 -060055PPC_MPC85XX_BR_DATA = b'ppcmpc85xxbr'
56U_BOOT_NODTB_DATA = b'nodtb with microcode pointer somewhere in here'
57U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here'
58U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here'
59FSP_DATA = b'fsp'
60CMC_DATA = b'cmc'
61VBT_DATA = b'vbt'
62MRC_DATA = b'mrc'
Simon Glass2ca52032018-07-17 13:25:33 -060063TEXT_DATA = 'text'
64TEXT_DATA2 = 'text2'
65TEXT_DATA3 = 'text3'
Simon Glass303f62f2019-05-17 22:00:46 -060066CROS_EC_RW_DATA = b'ecrw'
67GBB_DATA = b'gbbd'
68BMPBLK_DATA = b'bmp'
69VBLOCK_DATA = b'vblk'
70FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
71 b"sorry you're alive\n")
Simon Glassccec0262019-07-08 13:18:42 -060072COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
Simon Glassd92c8362020-10-26 17:40:25 -060073COMPRESS_DATA_BIG = COMPRESS_DATA * 2
Simon Glass303f62f2019-05-17 22:00:46 -060074REFCODE_DATA = b'refcode'
Simon Glassba7985d2019-08-24 07:23:07 -060075FSP_M_DATA = b'fsp_m'
Simon Glass4d9086d2019-10-20 21:31:35 -060076FSP_S_DATA = b'fsp_s'
Simon Glass9ea87b22019-10-20 21:31:36 -060077FSP_T_DATA = b'fsp_t'
Simon Glass559c4de2020-09-01 05:13:58 -060078ATF_BL31_DATA = b'bl31'
Bin Mengc0b15742021-05-10 20:23:33 +080079OPENSBI_DATA = b'opensbi'
Samuel Holland9d8cc632020-10-21 21:12:15 -050080SCP_DATA = b'scp'
Simon Glassa435cd12020-09-01 05:13:59 -060081TEST_FDT1_DATA = b'fdt1'
82TEST_FDT2_DATA = b'test-fdt2'
Simon Glassa0729502020-09-06 10:35:33 -060083ENV_DATA = b'var1=1\nvar2="2"'
Simon Glassa435cd12020-09-01 05:13:59 -060084
85# Subdirectory of the input dir to use to put test FDTs
86TEST_FDT_SUBDIR = 'fdts'
Simon Glassdb168d42018-07-17 13:25:39 -060087
Simon Glass2c6adba2019-07-20 12:23:47 -060088# The expected size for the device tree in some tests
Simon Glass4c613bf2019-07-08 14:25:50 -060089EXTRACT_DTB_SIZE = 0x3c9
90
Simon Glass2c6adba2019-07-20 12:23:47 -060091# Properties expected to be in the device tree when update_dtb is used
92BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
93
Simon Glassfb30e292019-07-20 12:23:51 -060094# Extra properties expected to be in the device tree when allow-repack is used
95REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
96
Simon Glass57454f42016-11-25 20:15:52 -070097
98class TestFunctional(unittest.TestCase):
99 """Functional tests for binman
100
101 Most of these use a sample .dts file to build an image and then check
102 that it looks correct. The sample files are in the test/ subdirectory
103 and are numbered.
104
105 For each entry type a very small test file is created using fixed
106 string contents. This makes it easy to test that things look right, and
107 debug problems.
108
109 In some cases a 'real' file must be used - these are also supplied in
110 the test/ diurectory.
111 """
112 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600113 def setUpClass(cls):
Simon Glassb3393262017-11-12 21:52:20 -0700114 global entry
Simon Glassc585dd42020-04-17 18:09:03 -0600115 from binman import entry
Simon Glassb3393262017-11-12 21:52:20 -0700116
Simon Glass57454f42016-11-25 20:15:52 -0700117 # Handle the case where argv[0] is 'python'
Simon Glass862f8e22019-08-24 07:22:43 -0600118 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
119 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
Simon Glass57454f42016-11-25 20:15:52 -0700120
121 # Create a temporary directory for input files
Simon Glass862f8e22019-08-24 07:22:43 -0600122 cls._indir = tempfile.mkdtemp(prefix='binmant.')
Simon Glass57454f42016-11-25 20:15:52 -0700123
124 # Create some test files
125 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
126 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
127 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glass8425a1f2018-07-17 13:25:48 -0600128 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700129 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glass72232452016-11-25 20:15:53 -0700130 TestFunctional._MakeInputFile('me.bin', ME_DATA)
131 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glass862f8e22019-08-24 07:22:43 -0600132 cls._ResetDtbs()
Simon Glass0b074d62019-08-24 07:22:48 -0600133
Jagdish Gediya311d4842018-09-03 21:35:08 +0530134 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glass0b074d62019-08-24 07:22:48 -0600135
Simon Glassabab18c2019-08-24 07:22:49 -0600136 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
137 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
Simon Glasse83679d2017-11-12 21:52:26 -0700138 X86_START16_SPL_DATA)
Simon Glassabab18c2019-08-24 07:22:49 -0600139 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
Simon Glassed40e962018-09-14 04:57:10 -0600140 X86_START16_TPL_DATA)
Simon Glass0b074d62019-08-24 07:22:48 -0600141
142 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
143 X86_RESET16_DATA)
144 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
145 X86_RESET16_SPL_DATA)
146 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
147 X86_RESET16_TPL_DATA)
148
Simon Glass57454f42016-11-25 20:15:52 -0700149 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass3d274232017-11-12 21:52:27 -0700150 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
151 U_BOOT_SPL_NODTB_DATA)
Simon Glass3fb4f422018-09-14 04:57:32 -0600152 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
153 U_BOOT_TPL_NODTB_DATA)
Simon Glassb4176d42016-11-25 20:15:56 -0700154 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
155 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Mengd7bcdf52017-08-15 22:41:54 -0700156 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassa409c932017-11-12 21:52:28 -0700157 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassdb168d42018-07-17 13:25:39 -0600158 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600159 TestFunctional._MakeInputDir('devkeys')
160 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass41902e42018-10-01 12:22:31 -0600161 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glassba7985d2019-08-24 07:23:07 -0600162 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
Simon Glass4d9086d2019-10-20 21:31:35 -0600163 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
Simon Glass9ea87b22019-10-20 21:31:36 -0600164 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700165
Simon Glassf6290892019-08-24 07:22:53 -0600166 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
167 elf_test.BuildElfTestFiles(cls._elf_testdir)
168
Simon Glass72232452016-11-25 20:15:53 -0700169 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glass4affd4b2019-08-24 07:22:54 -0600170 TestFunctional._MakeInputFile('u-boot',
171 tools.ReadFile(cls.ElfTestFile('u_boot_ucode_ptr')))
Simon Glass72232452016-11-25 20:15:53 -0700172
173 # Intel flash descriptor file
Simon Glasse88cef92020-07-09 18:39:41 -0600174 cls._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -0700175
Simon Glass862f8e22019-08-24 07:22:43 -0600176 shutil.copytree(cls.TestFile('files'),
177 os.path.join(cls._indir, 'files'))
Simon Glassac6328c2018-09-14 04:57:28 -0600178
Simon Glass7ba33592018-09-14 04:57:26 -0600179 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
Simon Glassd92c8362020-10-26 17:40:25 -0600180 TestFunctional._MakeInputFile('compress_big', COMPRESS_DATA_BIG)
Simon Glass559c4de2020-09-01 05:13:58 -0600181 TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
Bin Mengc0b15742021-05-10 20:23:33 +0800182 TestFunctional._MakeInputFile('fw_dynamic.bin', OPENSBI_DATA)
Samuel Holland9d8cc632020-10-21 21:12:15 -0500183 TestFunctional._MakeInputFile('scp.bin', SCP_DATA)
Simon Glass7ba33592018-09-14 04:57:26 -0600184
Simon Glassa435cd12020-09-01 05:13:59 -0600185 # Add a few .dtb files for testing
186 TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR,
187 TEST_FDT1_DATA)
188 TestFunctional._MakeInputFile('%s/test-fdt2.dtb' % TEST_FDT_SUBDIR,
189 TEST_FDT2_DATA)
190
Simon Glassa0729502020-09-06 10:35:33 -0600191 TestFunctional._MakeInputFile('env.txt', ENV_DATA)
192
Simon Glass1de34482019-07-08 13:18:53 -0600193 # Travis-CI may have an old lz4
Simon Glass862f8e22019-08-24 07:22:43 -0600194 cls.have_lz4 = True
Simon Glass1de34482019-07-08 13:18:53 -0600195 try:
196 tools.Run('lz4', '--no-frame-crc', '-c',
Simon Glasscc311ac2019-10-31 07:42:50 -0600197 os.path.join(cls._indir, 'u-boot.bin'), binary=True)
Simon Glass1de34482019-07-08 13:18:53 -0600198 except:
Simon Glass862f8e22019-08-24 07:22:43 -0600199 cls.have_lz4 = False
Simon Glass1de34482019-07-08 13:18:53 -0600200
Simon Glass57454f42016-11-25 20:15:52 -0700201 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600202 def tearDownClass(cls):
Simon Glass57454f42016-11-25 20:15:52 -0700203 """Remove the temporary input directory and its contents"""
Simon Glass862f8e22019-08-24 07:22:43 -0600204 if cls.preserve_indir:
205 print('Preserving input dir: %s' % cls._indir)
Simon Glass1c420c92019-07-08 13:18:49 -0600206 else:
Simon Glass862f8e22019-08-24 07:22:43 -0600207 if cls._indir:
208 shutil.rmtree(cls._indir)
209 cls._indir = None
Simon Glass57454f42016-11-25 20:15:52 -0700210
Simon Glass1c420c92019-07-08 13:18:49 -0600211 @classmethod
Simon Glasscebfab22019-07-08 13:18:50 -0600212 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
Simon Glassf46732a2019-07-08 14:25:29 -0600213 toolpath=None, verbosity=None):
Simon Glass1c420c92019-07-08 13:18:49 -0600214 """Accept arguments controlling test execution
215
216 Args:
217 preserve_indir: Preserve the shared input directory used by all
218 tests in this class.
219 preserve_outdir: Preserve the output directories used by tests. Each
220 test has its own, so this is normally only useful when running a
221 single test.
Simon Glasscebfab22019-07-08 13:18:50 -0600222 toolpath: ist of paths to use for tools
Simon Glass1c420c92019-07-08 13:18:49 -0600223 """
224 cls.preserve_indir = preserve_indir
225 cls.preserve_outdirs = preserve_outdirs
Simon Glasscebfab22019-07-08 13:18:50 -0600226 cls.toolpath = toolpath
Simon Glassf46732a2019-07-08 14:25:29 -0600227 cls.verbosity = verbosity
Simon Glass1c420c92019-07-08 13:18:49 -0600228
Simon Glass1de34482019-07-08 13:18:53 -0600229 def _CheckLz4(self):
230 if not self.have_lz4:
231 self.skipTest('lz4 --no-frame-crc not available')
232
Simon Glassee9d10d2019-07-20 12:24:09 -0600233 def _CleanupOutputDir(self):
234 """Remove the temporary output directory"""
235 if self.preserve_outdirs:
236 print('Preserving output dir: %s' % tools.outdir)
237 else:
238 tools._FinaliseForTest()
239
Simon Glass57454f42016-11-25 20:15:52 -0700240 def setUp(self):
241 # Enable this to turn on debugging output
242 # tout.Init(tout.DEBUG)
243 command.test_result = None
244
245 def tearDown(self):
246 """Remove the temporary output directory"""
Simon Glassee9d10d2019-07-20 12:24:09 -0600247 self._CleanupOutputDir()
Simon Glass57454f42016-11-25 20:15:52 -0700248
Simon Glassb3d6fc72019-07-20 12:24:10 -0600249 def _SetupImageInTmpdir(self):
250 """Set up the output image in a new temporary directory
251
252 This is used when an image has been generated in the output directory,
253 but we want to run binman again. This will create a new output
254 directory and fail to delete the original one.
255
256 This creates a new temporary directory, copies the image to it (with a
257 new name) and removes the old output directory.
258
259 Returns:
260 Tuple:
261 Temporary directory to use
262 New image filename
263 """
264 image_fname = tools.GetOutputFilename('image.bin')
265 tmpdir = tempfile.mkdtemp(prefix='binman.')
266 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
267 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
268 self._CleanupOutputDir()
269 return tmpdir, updated_fname
270
Simon Glass8425a1f2018-07-17 13:25:48 -0600271 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600272 def _ResetDtbs(cls):
Simon Glass8425a1f2018-07-17 13:25:48 -0600273 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
274 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
275 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
276
Simon Glass57454f42016-11-25 20:15:52 -0700277 def _RunBinman(self, *args, **kwargs):
278 """Run binman using the command line
279
280 Args:
281 Arguments to pass, as a list of strings
282 kwargs: Arguments to pass to Command.RunPipe()
283 """
284 result = command.RunPipe([[self._binman_pathname] + list(args)],
285 capture=True, capture_stderr=True, raise_on_error=False)
286 if result.return_code and kwargs.get('raise_on_error', True):
287 raise Exception("Error running '%s': %s" % (' '.join(args),
288 result.stdout + result.stderr))
289 return result
290
Simon Glassf46732a2019-07-08 14:25:29 -0600291 def _DoBinman(self, *argv):
Simon Glass57454f42016-11-25 20:15:52 -0700292 """Run binman using directly (in the same process)
293
294 Args:
295 Arguments to pass, as a list of strings
296 Returns:
297 Return value (0 for success)
298 """
Simon Glassf46732a2019-07-08 14:25:29 -0600299 argv = list(argv)
300 args = cmdline.ParseArgs(argv)
301 args.pager = 'binman-invalid-pager'
302 args.build_dir = self._indir
Simon Glass57454f42016-11-25 20:15:52 -0700303
304 # For testing, you can force an increase in verbosity here
Simon Glassf46732a2019-07-08 14:25:29 -0600305 # args.verbosity = tout.DEBUG
306 return control.Binman(args)
Simon Glass57454f42016-11-25 20:15:52 -0700307
Simon Glass91710b32018-07-17 13:25:32 -0600308 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glassb4595d82019-04-25 21:58:34 -0600309 entry_args=None, images=None, use_real_dtb=False,
Simon Glassed930672021-03-18 20:25:05 +1300310 use_expanded=False, verbosity=None, allow_missing=False,
Simon Glass76f496d2021-07-06 10:36:37 -0600311 extra_indirs=None, threads=None,
312 test_section_timeout=False):
Simon Glass57454f42016-11-25 20:15:52 -0700313 """Run binman with a given test file
314
315 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600316 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600317 debug: True to enable debugging output
Simon Glass30732662018-06-01 09:38:20 -0600318 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600319 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600320 tree before packing it into the image
Simon Glass3b376c32018-09-14 04:57:12 -0600321 entry_args: Dict of entry args to supply to binman
322 key: arg name
323 value: value of that arg
324 images: List of image names to build
Simon Glass31ee50f2020-09-01 05:13:55 -0600325 use_real_dtb: True to use the test file as the contents of
326 the u-boot-dtb entry. Normally this is not needed and the
327 test contents (the U_BOOT_DTB_DATA string) can be used.
328 But in some test we need the real contents.
Simon Glassed930672021-03-18 20:25:05 +1300329 use_expanded: True to use expanded entries where available, e.g.
330 'u-boot-expanded' instead of 'u-boot'
Simon Glass31ee50f2020-09-01 05:13:55 -0600331 verbosity: Verbosity level to use (0-3, None=don't set it)
332 allow_missing: Set the '--allow-missing' flag so that missing
333 external binaries just produce a warning instead of an error
Simon Glassa435cd12020-09-01 05:13:59 -0600334 extra_indirs: Extra input directories to add using -I
Simon Glass76f496d2021-07-06 10:36:37 -0600335 threads: Number of threads to use (None for default, 0 for
336 single-threaded)
Simon Glass57454f42016-11-25 20:15:52 -0700337 """
Simon Glassf46732a2019-07-08 14:25:29 -0600338 args = []
Simon Glass075a45c2017-11-13 18:55:00 -0700339 if debug:
340 args.append('-D')
Simon Glassf46732a2019-07-08 14:25:29 -0600341 if verbosity is not None:
342 args.append('-v%d' % verbosity)
343 elif self.verbosity:
344 args.append('-v%d' % self.verbosity)
345 if self.toolpath:
346 for path in self.toolpath:
347 args += ['--toolpath', path]
Simon Glass76f496d2021-07-06 10:36:37 -0600348 if threads is not None:
349 args.append('-T%d' % threads)
350 if test_section_timeout:
351 args.append('--test-section-timeout')
Simon Glassf46732a2019-07-08 14:25:29 -0600352 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass30732662018-06-01 09:38:20 -0600353 if map:
354 args.append('-m')
Simon Glassa87014e2018-07-06 10:27:42 -0600355 if update_dtb:
Simon Glass38a411c2019-07-08 13:18:47 -0600356 args.append('-u')
Simon Glass31402012018-09-14 04:57:23 -0600357 if not use_real_dtb:
358 args.append('--fake-dtb')
Simon Glassed930672021-03-18 20:25:05 +1300359 if not use_expanded:
360 args.append('--no-expanded')
Simon Glass91710b32018-07-17 13:25:32 -0600361 if entry_args:
Simon Glass5f3645b2019-05-14 15:53:41 -0600362 for arg, value in entry_args.items():
Simon Glass91710b32018-07-17 13:25:32 -0600363 args.append('-a%s=%s' % (arg, value))
Simon Glass5d94cc62020-07-09 18:39:38 -0600364 if allow_missing:
365 args.append('-M')
Simon Glass3b376c32018-09-14 04:57:12 -0600366 if images:
367 for image in images:
368 args += ['-i', image]
Simon Glassa435cd12020-09-01 05:13:59 -0600369 if extra_indirs:
370 for indir in extra_indirs:
371 args += ['-I', indir]
Simon Glass075a45c2017-11-13 18:55:00 -0700372 return self._DoBinman(*args)
Simon Glass57454f42016-11-25 20:15:52 -0700373
374 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glass72232452016-11-25 20:15:53 -0700375 """Set up a new test device-tree file
376
377 The given file is compiled and set up as the device tree to be used
378 for ths test.
379
380 Args:
381 fname: Filename of .dts file to read
Simon Glass1e324002018-06-01 09:38:19 -0600382 outfile: Output filename for compiled device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700383
384 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600385 Contents of device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700386 """
Simon Glassb8d2daa2019-07-20 12:23:49 -0600387 tmpdir = tempfile.mkdtemp(prefix='binmant.')
388 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
Simon Glass33486662019-05-14 15:53:42 -0600389 with open(dtb, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700390 data = fd.read()
391 TestFunctional._MakeInputFile(outfile, data)
Simon Glassb8d2daa2019-07-20 12:23:49 -0600392 shutil.rmtree(tmpdir)
Simon Glass752e7552018-10-01 21:12:41 -0600393 return data
Simon Glass57454f42016-11-25 20:15:52 -0700394
Simon Glasse219aa42018-09-14 04:57:24 -0600395 def _GetDtbContentsForSplTpl(self, dtb_data, name):
396 """Create a version of the main DTB for SPL or SPL
397
398 For testing we don't actually have different versions of the DTB. With
399 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
400 we don't normally have any unwanted nodes.
401
402 We still want the DTBs for SPL and TPL to be different though, since
403 otherwise it is confusing to know which one we are looking at. So add
404 an 'spl' or 'tpl' property to the top-level node.
Simon Glass31ee50f2020-09-01 05:13:55 -0600405
406 Args:
407 dtb_data: dtb data to modify (this should be a value devicetree)
408 name: Name of a new property to add
409
410 Returns:
411 New dtb data with the property added
Simon Glasse219aa42018-09-14 04:57:24 -0600412 """
413 dtb = fdt.Fdt.FromData(dtb_data)
414 dtb.Scan()
415 dtb.GetNode('/binman').AddZeroProp(name)
416 dtb.Sync(auto_resize=True)
417 dtb.Pack()
418 return dtb.GetContents()
419
Simon Glassed930672021-03-18 20:25:05 +1300420 def _DoReadFileDtb(self, fname, use_real_dtb=False, use_expanded=False,
421 map=False, update_dtb=False, entry_args=None,
Simon Glass76f496d2021-07-06 10:36:37 -0600422 reset_dtbs=True, extra_indirs=None, threads=None):
Simon Glass57454f42016-11-25 20:15:52 -0700423 """Run binman and return the resulting image
424
425 This runs binman with a given test file and then reads the resulting
426 output file. It is a shortcut function since most tests need to do
427 these steps.
428
429 Raises an assertion failure if binman returns a non-zero exit code.
430
431 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600432 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass57454f42016-11-25 20:15:52 -0700433 use_real_dtb: True to use the test file as the contents of
434 the u-boot-dtb entry. Normally this is not needed and the
435 test contents (the U_BOOT_DTB_DATA string) can be used.
436 But in some test we need the real contents.
Simon Glassed930672021-03-18 20:25:05 +1300437 use_expanded: True to use expanded entries where available, e.g.
438 'u-boot-expanded' instead of 'u-boot'
Simon Glass30732662018-06-01 09:38:20 -0600439 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600440 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600441 tree before packing it into the image
Simon Glass31ee50f2020-09-01 05:13:55 -0600442 entry_args: Dict of entry args to supply to binman
443 key: arg name
444 value: value of that arg
445 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
446 function. If reset_dtbs is True, then the original test dtb
447 is written back before this function finishes
Simon Glassa435cd12020-09-01 05:13:59 -0600448 extra_indirs: Extra input directories to add using -I
Simon Glass76f496d2021-07-06 10:36:37 -0600449 threads: Number of threads to use (None for default, 0 for
450 single-threaded)
Simon Glass72232452016-11-25 20:15:53 -0700451
452 Returns:
453 Tuple:
454 Resulting image contents
455 Device tree contents
Simon Glass30732662018-06-01 09:38:20 -0600456 Map data showing contents of image (or None if none)
Simon Glassdef77b52018-07-17 13:25:27 -0600457 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass57454f42016-11-25 20:15:52 -0700458 """
Simon Glass72232452016-11-25 20:15:53 -0700459 dtb_data = None
Simon Glass57454f42016-11-25 20:15:52 -0700460 # Use the compiled test file as the u-boot-dtb input
461 if use_real_dtb:
Simon Glass72232452016-11-25 20:15:53 -0700462 dtb_data = self._SetupDtb(fname)
Simon Glasse219aa42018-09-14 04:57:24 -0600463
464 # For testing purposes, make a copy of the DT for SPL and TPL. Add
465 # a node indicating which it is, so aid verification.
466 for name in ['spl', 'tpl']:
467 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
468 outfile = os.path.join(self._indir, dtb_fname)
469 TestFunctional._MakeInputFile(dtb_fname,
470 self._GetDtbContentsForSplTpl(dtb_data, name))
Simon Glass57454f42016-11-25 20:15:52 -0700471
472 try:
Simon Glass91710b32018-07-17 13:25:32 -0600473 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glassa435cd12020-09-01 05:13:59 -0600474 entry_args=entry_args, use_real_dtb=use_real_dtb,
Simon Glass76f496d2021-07-06 10:36:37 -0600475 use_expanded=use_expanded, extra_indirs=extra_indirs,
476 threads=threads)
Simon Glass57454f42016-11-25 20:15:52 -0700477 self.assertEqual(0, retcode)
Simon Glasse219aa42018-09-14 04:57:24 -0600478 out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
Simon Glass57454f42016-11-25 20:15:52 -0700479
480 # Find the (only) image, read it and return its contents
481 image = control.images['image']
Simon Glassa87014e2018-07-06 10:27:42 -0600482 image_fname = tools.GetOutputFilename('image.bin')
483 self.assertTrue(os.path.exists(image_fname))
Simon Glass30732662018-06-01 09:38:20 -0600484 if map:
485 map_fname = tools.GetOutputFilename('image.map')
486 with open(map_fname) as fd:
487 map_data = fd.read()
488 else:
489 map_data = None
Simon Glass33486662019-05-14 15:53:42 -0600490 with open(image_fname, 'rb') as fd:
Simon Glassa87014e2018-07-06 10:27:42 -0600491 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass57454f42016-11-25 20:15:52 -0700492 finally:
493 # Put the test file back
Simon Glasse219aa42018-09-14 04:57:24 -0600494 if reset_dtbs and use_real_dtb:
Simon Glass8425a1f2018-07-17 13:25:48 -0600495 self._ResetDtbs()
Simon Glass57454f42016-11-25 20:15:52 -0700496
Simon Glass5b4bce32019-07-08 14:25:26 -0600497 def _DoReadFileRealDtb(self, fname):
498 """Run binman with a real .dtb file and return the resulting data
499
500 Args:
501 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
502
503 Returns:
504 Resulting image contents
505 """
506 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
507
Simon Glass72232452016-11-25 20:15:53 -0700508 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass1e324002018-06-01 09:38:19 -0600509 """Helper function which discards the device-tree binary
510
511 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600512 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600513 use_real_dtb: True to use the test file as the contents of
514 the u-boot-dtb entry. Normally this is not needed and the
515 test contents (the U_BOOT_DTB_DATA string) can be used.
516 But in some test we need the real contents.
Simon Glassdef77b52018-07-17 13:25:27 -0600517
518 Returns:
519 Resulting image contents
Simon Glass1e324002018-06-01 09:38:19 -0600520 """
Simon Glass72232452016-11-25 20:15:53 -0700521 return self._DoReadFileDtb(fname, use_real_dtb)[0]
522
Simon Glass57454f42016-11-25 20:15:52 -0700523 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600524 def _MakeInputFile(cls, fname, contents):
Simon Glass57454f42016-11-25 20:15:52 -0700525 """Create a new test input file, creating directories as needed
526
527 Args:
Simon Glasse8561af2018-08-01 15:22:37 -0600528 fname: Filename to create
Simon Glass57454f42016-11-25 20:15:52 -0700529 contents: File contents to write in to the file
530 Returns:
531 Full pathname of file created
532 """
Simon Glass862f8e22019-08-24 07:22:43 -0600533 pathname = os.path.join(cls._indir, fname)
Simon Glass57454f42016-11-25 20:15:52 -0700534 dirname = os.path.dirname(pathname)
535 if dirname and not os.path.exists(dirname):
536 os.makedirs(dirname)
537 with open(pathname, 'wb') as fd:
538 fd.write(contents)
539 return pathname
540
541 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600542 def _MakeInputDir(cls, dirname):
Simon Glassc1ae83c2018-07-17 13:25:44 -0600543 """Create a new test input directory, creating directories as needed
544
545 Args:
546 dirname: Directory name to create
547
548 Returns:
549 Full pathname of directory created
550 """
Simon Glass862f8e22019-08-24 07:22:43 -0600551 pathname = os.path.join(cls._indir, dirname)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600552 if not os.path.exists(pathname):
553 os.makedirs(pathname)
554 return pathname
555
556 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600557 def _SetupSplElf(cls, src_fname='bss_data'):
Simon Glass7057d022018-10-01 21:12:47 -0600558 """Set up an ELF file with a '_dt_ucode_base_size' symbol
559
560 Args:
561 Filename of ELF file to use as SPL
562 """
Simon Glass93a806f2019-08-24 07:22:59 -0600563 TestFunctional._MakeInputFile('spl/u-boot-spl',
564 tools.ReadFile(cls.ElfTestFile(src_fname)))
Simon Glass7057d022018-10-01 21:12:47 -0600565
566 @classmethod
Simon Glass3eb5b202019-08-24 07:23:00 -0600567 def _SetupTplElf(cls, src_fname='bss_data'):
568 """Set up an ELF file with a '_dt_ucode_base_size' symbol
569
570 Args:
571 Filename of ELF file to use as TPL
572 """
573 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
574 tools.ReadFile(cls.ElfTestFile(src_fname)))
575
576 @classmethod
Simon Glasse88cef92020-07-09 18:39:41 -0600577 def _SetupDescriptor(cls):
578 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
579 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
580
581 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600582 def TestFile(cls, fname):
583 return os.path.join(cls._binman_dir, 'test', fname)
Simon Glass57454f42016-11-25 20:15:52 -0700584
Simon Glassf6290892019-08-24 07:22:53 -0600585 @classmethod
586 def ElfTestFile(cls, fname):
587 return os.path.join(cls._elf_testdir, fname)
588
Simon Glass57454f42016-11-25 20:15:52 -0700589 def AssertInList(self, grep_list, target):
590 """Assert that at least one of a list of things is in a target
591
592 Args:
593 grep_list: List of strings to check
594 target: Target string
595 """
596 for grep in grep_list:
597 if grep in target:
598 return
Simon Glass848cdb52019-05-17 22:00:50 -0600599 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass57454f42016-11-25 20:15:52 -0700600
601 def CheckNoGaps(self, entries):
602 """Check that all entries fit together without gaps
603
604 Args:
605 entries: List of entries to check
606 """
Simon Glasse8561af2018-08-01 15:22:37 -0600607 offset = 0
Simon Glass57454f42016-11-25 20:15:52 -0700608 for entry in entries.values():
Simon Glasse8561af2018-08-01 15:22:37 -0600609 self.assertEqual(offset, entry.offset)
610 offset += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700611
Simon Glass72232452016-11-25 20:15:53 -0700612 def GetFdtLen(self, dtb):
Simon Glass1e324002018-06-01 09:38:19 -0600613 """Get the totalsize field from a device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700614
615 Args:
Simon Glass1e324002018-06-01 09:38:19 -0600616 dtb: Device-tree binary contents
Simon Glass72232452016-11-25 20:15:53 -0700617
618 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600619 Total size of device-tree binary, from the header
Simon Glass72232452016-11-25 20:15:53 -0700620 """
621 return struct.unpack('>L', dtb[4:8])[0]
622
Simon Glass0f621332019-07-08 14:25:27 -0600623 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glassa87014e2018-07-06 10:27:42 -0600624 def AddNode(node, path):
625 if node.name != '/':
626 path += '/' + node.name
Simon Glass0f621332019-07-08 14:25:27 -0600627 for prop in node.props.values():
628 if prop.name in prop_names:
629 prop_path = path + ':' + prop.name
630 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
631 prop.value)
Simon Glassa87014e2018-07-06 10:27:42 -0600632 for subnode in node.subnodes:
Simon Glassa87014e2018-07-06 10:27:42 -0600633 AddNode(subnode, path)
634
635 tree = {}
Simon Glassa87014e2018-07-06 10:27:42 -0600636 AddNode(dtb.GetRoot(), '')
637 return tree
638
Simon Glass57454f42016-11-25 20:15:52 -0700639 def testRun(self):
640 """Test a basic run with valid args"""
641 result = self._RunBinman('-h')
642
643 def testFullHelp(self):
644 """Test that the full help is displayed with -H"""
645 result = self._RunBinman('-H')
Simon Glass75ead662021-03-18 20:25:13 +1300646 help_file = os.path.join(self._binman_dir, 'README.rst')
Tom Rinic3c0b6d2018-01-16 15:29:50 -0500647 # Remove possible extraneous strings
648 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
649 gothelp = result.stdout.replace(extra, '')
650 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass57454f42016-11-25 20:15:52 -0700651 self.assertEqual(0, len(result.stderr))
652 self.assertEqual(0, result.return_code)
653
654 def testFullHelpInternal(self):
655 """Test that the full help is displayed with -H"""
656 try:
657 command.test_result = command.CommandResult()
658 result = self._DoBinman('-H')
Simon Glass75ead662021-03-18 20:25:13 +1300659 help_file = os.path.join(self._binman_dir, 'README.rst')
Simon Glass57454f42016-11-25 20:15:52 -0700660 finally:
661 command.test_result = None
662
663 def testHelp(self):
664 """Test that the basic help is displayed with -h"""
665 result = self._RunBinman('-h')
666 self.assertTrue(len(result.stdout) > 200)
667 self.assertEqual(0, len(result.stderr))
668 self.assertEqual(0, result.return_code)
669
Simon Glass57454f42016-11-25 20:15:52 -0700670 def testBoard(self):
671 """Test that we can run it with a specific board"""
Simon Glass511f6582018-10-01 12:22:30 -0600672 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass57454f42016-11-25 20:15:52 -0700673 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glassed930672021-03-18 20:25:05 +1300674 result = self._DoBinman('build', '-n', '-b', 'sandbox')
Simon Glass57454f42016-11-25 20:15:52 -0700675 self.assertEqual(0, result)
676
677 def testNeedBoard(self):
678 """Test that we get an error when no board ius supplied"""
679 with self.assertRaises(ValueError) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600680 result = self._DoBinman('build')
Simon Glass57454f42016-11-25 20:15:52 -0700681 self.assertIn("Must provide a board to process (use -b <board>)",
682 str(e.exception))
683
684 def testMissingDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600685 """Test that an invalid device-tree file generates an error"""
Simon Glass57454f42016-11-25 20:15:52 -0700686 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600687 self._RunBinman('build', '-d', 'missing_file')
Simon Glass57454f42016-11-25 20:15:52 -0700688 # We get one error from libfdt, and a different one from fdtget.
689 self.AssertInList(["Couldn't open blob from 'missing_file'",
690 'No such file or directory'], str(e.exception))
691
692 def testBrokenDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600693 """Test that an invalid device-tree source file generates an error
Simon Glass57454f42016-11-25 20:15:52 -0700694
695 Since this is a source file it should be compiled and the error
696 will come from the device-tree compiler (dtc).
697 """
698 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600699 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700700 self.assertIn("FATAL ERROR: Unable to parse input tree",
701 str(e.exception))
702
703 def testMissingNode(self):
704 """Test that a device tree without a 'binman' node generates an error"""
705 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600706 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700707 self.assertIn("does not have a 'binman' node", str(e.exception))
708
709 def testEmpty(self):
710 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glassf46732a2019-07-08 14:25:29 -0600711 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700712 self.assertEqual(0, len(result.stderr))
713 self.assertEqual(0, result.return_code)
714
715 def testInvalidEntry(self):
716 """Test that an invalid entry is flagged"""
717 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600718 result = self._RunBinman('build', '-d',
Simon Glass511f6582018-10-01 12:22:30 -0600719 self.TestFile('004_invalid_entry.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700720 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
721 "'/binman/not-a-valid-type'", str(e.exception))
722
723 def testSimple(self):
724 """Test a simple binman with a single file"""
Simon Glass511f6582018-10-01 12:22:30 -0600725 data = self._DoReadFile('005_simple.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700726 self.assertEqual(U_BOOT_DATA, data)
727
Simon Glass075a45c2017-11-13 18:55:00 -0700728 def testSimpleDebug(self):
729 """Test a simple binman run with debugging enabled"""
Simon Glass52d06212019-07-08 14:25:53 -0600730 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass075a45c2017-11-13 18:55:00 -0700731
Simon Glass57454f42016-11-25 20:15:52 -0700732 def testDual(self):
733 """Test that we can handle creating two images
734
735 This also tests image padding.
736 """
Simon Glass511f6582018-10-01 12:22:30 -0600737 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700738 self.assertEqual(0, retcode)
739
740 image = control.images['image1']
Simon Glass39dd2152019-07-08 14:25:47 -0600741 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700742 fname = tools.GetOutputFilename('image1.bin')
743 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600744 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700745 data = fd.read()
746 self.assertEqual(U_BOOT_DATA, data)
747
748 image = control.images['image2']
Simon Glass39dd2152019-07-08 14:25:47 -0600749 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700750 fname = tools.GetOutputFilename('image2.bin')
751 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600752 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700753 data = fd.read()
754 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glassac0d4952019-05-14 15:53:47 -0600755 self.assertEqual(tools.GetBytes(0, 3), data[:3])
756 self.assertEqual(tools.GetBytes(0, 5), data[7:])
Simon Glass57454f42016-11-25 20:15:52 -0700757
758 def testBadAlign(self):
759 """Test that an invalid alignment value is detected"""
760 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600761 self._DoTestFile('007_bad_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700762 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
763 "of two", str(e.exception))
764
765 def testPackSimple(self):
766 """Test that packing works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -0600767 retcode = self._DoTestFile('008_pack.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700768 self.assertEqual(0, retcode)
769 self.assertIn('image', control.images)
770 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600771 entries = image.GetEntries()
Simon Glass57454f42016-11-25 20:15:52 -0700772 self.assertEqual(5, len(entries))
773
774 # First u-boot
775 self.assertIn('u-boot', entries)
776 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600777 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700778 self.assertEqual(len(U_BOOT_DATA), entry.size)
779
780 # Second u-boot, aligned to 16-byte boundary
781 self.assertIn('u-boot-align', entries)
782 entry = entries['u-boot-align']
Simon Glasse8561af2018-08-01 15:22:37 -0600783 self.assertEqual(16, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700784 self.assertEqual(len(U_BOOT_DATA), entry.size)
785
786 # Third u-boot, size 23 bytes
787 self.assertIn('u-boot-size', entries)
788 entry = entries['u-boot-size']
Simon Glasse8561af2018-08-01 15:22:37 -0600789 self.assertEqual(20, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700790 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
791 self.assertEqual(23, entry.size)
792
793 # Fourth u-boot, placed immediate after the above
794 self.assertIn('u-boot-next', entries)
795 entry = entries['u-boot-next']
Simon Glasse8561af2018-08-01 15:22:37 -0600796 self.assertEqual(43, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700797 self.assertEqual(len(U_BOOT_DATA), entry.size)
798
Simon Glasse8561af2018-08-01 15:22:37 -0600799 # Fifth u-boot, placed at a fixed offset
Simon Glass57454f42016-11-25 20:15:52 -0700800 self.assertIn('u-boot-fixed', entries)
801 entry = entries['u-boot-fixed']
Simon Glasse8561af2018-08-01 15:22:37 -0600802 self.assertEqual(61, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700803 self.assertEqual(len(U_BOOT_DATA), entry.size)
804
Simon Glass39dd2152019-07-08 14:25:47 -0600805 self.assertEqual(65, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700806
807 def testPackExtra(self):
808 """Test that extra packing feature works as expected"""
Simon Glassafb9caa2020-10-26 17:40:10 -0600809 data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
810 update_dtb=True)
Simon Glass57454f42016-11-25 20:15:52 -0700811
Simon Glass57454f42016-11-25 20:15:52 -0700812 self.assertIn('image', control.images)
813 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600814 entries = image.GetEntries()
Simon Glass57454f42016-11-25 20:15:52 -0700815 self.assertEqual(5, len(entries))
816
817 # First u-boot with padding before and after
818 self.assertIn('u-boot', entries)
819 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600820 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700821 self.assertEqual(3, entry.pad_before)
822 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600823 self.assertEqual(U_BOOT_DATA, entry.data)
824 self.assertEqual(tools.GetBytes(0, 3) + U_BOOT_DATA +
825 tools.GetBytes(0, 5), data[:entry.size])
826 pos = entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700827
828 # Second u-boot has an aligned size, but it has no effect
829 self.assertIn('u-boot-align-size-nop', entries)
830 entry = entries['u-boot-align-size-nop']
Simon Glass187202f2020-10-26 17:40:08 -0600831 self.assertEqual(pos, entry.offset)
832 self.assertEqual(len(U_BOOT_DATA), entry.size)
833 self.assertEqual(U_BOOT_DATA, entry.data)
834 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
835 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700836
837 # Third u-boot has an aligned size too
838 self.assertIn('u-boot-align-size', entries)
839 entry = entries['u-boot-align-size']
Simon Glass187202f2020-10-26 17:40:08 -0600840 self.assertEqual(pos, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700841 self.assertEqual(32, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600842 self.assertEqual(U_BOOT_DATA, entry.data)
843 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 32 - len(U_BOOT_DATA)),
844 data[pos:pos + entry.size])
845 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700846
847 # Fourth u-boot has an aligned end
848 self.assertIn('u-boot-align-end', entries)
849 entry = entries['u-boot-align-end']
Simon Glasse8561af2018-08-01 15:22:37 -0600850 self.assertEqual(48, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700851 self.assertEqual(16, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600852 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
853 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 16 - len(U_BOOT_DATA)),
854 data[pos:pos + entry.size])
855 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700856
857 # Fifth u-boot immediately afterwards
858 self.assertIn('u-boot-align-both', entries)
859 entry = entries['u-boot-align-both']
Simon Glasse8561af2018-08-01 15:22:37 -0600860 self.assertEqual(64, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700861 self.assertEqual(64, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600862 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
863 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 64 - len(U_BOOT_DATA)),
864 data[pos:pos + entry.size])
Simon Glass57454f42016-11-25 20:15:52 -0700865
866 self.CheckNoGaps(entries)
Simon Glass39dd2152019-07-08 14:25:47 -0600867 self.assertEqual(128, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700868
Simon Glassafb9caa2020-10-26 17:40:10 -0600869 dtb = fdt.Fdt(out_dtb_fname)
870 dtb.Scan()
871 props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
872 expected = {
873 'image-pos': 0,
874 'offset': 0,
875 'size': 128,
876
877 'u-boot:image-pos': 0,
878 'u-boot:offset': 0,
879 'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
880
881 'u-boot-align-size-nop:image-pos': 12,
882 'u-boot-align-size-nop:offset': 12,
883 'u-boot-align-size-nop:size': 4,
884
885 'u-boot-align-size:image-pos': 16,
886 'u-boot-align-size:offset': 16,
887 'u-boot-align-size:size': 32,
888
889 'u-boot-align-end:image-pos': 48,
890 'u-boot-align-end:offset': 48,
891 'u-boot-align-end:size': 16,
892
893 'u-boot-align-both:image-pos': 64,
894 'u-boot-align-both:offset': 64,
895 'u-boot-align-both:size': 64,
896 }
897 self.assertEqual(expected, props)
898
Simon Glass57454f42016-11-25 20:15:52 -0700899 def testPackAlignPowerOf2(self):
900 """Test that invalid entry alignment is detected"""
901 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600902 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700903 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
904 "of two", str(e.exception))
905
906 def testPackAlignSizePowerOf2(self):
907 """Test that invalid entry size alignment is detected"""
908 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600909 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700910 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
911 "power of two", str(e.exception))
912
913 def testPackInvalidAlign(self):
Simon Glasse8561af2018-08-01 15:22:37 -0600914 """Test detection of an offset that does not match its alignment"""
Simon Glass57454f42016-11-25 20:15:52 -0700915 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600916 self._DoTestFile('012_pack_inv_align.dts')
Simon Glasse8561af2018-08-01 15:22:37 -0600917 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass57454f42016-11-25 20:15:52 -0700918 "align 0x4 (4)", str(e.exception))
919
920 def testPackInvalidSizeAlign(self):
921 """Test that invalid entry size alignment is detected"""
922 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600923 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700924 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
925 "align-size 0x4 (4)", str(e.exception))
926
927 def testPackOverlap(self):
928 """Test that overlapping regions are detected"""
929 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600930 self._DoTestFile('014_pack_overlap.dts')
Simon Glasse8561af2018-08-01 15:22:37 -0600931 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -0700932 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
933 str(e.exception))
934
935 def testPackEntryOverflow(self):
936 """Test that entries that overflow their size are detected"""
937 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600938 self._DoTestFile('015_pack_overflow.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700939 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
940 "but entry size is 0x3 (3)", str(e.exception))
941
942 def testPackImageOverflow(self):
943 """Test that entries which overflow the image size are detected"""
944 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600945 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glasseca32212018-06-01 09:38:12 -0600946 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass57454f42016-11-25 20:15:52 -0700947 "size 0x3 (3)", str(e.exception))
948
949 def testPackImageSize(self):
950 """Test that the image size can be set"""
Simon Glass511f6582018-10-01 12:22:30 -0600951 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700952 self.assertEqual(0, retcode)
953 self.assertIn('image', control.images)
954 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -0600955 self.assertEqual(7, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700956
957 def testPackImageSizeAlign(self):
958 """Test that image size alignemnt works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -0600959 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700960 self.assertEqual(0, retcode)
961 self.assertIn('image', control.images)
962 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -0600963 self.assertEqual(16, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700964
965 def testPackInvalidImageAlign(self):
966 """Test that invalid image alignment is detected"""
967 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600968 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glasseca32212018-06-01 09:38:12 -0600969 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass57454f42016-11-25 20:15:52 -0700970 "align-size 0x8 (8)", str(e.exception))
971
972 def testPackAlignPowerOf2(self):
973 """Test that invalid image alignment is detected"""
974 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600975 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass39dd2152019-07-08 14:25:47 -0600976 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass57454f42016-11-25 20:15:52 -0700977 "two", str(e.exception))
978
979 def testImagePadByte(self):
980 """Test that the image pad byte can be specified"""
Simon Glass7057d022018-10-01 21:12:47 -0600981 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -0600982 data = self._DoReadFile('021_image_pad.dts')
Simon Glassac0d4952019-05-14 15:53:47 -0600983 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0xff, 1) +
984 U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -0700985
986 def testImageName(self):
987 """Test that image files can be named"""
Simon Glass511f6582018-10-01 12:22:30 -0600988 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700989 self.assertEqual(0, retcode)
990 image = control.images['image1']
991 fname = tools.GetOutputFilename('test-name')
992 self.assertTrue(os.path.exists(fname))
993
994 image = control.images['image2']
995 fname = tools.GetOutputFilename('test-name.xx')
996 self.assertTrue(os.path.exists(fname))
997
998 def testBlobFilename(self):
999 """Test that generic blobs can be provided by filename"""
Simon Glass511f6582018-10-01 12:22:30 -06001000 data = self._DoReadFile('023_blob.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001001 self.assertEqual(BLOB_DATA, data)
1002
1003 def testPackSorted(self):
1004 """Test that entries can be sorted"""
Simon Glass7057d022018-10-01 21:12:47 -06001005 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001006 data = self._DoReadFile('024_sorted.dts')
Simon Glassac0d4952019-05-14 15:53:47 -06001007 self.assertEqual(tools.GetBytes(0, 1) + U_BOOT_SPL_DATA +
1008 tools.GetBytes(0, 2) + U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -07001009
Simon Glasse8561af2018-08-01 15:22:37 -06001010 def testPackZeroOffset(self):
1011 """Test that an entry at offset 0 is not given a new offset"""
Simon Glass57454f42016-11-25 20:15:52 -07001012 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001013 self._DoTestFile('025_pack_zero_size.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001014 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -07001015 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1016 str(e.exception))
1017
1018 def testPackUbootDtb(self):
1019 """Test that a device tree can be added to U-Boot"""
Simon Glass511f6582018-10-01 12:22:30 -06001020 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001021 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glass72232452016-11-25 20:15:53 -07001022
1023 def testPackX86RomNoSize(self):
1024 """Test that the end-at-4gb property requires a size property"""
1025 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001026 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001027 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glass72232452016-11-25 20:15:53 -07001028 "using end-at-4gb", str(e.exception))
1029
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301030 def test4gbAndSkipAtStartTogether(self):
1031 """Test that the end-at-4gb and skip-at-size property can't be used
1032 together"""
1033 with self.assertRaises(ValueError) as e:
Simon Glass11f2bd02019-08-24 07:23:02 -06001034 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001035 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301036 "'skip-at-start'", str(e.exception))
1037
Simon Glass72232452016-11-25 20:15:53 -07001038 def testPackX86RomOutside(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001039 """Test that the end-at-4gb property checks for offset boundaries"""
Simon Glass72232452016-11-25 20:15:53 -07001040 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001041 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glassd6179862020-10-26 17:40:05 -06001042 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
1043 "is outside the section '/binman' starting at "
1044 '0xffffffe0 (4294967264) of size 0x20 (32)',
Simon Glass72232452016-11-25 20:15:53 -07001045 str(e.exception))
1046
1047 def testPackX86Rom(self):
1048 """Test that a basic x86 ROM can be created"""
Simon Glass7057d022018-10-01 21:12:47 -06001049 self._SetupSplElf()
Simon Glass1d167762019-08-24 07:23:01 -06001050 data = self._DoReadFile('029_x86_rom.dts')
Simon Glass4e353e22019-08-24 07:23:04 -06001051 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 3) + U_BOOT_SPL_DATA +
Simon Glassac0d4952019-05-14 15:53:47 -06001052 tools.GetBytes(0, 2), data)
Simon Glass72232452016-11-25 20:15:53 -07001053
1054 def testPackX86RomMeNoDesc(self):
1055 """Test that an invalid Intel descriptor entry is detected"""
Simon Glasse88cef92020-07-09 18:39:41 -06001056 try:
Simon Glass14c596c2020-07-25 15:11:19 -06001057 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
Simon Glasse88cef92020-07-09 18:39:41 -06001058 with self.assertRaises(ValueError) as e:
Simon Glass14c596c2020-07-25 15:11:19 -06001059 self._DoTestFile('163_x86_rom_me_empty.dts')
Simon Glasse88cef92020-07-09 18:39:41 -06001060 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1061 str(e.exception))
1062 finally:
1063 self._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -07001064
1065 def testPackX86RomBadDesc(self):
1066 """Test that the Intel requires a descriptor entry"""
1067 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06001068 self._DoTestFile('030_x86_rom_me_no_desc.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001069 self.assertIn("Node '/binman/intel-me': No offset set with "
1070 "offset-unset: should another entry provide this correct "
1071 "offset?", str(e.exception))
Simon Glass72232452016-11-25 20:15:53 -07001072
1073 def testPackX86RomMe(self):
1074 """Test that an x86 ROM with an ME region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001075 data = self._DoReadFile('031_x86_rom_me.dts')
Simon Glass759af872019-07-08 13:18:54 -06001076 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
1077 if data[:0x1000] != expected_desc:
1078 self.fail('Expected descriptor binary at start of image')
Simon Glass72232452016-11-25 20:15:53 -07001079 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1080
1081 def testPackVga(self):
1082 """Test that an image with a VGA binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001083 data = self._DoReadFile('032_intel_vga.dts')
Simon Glass72232452016-11-25 20:15:53 -07001084 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1085
1086 def testPackStart16(self):
1087 """Test that an image with an x86 start16 region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001088 data = self._DoReadFile('033_x86_start16.dts')
Simon Glass72232452016-11-25 20:15:53 -07001089 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1090
Jagdish Gediya311d4842018-09-03 21:35:08 +05301091 def testPackPowerpcMpc85xxBootpgResetvec(self):
1092 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1093 created"""
Simon Glass11f2bd02019-08-24 07:23:02 -06001094 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
Jagdish Gediya311d4842018-09-03 21:35:08 +05301095 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1096
Simon Glass6ba679c2018-07-06 10:27:17 -06001097 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glass820af1d2018-07-06 10:27:16 -06001098 """Handle running a test for insertion of microcode
1099
1100 Args:
1101 dts_fname: Name of test .dts file
1102 nodtb_data: Data that we expect in the first section
Simon Glass6ba679c2018-07-06 10:27:17 -06001103 ucode_second: True if the microsecond entry is second instead of
1104 third
Simon Glass820af1d2018-07-06 10:27:16 -06001105
1106 Returns:
1107 Tuple:
1108 Contents of first region (U-Boot or SPL)
Simon Glasse8561af2018-08-01 15:22:37 -06001109 Offset and size components of microcode pointer, as inserted
Simon Glass820af1d2018-07-06 10:27:16 -06001110 in the above (two 4-byte words)
1111 """
Simon Glass3d274232017-11-12 21:52:27 -07001112 data = self._DoReadFile(dts_fname, True)
Simon Glass72232452016-11-25 20:15:53 -07001113
1114 # Now check the device tree has no microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001115 if ucode_second:
1116 ucode_content = data[len(nodtb_data):]
1117 ucode_pos = len(nodtb_data)
1118 dtb_with_ucode = ucode_content[16:]
1119 fdt_len = self.GetFdtLen(dtb_with_ucode)
1120 else:
1121 dtb_with_ucode = data[len(nodtb_data):]
1122 fdt_len = self.GetFdtLen(dtb_with_ucode)
1123 ucode_content = dtb_with_ucode[fdt_len:]
1124 ucode_pos = len(nodtb_data) + fdt_len
Simon Glass72232452016-11-25 20:15:53 -07001125 fname = tools.GetOutputFilename('test.dtb')
1126 with open(fname, 'wb') as fd:
Simon Glass820af1d2018-07-06 10:27:16 -06001127 fd.write(dtb_with_ucode)
Simon Glass22c92ca2017-05-27 07:38:29 -06001128 dtb = fdt.FdtScan(fname)
1129 ucode = dtb.GetNode('/microcode')
Simon Glass72232452016-11-25 20:15:53 -07001130 self.assertTrue(ucode)
1131 for node in ucode.subnodes:
1132 self.assertFalse(node.props.get('data'))
1133
Simon Glass72232452016-11-25 20:15:53 -07001134 # Check that the microcode appears immediately after the Fdt
1135 # This matches the concatenation of the data properties in
Simon Glasse83679d2017-11-12 21:52:26 -07001136 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glass72232452016-11-25 20:15:53 -07001137 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1138 0x78235609)
Simon Glass820af1d2018-07-06 10:27:16 -06001139 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glass72232452016-11-25 20:15:53 -07001140
1141 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001142 # expected offset and size
Simon Glass72232452016-11-25 20:15:53 -07001143 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1144 len(ucode_data))
Simon Glass6ba679c2018-07-06 10:27:17 -06001145 u_boot = data[:len(nodtb_data)]
1146 return u_boot, pos_and_size
Simon Glass3d274232017-11-12 21:52:27 -07001147
1148 def testPackUbootMicrocode(self):
1149 """Test that x86 microcode can be handled correctly
1150
1151 We expect to see the following in the image, in order:
1152 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1153 place
1154 u-boot.dtb with the microcode removed
1155 the microcode
1156 """
Simon Glass511f6582018-10-01 12:22:30 -06001157 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass3d274232017-11-12 21:52:27 -07001158 U_BOOT_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06001159 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1160 b' somewhere in here', first)
Simon Glass72232452016-11-25 20:15:53 -07001161
Simon Glassbac25c82017-05-27 07:38:26 -06001162 def _RunPackUbootSingleMicrocode(self):
Simon Glass72232452016-11-25 20:15:53 -07001163 """Test that x86 microcode can be handled correctly
1164
1165 We expect to see the following in the image, in order:
1166 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1167 place
1168 u-boot.dtb with the microcode
1169 an empty microcode region
1170 """
1171 # We need the libfdt library to run this test since only that allows
1172 # finding the offset of a property. This is required by
1173 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass511f6582018-10-01 12:22:30 -06001174 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glass72232452016-11-25 20:15:53 -07001175
1176 second = data[len(U_BOOT_NODTB_DATA):]
1177
1178 fdt_len = self.GetFdtLen(second)
1179 third = second[fdt_len:]
1180 second = second[:fdt_len]
1181
Simon Glassbac25c82017-05-27 07:38:26 -06001182 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1183 self.assertIn(ucode_data, second)
1184 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glass72232452016-11-25 20:15:53 -07001185
Simon Glassbac25c82017-05-27 07:38:26 -06001186 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001187 # expected offset and size
Simon Glassbac25c82017-05-27 07:38:26 -06001188 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1189 len(ucode_data))
1190 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glass303f62f2019-05-17 22:00:46 -06001191 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1192 b' somewhere in here', first)
Simon Glass996021e2016-11-25 20:15:54 -07001193
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001194 def testPackUbootSingleMicrocode(self):
1195 """Test that x86 microcode can be handled correctly with fdt_normal.
1196 """
Simon Glassbac25c82017-05-27 07:38:26 -06001197 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001198
Simon Glass996021e2016-11-25 20:15:54 -07001199 def testUBootImg(self):
1200 """Test that u-boot.img can be put in a file"""
Simon Glass511f6582018-10-01 12:22:30 -06001201 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glass996021e2016-11-25 20:15:54 -07001202 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001203
1204 def testNoMicrocode(self):
1205 """Test that a missing microcode region is detected"""
1206 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001207 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001208 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1209 "node found in ", str(e.exception))
1210
1211 def testMicrocodeWithoutNode(self):
1212 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1213 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001214 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001215 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1216 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1217
1218 def testMicrocodeWithoutNode2(self):
1219 """Test that a missing u-boot-ucode node is detected"""
1220 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001221 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001222 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1223 "microcode region u-boot-ucode", str(e.exception))
1224
1225 def testMicrocodeWithoutPtrInElf(self):
1226 """Test that a U-Boot binary without the microcode symbol is detected"""
1227 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001228 try:
Simon Glassfaaaa162019-08-24 07:22:55 -06001229 TestFunctional._MakeInputFile('u-boot',
1230 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001231
1232 with self.assertRaises(ValueError) as e:
Simon Glassbac25c82017-05-27 07:38:26 -06001233 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001234 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1235 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1236
1237 finally:
1238 # Put the original file back
Simon Glass4affd4b2019-08-24 07:22:54 -06001239 TestFunctional._MakeInputFile('u-boot',
1240 tools.ReadFile(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001241
1242 def testMicrocodeNotInImage(self):
1243 """Test that microcode must be placed within the image"""
1244 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001245 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001246 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1247 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glassad5a7712018-06-01 09:38:14 -06001248 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001249
1250 def testWithoutMicrocode(self):
1251 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glassfaaaa162019-08-24 07:22:55 -06001252 TestFunctional._MakeInputFile('u-boot',
1253 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass511f6582018-10-01 12:22:30 -06001254 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001255
1256 # Now check the device tree has no microcode
1257 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1258 second = data[len(U_BOOT_NODTB_DATA):]
1259
1260 fdt_len = self.GetFdtLen(second)
1261 self.assertEqual(dtb, second[:fdt_len])
1262
1263 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1264 third = data[used_len:]
Simon Glassac0d4952019-05-14 15:53:47 -06001265 self.assertEqual(tools.GetBytes(0, 0x200 - used_len), third)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001266
1267 def testUnknownPosSize(self):
1268 """Test that microcode must be placed within the image"""
1269 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001270 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glasse8561af2018-08-01 15:22:37 -06001271 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001272 "entry 'invalid-entry'", str(e.exception))
Simon Glassb4176d42016-11-25 20:15:56 -07001273
1274 def testPackFsp(self):
1275 """Test that an image with a FSP binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001276 data = self._DoReadFile('042_intel_fsp.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001277 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1278
1279 def testPackCmc(self):
Bin Mengd7bcdf52017-08-15 22:41:54 -07001280 """Test that an image with a CMC binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001281 data = self._DoReadFile('043_intel_cmc.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001282 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Mengd7bcdf52017-08-15 22:41:54 -07001283
1284 def testPackVbt(self):
1285 """Test that an image with a VBT binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001286 data = self._DoReadFile('046_intel_vbt.dts')
Bin Mengd7bcdf52017-08-15 22:41:54 -07001287 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glassac599912017-11-12 21:52:22 -07001288
Simon Glass7f94e832017-11-12 21:52:25 -07001289 def testSplBssPad(self):
1290 """Test that we can pad SPL's BSS with zeros"""
Simon Glass3d274232017-11-12 21:52:27 -07001291 # ELF file with a '__bss_size' symbol
Simon Glass7057d022018-10-01 21:12:47 -06001292 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001293 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassac0d4952019-05-14 15:53:47 -06001294 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
1295 data)
Simon Glass7f94e832017-11-12 21:52:25 -07001296
Simon Glass04cda032018-10-01 21:12:42 -06001297 def testSplBssPadMissing(self):
1298 """Test that a missing symbol is detected"""
Simon Glass7057d022018-10-01 21:12:47 -06001299 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass24ad3652017-11-13 18:54:54 -07001300 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001301 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass24ad3652017-11-13 18:54:54 -07001302 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1303 str(e.exception))
1304
Simon Glasse83679d2017-11-12 21:52:26 -07001305 def testPackStart16Spl(self):
Simon Glassed40e962018-09-14 04:57:10 -06001306 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001307 data = self._DoReadFile('048_x86_start16_spl.dts')
Simon Glasse83679d2017-11-12 21:52:26 -07001308 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1309
Simon Glass6ba679c2018-07-06 10:27:17 -06001310 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1311 """Helper function for microcode tests
Simon Glass3d274232017-11-12 21:52:27 -07001312
1313 We expect to see the following in the image, in order:
1314 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1315 correct place
1316 u-boot.dtb with the microcode removed
1317 the microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001318
1319 Args:
1320 dts: Device tree file to use for test
1321 ucode_second: True if the microsecond entry is second instead of
1322 third
Simon Glass3d274232017-11-12 21:52:27 -07001323 """
Simon Glass7057d022018-10-01 21:12:47 -06001324 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass6ba679c2018-07-06 10:27:17 -06001325 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1326 ucode_second=ucode_second)
Simon Glass303f62f2019-05-17 22:00:46 -06001327 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1328 b'ter somewhere in here', first)
Simon Glass3d274232017-11-12 21:52:27 -07001329
Simon Glass6ba679c2018-07-06 10:27:17 -06001330 def testPackUbootSplMicrocode(self):
1331 """Test that x86 microcode can be handled correctly in SPL"""
Simon Glass511f6582018-10-01 12:22:30 -06001332 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass6ba679c2018-07-06 10:27:17 -06001333
1334 def testPackUbootSplMicrocodeReorder(self):
1335 """Test that order doesn't matter for microcode entries
1336
1337 This is the same as testPackUbootSplMicrocode but when we process the
1338 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1339 entry, so we reply on binman to try later.
1340 """
Simon Glass511f6582018-10-01 12:22:30 -06001341 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass6ba679c2018-07-06 10:27:17 -06001342 ucode_second=True)
1343
Simon Glassa409c932017-11-12 21:52:28 -07001344 def testPackMrc(self):
1345 """Test that an image with an MRC binary can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001346 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassa409c932017-11-12 21:52:28 -07001347 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1348
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001349 def testSplDtb(self):
1350 """Test that an image with spl/u-boot-spl.dtb can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001351 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001352 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1353
Simon Glass0a6da312017-11-13 18:54:56 -07001354 def testSplNoDtb(self):
1355 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12001356 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001357 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass0a6da312017-11-13 18:54:56 -07001358 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1359
Simon Glass7098b7f2021-03-21 18:24:30 +13001360 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
1361 use_expanded=False):
Simon Glass31e04cb2021-03-18 20:24:56 +13001362 """Check the image contains the expected symbol values
1363
1364 Args:
1365 dts: Device tree file to use for test
1366 base_data: Data before and after 'u-boot' section
1367 u_boot_offset: Offset of 'u-boot' section in image
Simon Glass7098b7f2021-03-21 18:24:30 +13001368 entry_args: Dict of entry args to supply to binman
1369 key: arg name
1370 value: value of that arg
1371 use_expanded: True to use expanded entries where available, e.g.
1372 'u-boot-expanded' instead of 'u-boot'
Simon Glass31e04cb2021-03-18 20:24:56 +13001373 """
Simon Glass5d0c0262019-08-24 07:22:56 -06001374 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass4ca8e042017-11-13 18:55:01 -07001375 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1376 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Simon Glass31e04cb2021-03-18 20:24:56 +13001377 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
1378 addr)
Simon Glass4ca8e042017-11-13 18:55:01 -07001379
Simon Glass7057d022018-10-01 21:12:47 -06001380 self._SetupSplElf('u_boot_binman_syms')
Simon Glass7098b7f2021-03-21 18:24:30 +13001381 data = self._DoReadFileDtb(dts, entry_args=entry_args,
1382 use_expanded=use_expanded)[0]
Simon Glass31e04cb2021-03-18 20:24:56 +13001383 # The image should contain the symbols from u_boot_binman_syms.c
1384 # Note that image_pos is adjusted by the base address of the image,
1385 # which is 0x10 in our test image
1386 sym_values = struct.pack('<LQLL', 0x00,
1387 u_boot_offset + len(U_BOOT_DATA),
1388 0x10 + u_boot_offset, 0x04)
1389 expected = (sym_values + base_data[20:] +
Simon Glassac0d4952019-05-14 15:53:47 -06001390 tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
Simon Glass31e04cb2021-03-18 20:24:56 +13001391 base_data[20:])
Simon Glass4ca8e042017-11-13 18:55:01 -07001392 self.assertEqual(expected, data)
1393
Simon Glass31e04cb2021-03-18 20:24:56 +13001394 def testSymbols(self):
1395 """Test binman can assign symbols embedded in U-Boot"""
1396 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x18)
1397
1398 def testSymbolsNoDtb(self):
1399 """Test binman can assign symbols embedded in U-Boot SPL"""
Simon Glass3bbc9932021-03-21 18:24:29 +13001400 self.checkSymbols('196_symbols_nodtb.dts',
Simon Glass31e04cb2021-03-18 20:24:56 +13001401 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1402 0x38)
1403
Simon Glasse76a3e62018-06-01 09:38:11 -06001404 def testPackUnitAddress(self):
1405 """Test that we support multiple binaries with the same name"""
Simon Glass511f6582018-10-01 12:22:30 -06001406 data = self._DoReadFile('054_unit_address.dts')
Simon Glasse76a3e62018-06-01 09:38:11 -06001407 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1408
Simon Glassa91e1152018-06-01 09:38:16 -06001409 def testSections(self):
1410 """Basic test of sections"""
Simon Glass511f6582018-10-01 12:22:30 -06001411 data = self._DoReadFile('055_sections.dts')
Simon Glass303f62f2019-05-17 22:00:46 -06001412 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1413 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
1414 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
Simon Glassa91e1152018-06-01 09:38:16 -06001415 self.assertEqual(expected, data)
Simon Glassac599912017-11-12 21:52:22 -07001416
Simon Glass30732662018-06-01 09:38:20 -06001417 def testMap(self):
1418 """Tests outputting a map of the images"""
Simon Glass511f6582018-10-01 12:22:30 -06001419 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001420 self.assertEqual('''ImagePos Offset Size Name
142100000000 00000000 00000028 main-section
142200000000 00000000 00000010 section@0
142300000000 00000000 00000004 u-boot
142400000010 00000010 00000010 section@1
142500000010 00000000 00000004 u-boot
142600000020 00000020 00000004 section@2
142700000020 00000000 00000004 u-boot
Simon Glass30732662018-06-01 09:38:20 -06001428''', map_data)
1429
Simon Glass3b78d532018-06-01 09:38:21 -06001430 def testNamePrefix(self):
1431 """Tests that name prefixes are used"""
Simon Glass511f6582018-10-01 12:22:30 -06001432 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001433 self.assertEqual('''ImagePos Offset Size Name
143400000000 00000000 00000028 main-section
143500000000 00000000 00000010 section@0
143600000000 00000000 00000004 ro-u-boot
143700000010 00000010 00000010 section@1
143800000010 00000000 00000004 rw-u-boot
Simon Glass3b78d532018-06-01 09:38:21 -06001439''', map_data)
1440
Simon Glass6ba679c2018-07-06 10:27:17 -06001441 def testUnknownContents(self):
1442 """Test that obtaining the contents works as expected"""
1443 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001444 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass39dd2152019-07-08 14:25:47 -06001445 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glassc585dd42020-04-17 18:09:03 -06001446 "processing of contents: remaining ["
1447 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass6ba679c2018-07-06 10:27:17 -06001448
Simon Glass2e1169f2018-07-06 10:27:19 -06001449 def testBadChangeSize(self):
1450 """Test that trying to change the size of an entry fails"""
Simon Glasse61b6f62019-07-08 14:25:37 -06001451 try:
1452 state.SetAllowEntryExpansion(False)
1453 with self.assertRaises(ValueError) as e:
1454 self._DoReadFile('059_change_size.dts', True)
Simon Glass8c702fb2019-07-20 12:23:57 -06001455 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glasse61b6f62019-07-08 14:25:37 -06001456 str(e.exception))
1457 finally:
1458 state.SetAllowEntryExpansion(True)
Simon Glass2e1169f2018-07-06 10:27:19 -06001459
Simon Glassa87014e2018-07-06 10:27:42 -06001460 def testUpdateFdt(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001461 """Test that we can update the device tree with offset/size info"""
Simon Glass511f6582018-10-01 12:22:30 -06001462 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glassa87014e2018-07-06 10:27:42 -06001463 update_dtb=True)
Simon Glass5463a6a2018-07-17 13:25:52 -06001464 dtb = fdt.Fdt(out_dtb_fname)
1465 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06001466 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glassa87014e2018-07-06 10:27:42 -06001467 self.assertEqual({
Simon Glass9dcc8612018-08-01 15:22:42 -06001468 'image-pos': 0,
Simon Glass3a9a2b82018-07-17 13:25:28 -06001469 'offset': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001470 '_testing:offset': 32,
Simon Glass8c702fb2019-07-20 12:23:57 -06001471 '_testing:size': 2,
Simon Glass9dcc8612018-08-01 15:22:42 -06001472 '_testing:image-pos': 32,
Simon Glasse8561af2018-08-01 15:22:37 -06001473 'section@0/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001474 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001475 'section@0/u-boot:image-pos': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001476 'section@0:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001477 'section@0:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001478 'section@0:image-pos': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001479
Simon Glasse8561af2018-08-01 15:22:37 -06001480 'section@1/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001481 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001482 'section@1/u-boot:image-pos': 16,
Simon Glasse8561af2018-08-01 15:22:37 -06001483 'section@1:offset': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001484 'section@1:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001485 'section@1:image-pos': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001486 'size': 40
1487 }, props)
1488
1489 def testUpdateFdtBad(self):
1490 """Test that we detect when ProcessFdt never completes"""
1491 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001492 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glassa87014e2018-07-06 10:27:42 -06001493 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glassc585dd42020-04-17 18:09:03 -06001494 '[<binman.etype._testing.Entry__testing',
1495 str(e.exception))
Simon Glass2e1169f2018-07-06 10:27:19 -06001496
Simon Glass91710b32018-07-17 13:25:32 -06001497 def testEntryArgs(self):
1498 """Test passing arguments to entries from the command line"""
1499 entry_args = {
1500 'test-str-arg': 'test1',
1501 'test-int-arg': '456',
1502 }
Simon Glass511f6582018-10-01 12:22:30 -06001503 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001504 self.assertIn('image', control.images)
1505 entry = control.images['image'].GetEntries()['_testing']
1506 self.assertEqual('test0', entry.test_str_fdt)
1507 self.assertEqual('test1', entry.test_str_arg)
1508 self.assertEqual(123, entry.test_int_fdt)
1509 self.assertEqual(456, entry.test_int_arg)
1510
1511 def testEntryArgsMissing(self):
1512 """Test missing arguments and properties"""
1513 entry_args = {
1514 'test-int-arg': '456',
1515 }
Simon Glass511f6582018-10-01 12:22:30 -06001516 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001517 entry = control.images['image'].GetEntries()['_testing']
1518 self.assertEqual('test0', entry.test_str_fdt)
1519 self.assertEqual(None, entry.test_str_arg)
1520 self.assertEqual(None, entry.test_int_fdt)
1521 self.assertEqual(456, entry.test_int_arg)
1522
1523 def testEntryArgsRequired(self):
1524 """Test missing arguments and properties"""
1525 entry_args = {
1526 'test-int-arg': '456',
1527 }
1528 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001529 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass21db0ff2020-09-01 05:13:54 -06001530 self.assertIn("Node '/binman/_testing': "
1531 'Missing required properties/entry args: test-str-arg, '
1532 'test-int-fdt, test-int-arg',
Simon Glass91710b32018-07-17 13:25:32 -06001533 str(e.exception))
1534
1535 def testEntryArgsInvalidFormat(self):
1536 """Test that an invalid entry-argument format is detected"""
Simon Glassf46732a2019-07-08 14:25:29 -06001537 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1538 '-ano-value']
Simon Glass91710b32018-07-17 13:25:32 -06001539 with self.assertRaises(ValueError) as e:
1540 self._DoBinman(*args)
1541 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1542
1543 def testEntryArgsInvalidInteger(self):
1544 """Test that an invalid entry-argument integer is detected"""
1545 entry_args = {
1546 'test-int-arg': 'abc',
1547 }
1548 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001549 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001550 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1551 "'test-int-arg' (value 'abc') to integer",
1552 str(e.exception))
1553
1554 def testEntryArgsInvalidDatatype(self):
1555 """Test that an invalid entry-argument datatype is detected
1556
1557 This test could be written in entry_test.py except that it needs
1558 access to control.entry_args, which seems more than that module should
1559 be able to see.
1560 """
1561 entry_args = {
1562 'test-bad-datatype-arg': '12',
1563 }
1564 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001565 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass91710b32018-07-17 13:25:32 -06001566 entry_args=entry_args)
1567 self.assertIn('GetArg() internal error: Unknown data type ',
1568 str(e.exception))
1569
Simon Glass2ca52032018-07-17 13:25:33 -06001570 def testText(self):
1571 """Test for a text entry type"""
1572 entry_args = {
1573 'test-id': TEXT_DATA,
1574 'test-id2': TEXT_DATA2,
1575 'test-id3': TEXT_DATA3,
1576 }
Simon Glass511f6582018-10-01 12:22:30 -06001577 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glass2ca52032018-07-17 13:25:33 -06001578 entry_args=entry_args)
Simon Glass303f62f2019-05-17 22:00:46 -06001579 expected = (tools.ToBytes(TEXT_DATA) +
1580 tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1581 tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
Simon Glass47f6a622019-07-08 13:18:40 -06001582 b'some text' + b'more text')
Simon Glass2ca52032018-07-17 13:25:33 -06001583 self.assertEqual(expected, data)
1584
Simon Glass969616c2018-07-17 13:25:36 -06001585 def testEntryDocs(self):
1586 """Test for creation of entry documentation"""
1587 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001588 control.WriteEntryDocs(control.GetEntryModules())
Simon Glass969616c2018-07-17 13:25:36 -06001589 self.assertTrue(len(stdout.getvalue()) > 0)
1590
1591 def testEntryDocsMissing(self):
1592 """Test handling of missing entry documentation"""
1593 with self.assertRaises(ValueError) as e:
1594 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001595 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glass969616c2018-07-17 13:25:36 -06001596 self.assertIn('Documentation is missing for modules: u_boot',
1597 str(e.exception))
1598
Simon Glass704784b2018-07-17 13:25:38 -06001599 def testFmap(self):
1600 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06001601 data = self._DoReadFile('067_fmap.dts')
Simon Glass704784b2018-07-17 13:25:38 -06001602 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass303f62f2019-05-17 22:00:46 -06001603 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1604 U_BOOT_DATA + tools.GetBytes(ord('a'), 12))
Simon Glass704784b2018-07-17 13:25:38 -06001605 self.assertEqual(expected, data[:32])
Simon Glass303f62f2019-05-17 22:00:46 -06001606 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass704784b2018-07-17 13:25:38 -06001607 self.assertEqual(1, fhdr.ver_major)
1608 self.assertEqual(0, fhdr.ver_minor)
1609 self.assertEqual(0, fhdr.base)
Simon Glassb1d414c2021-04-03 11:05:10 +13001610 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 5
Simon Glass82059c22021-04-03 11:05:09 +13001611 self.assertEqual(16 + 16 + expect_size, fhdr.image_size)
Simon Glass303f62f2019-05-17 22:00:46 -06001612 self.assertEqual(b'FMAP', fhdr.name)
Simon Glassb1d414c2021-04-03 11:05:10 +13001613 self.assertEqual(5, fhdr.nareas)
Simon Glass82059c22021-04-03 11:05:09 +13001614 fiter = iter(fentries)
Simon Glass704784b2018-07-17 13:25:38 -06001615
Simon Glass82059c22021-04-03 11:05:09 +13001616 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001617 self.assertEqual(b'SECTION0', fentry.name)
1618 self.assertEqual(0, fentry.offset)
1619 self.assertEqual(16, fentry.size)
1620 self.assertEqual(0, fentry.flags)
1621
1622 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001623 self.assertEqual(b'RO_U_BOOT', fentry.name)
1624 self.assertEqual(0, fentry.offset)
1625 self.assertEqual(4, fentry.size)
1626 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001627
Simon Glass82059c22021-04-03 11:05:09 +13001628 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001629 self.assertEqual(b'SECTION1', fentry.name)
1630 self.assertEqual(16, fentry.offset)
1631 self.assertEqual(16, fentry.size)
1632 self.assertEqual(0, fentry.flags)
1633
1634 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001635 self.assertEqual(b'RW_U_BOOT', fentry.name)
1636 self.assertEqual(16, fentry.offset)
1637 self.assertEqual(4, fentry.size)
1638 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001639
Simon Glass82059c22021-04-03 11:05:09 +13001640 fentry = next(fiter)
1641 self.assertEqual(b'FMAP', fentry.name)
1642 self.assertEqual(32, fentry.offset)
1643 self.assertEqual(expect_size, fentry.size)
1644 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001645
Simon Glassdb168d42018-07-17 13:25:39 -06001646 def testBlobNamedByArg(self):
1647 """Test we can add a blob with the filename coming from an entry arg"""
1648 entry_args = {
1649 'cros-ec-rw-path': 'ecrw.bin',
1650 }
Simon Glass21db0ff2020-09-01 05:13:54 -06001651 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassdb168d42018-07-17 13:25:39 -06001652
Simon Glass53f53992018-07-17 13:25:40 -06001653 def testFill(self):
1654 """Test for an fill entry type"""
Simon Glass511f6582018-10-01 12:22:30 -06001655 data = self._DoReadFile('069_fill.dts')
Simon Glassac0d4952019-05-14 15:53:47 -06001656 expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
Simon Glass53f53992018-07-17 13:25:40 -06001657 self.assertEqual(expected, data)
1658
1659 def testFillNoSize(self):
1660 """Test for an fill entry type with no size"""
1661 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001662 self._DoReadFile('070_fill_no_size.dts')
Simon Glass53f53992018-07-17 13:25:40 -06001663 self.assertIn("'fill' entry must have a size property",
1664 str(e.exception))
1665
Simon Glassc1ae83c2018-07-17 13:25:44 -06001666 def _HandleGbbCommand(self, pipe_list):
1667 """Fake calls to the futility utility"""
1668 if pipe_list[0][0] == 'futility':
1669 fname = pipe_list[0][-1]
1670 # Append our GBB data to the file, which will happen every time the
1671 # futility command is called.
Simon Glass33486662019-05-14 15:53:42 -06001672 with open(fname, 'ab') as fd:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001673 fd.write(GBB_DATA)
1674 return command.CommandResult()
1675
1676 def testGbb(self):
1677 """Test for the Chromium OS Google Binary Block"""
1678 command.test_result = self._HandleGbbCommand
1679 entry_args = {
1680 'keydir': 'devkeys',
1681 'bmpblk': 'bmpblk.bin',
1682 }
Simon Glass511f6582018-10-01 12:22:30 -06001683 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glassc1ae83c2018-07-17 13:25:44 -06001684
1685 # Since futility
Simon Glassac0d4952019-05-14 15:53:47 -06001686 expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1687 tools.GetBytes(0, 0x2180 - 16))
Simon Glassc1ae83c2018-07-17 13:25:44 -06001688 self.assertEqual(expected, data)
1689
1690 def testGbbTooSmall(self):
1691 """Test for the Chromium OS Google Binary Block being large enough"""
1692 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001693 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001694 self.assertIn("Node '/binman/gbb': GBB is too small",
1695 str(e.exception))
1696
1697 def testGbbNoSize(self):
1698 """Test for the Chromium OS Google Binary Block having a size"""
1699 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001700 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001701 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1702 str(e.exception))
1703
Simon Glass5c350162018-07-17 13:25:47 -06001704 def _HandleVblockCommand(self, pipe_list):
Simon Glass220c6222021-01-06 21:35:17 -07001705 """Fake calls to the futility utility
1706
1707 The expected pipe is:
1708
1709 [('futility', 'vbutil_firmware', '--vblock',
1710 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1711 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1712 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1713 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1714
1715 This writes to the output file (here, 'vblock.vblock'). If
1716 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1717 of the input data (here, 'input.vblock').
1718 """
Simon Glass5c350162018-07-17 13:25:47 -06001719 if pipe_list[0][0] == 'futility':
1720 fname = pipe_list[0][3]
Simon Glass639505b2018-09-14 04:57:11 -06001721 with open(fname, 'wb') as fd:
Simon Glass220c6222021-01-06 21:35:17 -07001722 if self._hash_data:
1723 infile = pipe_list[0][11]
1724 m = hashlib.sha256()
1725 data = tools.ReadFile(infile)
1726 m.update(data)
1727 fd.write(m.digest())
1728 else:
1729 fd.write(VBLOCK_DATA)
1730
Simon Glass5c350162018-07-17 13:25:47 -06001731 return command.CommandResult()
1732
1733 def testVblock(self):
1734 """Test for the Chromium OS Verified Boot Block"""
Simon Glass220c6222021-01-06 21:35:17 -07001735 self._hash_data = False
Simon Glass5c350162018-07-17 13:25:47 -06001736 command.test_result = self._HandleVblockCommand
1737 entry_args = {
1738 'keydir': 'devkeys',
1739 }
Simon Glass511f6582018-10-01 12:22:30 -06001740 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass5c350162018-07-17 13:25:47 -06001741 entry_args=entry_args)
1742 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1743 self.assertEqual(expected, data)
1744
1745 def testVblockNoContent(self):
1746 """Test we detect a vblock which has no content to sign"""
1747 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001748 self._DoReadFile('075_vblock_no_content.dts')
Simon Glasse1915782021-03-21 18:24:31 +13001749 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
Simon Glass5c350162018-07-17 13:25:47 -06001750 'property', str(e.exception))
1751
1752 def testVblockBadPhandle(self):
1753 """Test that we detect a vblock with an invalid phandle in contents"""
1754 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001755 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001756 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1757 '1000', str(e.exception))
1758
1759 def testVblockBadEntry(self):
1760 """Test that we detect an entry that points to a non-entry"""
1761 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001762 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001763 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1764 "'other'", str(e.exception))
1765
Simon Glass220c6222021-01-06 21:35:17 -07001766 def testVblockContent(self):
1767 """Test that the vblock signs the right data"""
1768 self._hash_data = True
1769 command.test_result = self._HandleVblockCommand
1770 entry_args = {
1771 'keydir': 'devkeys',
1772 }
1773 data = self._DoReadFileDtb(
1774 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1775 entry_args=entry_args)[0]
1776 hashlen = 32 # SHA256 hash is 32 bytes
1777 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1778 hashval = data[-hashlen:]
1779 dtb = data[len(U_BOOT_DATA):-hashlen]
1780
1781 expected_data = U_BOOT_DATA + dtb
1782
1783 # The hashval should be a hash of the dtb
1784 m = hashlib.sha256()
1785 m.update(expected_data)
1786 expected_hashval = m.digest()
1787 self.assertEqual(expected_hashval, hashval)
1788
Simon Glass8425a1f2018-07-17 13:25:48 -06001789 def testTpl(self):
Simon Glass3eb5b202019-08-24 07:23:00 -06001790 """Test that an image with TPL and its device tree can be created"""
Simon Glass8425a1f2018-07-17 13:25:48 -06001791 # ELF file with a '__bss_size' symbol
Simon Glass3eb5b202019-08-24 07:23:00 -06001792 self._SetupTplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001793 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glass8425a1f2018-07-17 13:25:48 -06001794 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1795
Simon Glass24b97442018-07-17 13:25:51 -06001796 def testUsesPos(self):
1797 """Test that the 'pos' property cannot be used anymore"""
1798 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001799 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass24b97442018-07-17 13:25:51 -06001800 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1801 "'pos'", str(e.exception))
1802
Simon Glass274bf092018-09-14 04:57:08 -06001803 def testFillZero(self):
1804 """Test for an fill entry type with a size of 0"""
Simon Glass511f6582018-10-01 12:22:30 -06001805 data = self._DoReadFile('080_fill_empty.dts')
Simon Glassac0d4952019-05-14 15:53:47 -06001806 self.assertEqual(tools.GetBytes(0, 16), data)
Simon Glass274bf092018-09-14 04:57:08 -06001807
Simon Glass267de432018-09-14 04:57:09 -06001808 def testTextMissing(self):
1809 """Test for a text entry type where there is no text"""
1810 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001811 self._DoReadFileDtb('066_text.dts',)
Simon Glass267de432018-09-14 04:57:09 -06001812 self.assertIn("Node '/binman/text': No value provided for text label "
1813 "'test-id'", str(e.exception))
1814
Simon Glassed40e962018-09-14 04:57:10 -06001815 def testPackStart16Tpl(self):
1816 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001817 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glassed40e962018-09-14 04:57:10 -06001818 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1819
Simon Glass3b376c32018-09-14 04:57:12 -06001820 def testSelectImage(self):
1821 """Test that we can select which images to build"""
Simon Glassb4595d82019-04-25 21:58:34 -06001822 expected = 'Skipping images: image1'
1823
1824 # We should only get the expected message in verbose mode
Simon Glass8a50b4a2019-07-08 13:18:48 -06001825 for verbosity in (0, 2):
Simon Glassb4595d82019-04-25 21:58:34 -06001826 with test_util.capture_sys_output() as (stdout, stderr):
1827 retcode = self._DoTestFile('006_dual_image.dts',
1828 verbosity=verbosity,
1829 images=['image2'])
1830 self.assertEqual(0, retcode)
1831 if verbosity:
1832 self.assertIn(expected, stdout.getvalue())
1833 else:
1834 self.assertNotIn(expected, stdout.getvalue())
Simon Glass3b376c32018-09-14 04:57:12 -06001835
Simon Glassb4595d82019-04-25 21:58:34 -06001836 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1837 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
Simon Glassb3d6fc72019-07-20 12:24:10 -06001838 self._CleanupOutputDir()
Simon Glass3b376c32018-09-14 04:57:12 -06001839
Simon Glasse219aa42018-09-14 04:57:24 -06001840 def testUpdateFdtAll(self):
1841 """Test that all device trees are updated with offset/size info"""
Simon Glass5b4bce32019-07-08 14:25:26 -06001842 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glasse219aa42018-09-14 04:57:24 -06001843
1844 base_expected = {
1845 'section:image-pos': 0,
1846 'u-boot-tpl-dtb:size': 513,
1847 'u-boot-spl-dtb:size': 513,
1848 'u-boot-spl-dtb:offset': 493,
1849 'image-pos': 0,
1850 'section/u-boot-dtb:image-pos': 0,
1851 'u-boot-spl-dtb:image-pos': 493,
1852 'section/u-boot-dtb:size': 493,
1853 'u-boot-tpl-dtb:image-pos': 1006,
1854 'section/u-boot-dtb:offset': 0,
1855 'section:size': 493,
1856 'offset': 0,
1857 'section:offset': 0,
1858 'u-boot-tpl-dtb:offset': 1006,
1859 'size': 1519
1860 }
1861
1862 # We expect three device-tree files in the output, one after the other.
1863 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1864 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1865 # main U-Boot tree. All three should have the same postions and offset.
1866 start = 0
1867 for item in ['', 'spl', 'tpl']:
1868 dtb = fdt.Fdt.FromData(data[start:])
1869 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06001870 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
1871 ['spl', 'tpl'])
Simon Glasse219aa42018-09-14 04:57:24 -06001872 expected = dict(base_expected)
1873 if item:
1874 expected[item] = 0
1875 self.assertEqual(expected, props)
1876 start += dtb._fdt_obj.totalsize()
1877
1878 def testUpdateFdtOutput(self):
1879 """Test that output DTB files are updated"""
1880 try:
Simon Glass511f6582018-10-01 12:22:30 -06001881 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glasse219aa42018-09-14 04:57:24 -06001882 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1883
1884 # Unfortunately, compiling a source file always results in a file
1885 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass511f6582018-10-01 12:22:30 -06001886 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glasse219aa42018-09-14 04:57:24 -06001887 # binman as a file called u-boot.dtb. To fix this, copy the file
1888 # over to the expected place.
Simon Glasse219aa42018-09-14 04:57:24 -06001889 start = 0
1890 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1891 'tpl/u-boot-tpl.dtb.out']:
1892 dtb = fdt.Fdt.FromData(data[start:])
1893 size = dtb._fdt_obj.totalsize()
1894 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1895 outdata = tools.ReadFile(pathname)
1896 name = os.path.split(fname)[0]
1897
1898 if name:
1899 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1900 else:
1901 orig_indata = dtb_data
1902 self.assertNotEqual(outdata, orig_indata,
1903 "Expected output file '%s' be updated" % pathname)
1904 self.assertEqual(outdata, data[start:start + size],
1905 "Expected output file '%s' to match output image" %
1906 pathname)
1907 start += size
1908 finally:
1909 self._ResetDtbs()
1910
Simon Glass7ba33592018-09-14 04:57:26 -06001911 def _decompress(self, data):
Simon Glassccec0262019-07-08 13:18:42 -06001912 return tools.Decompress(data, 'lz4')
Simon Glass7ba33592018-09-14 04:57:26 -06001913
1914 def testCompress(self):
1915 """Test compression of blobs"""
Simon Glass1de34482019-07-08 13:18:53 -06001916 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06001917 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass7ba33592018-09-14 04:57:26 -06001918 use_real_dtb=True, update_dtb=True)
1919 dtb = fdt.Fdt(out_dtb_fname)
1920 dtb.Scan()
1921 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1922 orig = self._decompress(data)
1923 self.assertEquals(COMPRESS_DATA, orig)
Simon Glass789b34402020-10-26 17:40:15 -06001924
1925 # Do a sanity check on various fields
1926 image = control.images['image']
1927 entries = image.GetEntries()
1928 self.assertEqual(1, len(entries))
1929
1930 entry = entries['blob']
1931 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
1932 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
1933 orig = self._decompress(entry.data)
1934 self.assertEqual(orig, entry.uncomp_data)
1935
Simon Glass72eeff12020-10-26 17:40:16 -06001936 self.assertEqual(image.data, entry.data)
1937
Simon Glass7ba33592018-09-14 04:57:26 -06001938 expected = {
1939 'blob:uncomp-size': len(COMPRESS_DATA),
1940 'blob:size': len(data),
1941 'size': len(data),
1942 }
1943 self.assertEqual(expected, props)
1944
Simon Glassac6328c2018-09-14 04:57:28 -06001945 def testFiles(self):
1946 """Test bringing in multiple files"""
Simon Glass511f6582018-10-01 12:22:30 -06001947 data = self._DoReadFile('084_files.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06001948 self.assertEqual(FILES_DATA, data)
1949
1950 def testFilesCompress(self):
1951 """Test bringing in multiple files and compressing them"""
Simon Glass1de34482019-07-08 13:18:53 -06001952 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06001953 data = self._DoReadFile('085_files_compress.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06001954
1955 image = control.images['image']
1956 entries = image.GetEntries()
1957 files = entries['files']
Simon Glass39dd2152019-07-08 14:25:47 -06001958 entries = files._entries
Simon Glassac6328c2018-09-14 04:57:28 -06001959
Simon Glass303f62f2019-05-17 22:00:46 -06001960 orig = b''
Simon Glassac6328c2018-09-14 04:57:28 -06001961 for i in range(1, 3):
1962 key = '%d.dat' % i
1963 start = entries[key].image_pos
1964 len = entries[key].size
1965 chunk = data[start:start + len]
1966 orig += self._decompress(chunk)
1967
1968 self.assertEqual(FILES_DATA, orig)
1969
1970 def testFilesMissing(self):
1971 """Test missing files"""
1972 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001973 data = self._DoReadFile('086_files_none.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06001974 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1975 'no files', str(e.exception))
1976
1977 def testFilesNoPattern(self):
1978 """Test missing files"""
1979 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001980 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06001981 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1982 str(e.exception))
1983
Simon Glassfa79a812018-09-14 04:57:29 -06001984 def testExpandSize(self):
1985 """Test an expanding entry"""
Simon Glass511f6582018-10-01 12:22:30 -06001986 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
Simon Glassfa79a812018-09-14 04:57:29 -06001987 map=True)
Simon Glass303f62f2019-05-17 22:00:46 -06001988 expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA +
1989 MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA +
1990 tools.GetBytes(ord('c'), 8) + U_BOOT_DATA +
1991 tools.GetBytes(ord('d'), 8))
Simon Glassfa79a812018-09-14 04:57:29 -06001992 self.assertEqual(expect, data)
1993 self.assertEqual('''ImagePos Offset Size Name
199400000000 00000000 00000028 main-section
199500000000 00000000 00000008 fill
199600000008 00000008 00000004 u-boot
19970000000c 0000000c 00000004 section
19980000000c 00000000 00000003 intel-mrc
199900000010 00000010 00000004 u-boot2
200000000014 00000014 0000000c section2
200100000014 00000000 00000008 fill
20020000001c 00000008 00000004 u-boot
200300000020 00000020 00000008 fill2
2004''', map_data)
2005
2006 def testExpandSizeBad(self):
2007 """Test an expanding entry which fails to provide contents"""
Simon Glasscd817d52018-09-14 04:57:36 -06002008 with test_util.capture_sys_output() as (stdout, stderr):
2009 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002010 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
Simon Glassfa79a812018-09-14 04:57:29 -06002011 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
2012 'expanding entry', str(e.exception))
2013
Simon Glassae7cf032018-09-14 04:57:31 -06002014 def testHash(self):
2015 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002016 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002017 use_real_dtb=True, update_dtb=True)
2018 dtb = fdt.Fdt(out_dtb_fname)
2019 dtb.Scan()
2020 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
2021 m = hashlib.sha256()
2022 m.update(U_BOOT_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002023 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002024
2025 def testHashNoAlgo(self):
2026 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002027 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glassae7cf032018-09-14 04:57:31 -06002028 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2029 'hash node', str(e.exception))
2030
2031 def testHashBadAlgo(self):
2032 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002033 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glassae7cf032018-09-14 04:57:31 -06002034 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
2035 str(e.exception))
2036
2037 def testHashSection(self):
2038 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002039 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002040 use_real_dtb=True, update_dtb=True)
2041 dtb = fdt.Fdt(out_dtb_fname)
2042 dtb.Scan()
2043 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2044 m = hashlib.sha256()
2045 m.update(U_BOOT_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002046 m.update(tools.GetBytes(ord('a'), 16))
2047 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002048
Simon Glass3fb4f422018-09-14 04:57:32 -06002049 def testPackUBootTplMicrocode(self):
2050 """Test that x86 microcode can be handled correctly in TPL
2051
2052 We expect to see the following in the image, in order:
2053 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2054 place
2055 u-boot-tpl.dtb with the microcode removed
2056 the microcode
2057 """
Simon Glass3eb5b202019-08-24 07:23:00 -06002058 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass511f6582018-10-01 12:22:30 -06002059 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glass3fb4f422018-09-14 04:57:32 -06002060 U_BOOT_TPL_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002061 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2062 b'ter somewhere in here', first)
Simon Glass3fb4f422018-09-14 04:57:32 -06002063
Simon Glassc64aea52018-09-14 04:57:34 -06002064 def testFmapX86(self):
2065 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002066 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassc64aea52018-09-14 04:57:34 -06002067 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass303f62f2019-05-17 22:00:46 -06002068 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002069 self.assertEqual(expected, data[:32])
2070 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2071
2072 self.assertEqual(0x100, fhdr.image_size)
2073
2074 self.assertEqual(0, fentries[0].offset)
2075 self.assertEqual(4, fentries[0].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002076 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002077
2078 self.assertEqual(4, fentries[1].offset)
2079 self.assertEqual(3, fentries[1].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002080 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002081
2082 self.assertEqual(32, fentries[2].offset)
2083 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2084 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002085 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002086
2087 def testFmapX86Section(self):
2088 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002089 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glass303f62f2019-05-17 22:00:46 -06002090 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002091 self.assertEqual(expected, data[:32])
2092 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2093
Simon Glassb1d414c2021-04-03 11:05:10 +13002094 self.assertEqual(0x180, fhdr.image_size)
2095 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
Simon Glass82059c22021-04-03 11:05:09 +13002096 fiter = iter(fentries)
Simon Glassc64aea52018-09-14 04:57:34 -06002097
Simon Glass82059c22021-04-03 11:05:09 +13002098 fentry = next(fiter)
2099 self.assertEqual(b'U_BOOT', fentry.name)
2100 self.assertEqual(0, fentry.offset)
2101 self.assertEqual(4, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002102
Simon Glass82059c22021-04-03 11:05:09 +13002103 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13002104 self.assertEqual(b'SECTION', fentry.name)
2105 self.assertEqual(4, fentry.offset)
2106 self.assertEqual(0x20 + expect_size, fentry.size)
2107
2108 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13002109 self.assertEqual(b'INTEL_MRC', fentry.name)
2110 self.assertEqual(4, fentry.offset)
2111 self.assertEqual(3, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002112
Simon Glass82059c22021-04-03 11:05:09 +13002113 fentry = next(fiter)
2114 self.assertEqual(b'FMAP', fentry.name)
2115 self.assertEqual(36, fentry.offset)
2116 self.assertEqual(expect_size, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002117
Simon Glassb1714232018-09-14 04:57:35 -06002118 def testElf(self):
2119 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002120 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002121 self._SetupTplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002122 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002123 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002124 data = self._DoReadFile('096_elf.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002125
Simon Glass0d673792019-07-08 13:18:25 -06002126 def testElfStrip(self):
Simon Glassb1714232018-09-14 04:57:35 -06002127 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002128 self._SetupSplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002129 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002130 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002131 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002132
Simon Glasscd817d52018-09-14 04:57:36 -06002133 def testPackOverlapMap(self):
2134 """Test that overlapping regions are detected"""
2135 with test_util.capture_sys_output() as (stdout, stderr):
2136 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002137 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glasscd817d52018-09-14 04:57:36 -06002138 map_fname = tools.GetOutputFilename('image.map')
2139 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2140 stdout.getvalue())
2141
2142 # We should not get an inmage, but there should be a map file
2143 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
2144 self.assertTrue(os.path.exists(map_fname))
Simon Glassb3774752019-05-17 22:00:51 -06002145 map_data = tools.ReadFile(map_fname, binary=False)
Simon Glasscd817d52018-09-14 04:57:36 -06002146 self.assertEqual('''ImagePos Offset Size Name
Simon Glassd99850b2020-10-26 17:40:24 -06002147<none> 00000000 00000008 main-section
Simon Glasscd817d52018-09-14 04:57:36 -06002148<none> 00000000 00000004 u-boot
2149<none> 00000003 00000004 u-boot-align
2150''', map_data)
2151
Simon Glass0d673792019-07-08 13:18:25 -06002152 def testPackRefCode(self):
Simon Glass41902e42018-10-01 12:22:31 -06002153 """Test that an image with an Intel Reference code binary works"""
2154 data = self._DoReadFile('100_intel_refcode.dts')
2155 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2156
Simon Glasseb023b32019-04-25 21:58:39 -06002157 def testSectionOffset(self):
2158 """Tests use of a section with an offset"""
2159 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2160 map=True)
2161 self.assertEqual('''ImagePos Offset Size Name
216200000000 00000000 00000038 main-section
216300000004 00000004 00000010 section@0
216400000004 00000000 00000004 u-boot
216500000018 00000018 00000010 section@1
216600000018 00000000 00000004 u-boot
21670000002c 0000002c 00000004 section@2
21680000002c 00000000 00000004 u-boot
2169''', map_data)
2170 self.assertEqual(data,
Simon Glassac0d4952019-05-14 15:53:47 -06002171 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2172 tools.GetBytes(0x21, 12) +
2173 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2174 tools.GetBytes(0x61, 12) +
2175 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2176 tools.GetBytes(0x26, 8))
Simon Glasseb023b32019-04-25 21:58:39 -06002177
Simon Glass1de34482019-07-08 13:18:53 -06002178 def testCbfsRaw(self):
2179 """Test base handling of a Coreboot Filesystem (CBFS)
2180
2181 The exact contents of the CBFS is verified by similar tests in
2182 cbfs_util_test.py. The tests here merely check that the files added to
2183 the CBFS can be found in the final image.
2184 """
2185 data = self._DoReadFile('102_cbfs_raw.dts')
2186 size = 0xb0
2187
2188 cbfs = cbfs_util.CbfsReader(data)
2189 self.assertEqual(size, cbfs.rom_size)
2190
2191 self.assertIn('u-boot-dtb', cbfs.files)
2192 cfile = cbfs.files['u-boot-dtb']
2193 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2194
2195 def testCbfsArch(self):
2196 """Test on non-x86 architecture"""
2197 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2198 size = 0x100
2199
2200 cbfs = cbfs_util.CbfsReader(data)
2201 self.assertEqual(size, cbfs.rom_size)
2202
2203 self.assertIn('u-boot-dtb', cbfs.files)
2204 cfile = cbfs.files['u-boot-dtb']
2205 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2206
2207 def testCbfsStage(self):
2208 """Tests handling of a Coreboot Filesystem (CBFS)"""
2209 if not elf.ELF_TOOLS:
2210 self.skipTest('Python elftools not available')
2211 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2212 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2213 size = 0xb0
2214
2215 data = self._DoReadFile('104_cbfs_stage.dts')
2216 cbfs = cbfs_util.CbfsReader(data)
2217 self.assertEqual(size, cbfs.rom_size)
2218
2219 self.assertIn('u-boot', cbfs.files)
2220 cfile = cbfs.files['u-boot']
2221 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2222
2223 def testCbfsRawCompress(self):
2224 """Test handling of compressing raw files"""
2225 self._CheckLz4()
2226 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2227 size = 0x140
2228
2229 cbfs = cbfs_util.CbfsReader(data)
2230 self.assertIn('u-boot', cbfs.files)
2231 cfile = cbfs.files['u-boot']
2232 self.assertEqual(COMPRESS_DATA, cfile.data)
2233
2234 def testCbfsBadArch(self):
2235 """Test handling of a bad architecture"""
2236 with self.assertRaises(ValueError) as e:
2237 self._DoReadFile('106_cbfs_bad_arch.dts')
2238 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2239
2240 def testCbfsNoSize(self):
2241 """Test handling of a missing size property"""
2242 with self.assertRaises(ValueError) as e:
2243 self._DoReadFile('107_cbfs_no_size.dts')
2244 self.assertIn('entry must have a size property', str(e.exception))
2245
2246 def testCbfsNoCOntents(self):
2247 """Test handling of a CBFS entry which does not provide contentsy"""
2248 with self.assertRaises(ValueError) as e:
2249 self._DoReadFile('108_cbfs_no_contents.dts')
2250 self.assertIn('Could not complete processing of contents',
2251 str(e.exception))
2252
2253 def testCbfsBadCompress(self):
2254 """Test handling of a bad architecture"""
2255 with self.assertRaises(ValueError) as e:
2256 self._DoReadFile('109_cbfs_bad_compress.dts')
2257 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2258 str(e.exception))
2259
2260 def testCbfsNamedEntries(self):
2261 """Test handling of named entries"""
2262 data = self._DoReadFile('110_cbfs_name.dts')
2263
2264 cbfs = cbfs_util.CbfsReader(data)
2265 self.assertIn('FRED', cbfs.files)
2266 cfile1 = cbfs.files['FRED']
2267 self.assertEqual(U_BOOT_DATA, cfile1.data)
2268
2269 self.assertIn('hello', cbfs.files)
2270 cfile2 = cbfs.files['hello']
2271 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2272
Simon Glass759af872019-07-08 13:18:54 -06002273 def _SetupIfwi(self, fname):
2274 """Set up to run an IFWI test
2275
2276 Args:
2277 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2278 """
2279 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002280 self._SetupTplElf()
Simon Glass759af872019-07-08 13:18:54 -06002281
2282 # Intel Integrated Firmware Image (IFWI) file
2283 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2284 data = fd.read()
2285 TestFunctional._MakeInputFile(fname,data)
2286
2287 def _CheckIfwi(self, data):
2288 """Check that an image with an IFWI contains the correct output
2289
2290 Args:
2291 data: Conents of output file
2292 """
2293 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
2294 if data[:0x1000] != expected_desc:
2295 self.fail('Expected descriptor binary at start of image')
2296
2297 # We expect to find the TPL wil in subpart IBBP entry IBBL
2298 image_fname = tools.GetOutputFilename('image.bin')
2299 tpl_fname = tools.GetOutputFilename('tpl.out')
2300 tools.RunIfwiTool(image_fname, tools.CMD_EXTRACT, fname=tpl_fname,
2301 subpart='IBBP', entry_name='IBBL')
2302
2303 tpl_data = tools.ReadFile(tpl_fname)
Simon Glassf55bd692019-08-24 07:22:51 -06002304 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glass759af872019-07-08 13:18:54 -06002305
2306 def testPackX86RomIfwi(self):
2307 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2308 self._SetupIfwi('fitimage.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002309 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glass759af872019-07-08 13:18:54 -06002310 self._CheckIfwi(data)
2311
2312 def testPackX86RomIfwiNoDesc(self):
2313 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2314 self._SetupIfwi('ifwi.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002315 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glass759af872019-07-08 13:18:54 -06002316 self._CheckIfwi(data)
2317
2318 def testPackX86RomIfwiNoData(self):
2319 """Test that an x86 ROM with IFWI handles missing data"""
2320 self._SetupIfwi('ifwi.bin')
2321 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06002322 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glass759af872019-07-08 13:18:54 -06002323 self.assertIn('Could not complete processing of contents',
2324 str(e.exception))
Simon Glass91710b32018-07-17 13:25:32 -06002325
Simon Glassc2f1aed2019-07-08 13:18:56 -06002326 def testCbfsOffset(self):
2327 """Test a CBFS with files at particular offsets
2328
2329 Like all CFBS tests, this is just checking the logic that calls
2330 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2331 """
2332 data = self._DoReadFile('114_cbfs_offset.dts')
2333 size = 0x200
2334
2335 cbfs = cbfs_util.CbfsReader(data)
2336 self.assertEqual(size, cbfs.rom_size)
2337
2338 self.assertIn('u-boot', cbfs.files)
2339 cfile = cbfs.files['u-boot']
2340 self.assertEqual(U_BOOT_DATA, cfile.data)
2341 self.assertEqual(0x40, cfile.cbfs_offset)
2342
2343 self.assertIn('u-boot-dtb', cbfs.files)
2344 cfile2 = cbfs.files['u-boot-dtb']
2345 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2346 self.assertEqual(0x140, cfile2.cbfs_offset)
2347
Simon Glass0f621332019-07-08 14:25:27 -06002348 def testFdtmap(self):
2349 """Test an FDT map can be inserted in the image"""
2350 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2351 fdtmap_data = data[len(U_BOOT_DATA):]
2352 magic = fdtmap_data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002353 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass0f621332019-07-08 14:25:27 -06002354 self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
2355
2356 fdt_data = fdtmap_data[16:]
2357 dtb = fdt.Fdt.FromData(fdt_data)
2358 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002359 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass0f621332019-07-08 14:25:27 -06002360 self.assertEqual({
2361 'image-pos': 0,
2362 'offset': 0,
2363 'u-boot:offset': 0,
2364 'u-boot:size': len(U_BOOT_DATA),
2365 'u-boot:image-pos': 0,
2366 'fdtmap:image-pos': 4,
2367 'fdtmap:offset': 4,
2368 'fdtmap:size': len(fdtmap_data),
2369 'size': len(data),
2370 }, props)
2371
2372 def testFdtmapNoMatch(self):
2373 """Check handling of an FDT map when the section cannot be found"""
2374 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2375
2376 # Mangle the section name, which should cause a mismatch between the
2377 # correct FDT path and the one expected by the section
2378 image = control.images['image']
Simon Glasscec34ba2019-07-08 14:25:28 -06002379 image._node.path += '-suffix'
Simon Glass0f621332019-07-08 14:25:27 -06002380 entries = image.GetEntries()
2381 fdtmap = entries['fdtmap']
2382 with self.assertRaises(ValueError) as e:
2383 fdtmap._GetFdtmap()
2384 self.assertIn("Cannot locate node for path '/binman-suffix'",
2385 str(e.exception))
2386
Simon Glasscec34ba2019-07-08 14:25:28 -06002387 def testFdtmapHeader(self):
2388 """Test an FDT map and image header can be inserted in the image"""
2389 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2390 fdtmap_pos = len(U_BOOT_DATA)
2391 fdtmap_data = data[fdtmap_pos:]
2392 fdt_data = fdtmap_data[16:]
2393 dtb = fdt.Fdt.FromData(fdt_data)
2394 fdt_size = dtb.GetFdtObj().totalsize()
2395 hdr_data = data[-8:]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002396 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002397 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2398 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2399
2400 def testFdtmapHeaderStart(self):
2401 """Test an image header can be inserted at the image start"""
2402 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2403 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2404 hdr_data = data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002405 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002406 offset = struct.unpack('<I', hdr_data[4:])[0]
2407 self.assertEqual(fdtmap_pos, offset)
2408
2409 def testFdtmapHeaderPos(self):
2410 """Test an image header can be inserted at a chosen position"""
2411 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2412 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2413 hdr_data = data[0x80:0x88]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002414 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002415 offset = struct.unpack('<I', hdr_data[4:])[0]
2416 self.assertEqual(fdtmap_pos, offset)
2417
2418 def testHeaderMissingFdtmap(self):
2419 """Test an image header requires an fdtmap"""
2420 with self.assertRaises(ValueError) as e:
2421 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2422 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2423 str(e.exception))
2424
2425 def testHeaderNoLocation(self):
2426 """Test an image header with a no specified location is detected"""
2427 with self.assertRaises(ValueError) as e:
2428 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2429 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2430 str(e.exception))
2431
Simon Glasse61b6f62019-07-08 14:25:37 -06002432 def testEntryExpand(self):
2433 """Test expanding an entry after it is packed"""
2434 data = self._DoReadFile('121_entry_expand.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002435 self.assertEqual(b'aaa', data[:3])
2436 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2437 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002438
2439 def testEntryExpandBad(self):
2440 """Test expanding an entry after it is packed, twice"""
2441 with self.assertRaises(ValueError) as e:
2442 self._DoReadFile('122_entry_expand_twice.dts')
Simon Glass9d8ee322019-07-20 12:23:58 -06002443 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glasse61b6f62019-07-08 14:25:37 -06002444 str(e.exception))
2445
2446 def testEntryExpandSection(self):
2447 """Test expanding an entry within a section after it is packed"""
2448 data = self._DoReadFile('123_entry_expand_section.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002449 self.assertEqual(b'aaa', data[:3])
2450 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2451 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002452
Simon Glass90d29682019-07-08 14:25:38 -06002453 def testCompressDtb(self):
2454 """Test that compress of device-tree files is supported"""
2455 self._CheckLz4()
2456 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2457 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2458 comp_data = data[len(U_BOOT_DATA):]
2459 orig = self._decompress(comp_data)
2460 dtb = fdt.Fdt.FromData(orig)
2461 dtb.Scan()
2462 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2463 expected = {
2464 'u-boot:size': len(U_BOOT_DATA),
2465 'u-boot-dtb:uncomp-size': len(orig),
2466 'u-boot-dtb:size': len(comp_data),
2467 'size': len(data),
2468 }
2469 self.assertEqual(expected, props)
2470
Simon Glass151bbbf2019-07-08 14:25:41 -06002471 def testCbfsUpdateFdt(self):
2472 """Test that we can update the device tree with CBFS offset/size info"""
2473 self._CheckLz4()
2474 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2475 update_dtb=True)
2476 dtb = fdt.Fdt(out_dtb_fname)
2477 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002478 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass151bbbf2019-07-08 14:25:41 -06002479 del props['cbfs/u-boot:size']
2480 self.assertEqual({
2481 'offset': 0,
2482 'size': len(data),
2483 'image-pos': 0,
2484 'cbfs:offset': 0,
2485 'cbfs:size': len(data),
2486 'cbfs:image-pos': 0,
2487 'cbfs/u-boot:offset': 0x38,
2488 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2489 'cbfs/u-boot:image-pos': 0x38,
2490 'cbfs/u-boot-dtb:offset': 0xb8,
2491 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2492 'cbfs/u-boot-dtb:image-pos': 0xb8,
2493 }, props)
2494
Simon Glass3c9b4f22019-07-08 14:25:42 -06002495 def testCbfsBadType(self):
2496 """Test an image header with a no specified location is detected"""
2497 with self.assertRaises(ValueError) as e:
2498 self._DoReadFile('126_cbfs_bad_type.dts')
2499 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2500
Simon Glass6b156f82019-07-08 14:25:43 -06002501 def testList(self):
2502 """Test listing the files in an image"""
2503 self._CheckLz4()
2504 data = self._DoReadFile('127_list.dts')
2505 image = control.images['image']
2506 entries = image.BuildEntryList()
2507 self.assertEqual(7, len(entries))
2508
2509 ent = entries[0]
2510 self.assertEqual(0, ent.indent)
2511 self.assertEqual('main-section', ent.name)
2512 self.assertEqual('section', ent.etype)
2513 self.assertEqual(len(data), ent.size)
2514 self.assertEqual(0, ent.image_pos)
2515 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002516 self.assertEqual(0, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002517
2518 ent = entries[1]
2519 self.assertEqual(1, ent.indent)
2520 self.assertEqual('u-boot', ent.name)
2521 self.assertEqual('u-boot', ent.etype)
2522 self.assertEqual(len(U_BOOT_DATA), ent.size)
2523 self.assertEqual(0, ent.image_pos)
2524 self.assertEqual(None, ent.uncomp_size)
2525 self.assertEqual(0, ent.offset)
2526
2527 ent = entries[2]
2528 self.assertEqual(1, ent.indent)
2529 self.assertEqual('section', ent.name)
2530 self.assertEqual('section', ent.etype)
2531 section_size = ent.size
2532 self.assertEqual(0x100, ent.image_pos)
2533 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002534 self.assertEqual(0x100, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002535
2536 ent = entries[3]
2537 self.assertEqual(2, ent.indent)
2538 self.assertEqual('cbfs', ent.name)
2539 self.assertEqual('cbfs', ent.etype)
2540 self.assertEqual(0x400, ent.size)
2541 self.assertEqual(0x100, ent.image_pos)
2542 self.assertEqual(None, ent.uncomp_size)
2543 self.assertEqual(0, ent.offset)
2544
2545 ent = entries[4]
2546 self.assertEqual(3, ent.indent)
2547 self.assertEqual('u-boot', ent.name)
2548 self.assertEqual('u-boot', ent.etype)
2549 self.assertEqual(len(U_BOOT_DATA), ent.size)
2550 self.assertEqual(0x138, ent.image_pos)
2551 self.assertEqual(None, ent.uncomp_size)
2552 self.assertEqual(0x38, ent.offset)
2553
2554 ent = entries[5]
2555 self.assertEqual(3, ent.indent)
2556 self.assertEqual('u-boot-dtb', ent.name)
2557 self.assertEqual('text', ent.etype)
2558 self.assertGreater(len(COMPRESS_DATA), ent.size)
2559 self.assertEqual(0x178, ent.image_pos)
2560 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2561 self.assertEqual(0x78, ent.offset)
2562
2563 ent = entries[6]
2564 self.assertEqual(2, ent.indent)
2565 self.assertEqual('u-boot-dtb', ent.name)
2566 self.assertEqual('u-boot-dtb', ent.etype)
2567 self.assertEqual(0x500, ent.image_pos)
2568 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2569 dtb_size = ent.size
2570 # Compressing this data expands it since headers are added
2571 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2572 self.assertEqual(0x400, ent.offset)
2573
2574 self.assertEqual(len(data), 0x100 + section_size)
2575 self.assertEqual(section_size, 0x400 + dtb_size)
2576
Simon Glass8d8bf4e2019-07-08 14:25:44 -06002577 def testFindFdtmap(self):
2578 """Test locating an FDT map in an image"""
2579 self._CheckLz4()
2580 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2581 image = control.images['image']
2582 entries = image.GetEntries()
2583 entry = entries['fdtmap']
2584 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2585
2586 def testFindFdtmapMissing(self):
2587 """Test failing to locate an FDP map"""
2588 data = self._DoReadFile('005_simple.dts')
2589 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2590
Simon Glassed39a3c2019-07-08 14:25:45 -06002591 def testFindImageHeader(self):
2592 """Test locating a image header"""
2593 self._CheckLz4()
Simon Glassb8424fa2019-07-08 14:25:46 -06002594 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002595 image = control.images['image']
2596 entries = image.GetEntries()
2597 entry = entries['fdtmap']
2598 # The header should point to the FDT map
2599 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2600
2601 def testFindImageHeaderStart(self):
2602 """Test locating a image header located at the start of an image"""
Simon Glassb8424fa2019-07-08 14:25:46 -06002603 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002604 image = control.images['image']
2605 entries = image.GetEntries()
2606 entry = entries['fdtmap']
2607 # The header should point to the FDT map
2608 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2609
2610 def testFindImageHeaderMissing(self):
2611 """Test failing to locate an image header"""
2612 data = self._DoReadFile('005_simple.dts')
2613 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2614
Simon Glassb8424fa2019-07-08 14:25:46 -06002615 def testReadImage(self):
2616 """Test reading an image and accessing its FDT map"""
2617 self._CheckLz4()
2618 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2619 image_fname = tools.GetOutputFilename('image.bin')
2620 orig_image = control.images['image']
2621 image = Image.FromFile(image_fname)
2622 self.assertEqual(orig_image.GetEntries().keys(),
2623 image.GetEntries().keys())
2624
2625 orig_entry = orig_image.GetEntries()['fdtmap']
2626 entry = image.GetEntries()['fdtmap']
2627 self.assertEquals(orig_entry.offset, entry.offset)
2628 self.assertEquals(orig_entry.size, entry.size)
2629 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2630
2631 def testReadImageNoHeader(self):
2632 """Test accessing an image's FDT map without an image header"""
2633 self._CheckLz4()
2634 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
2635 image_fname = tools.GetOutputFilename('image.bin')
2636 image = Image.FromFile(image_fname)
2637 self.assertTrue(isinstance(image, Image))
Simon Glass072959a2019-07-20 12:23:50 -06002638 self.assertEqual('image', image.image_name[-5:])
Simon Glassb8424fa2019-07-08 14:25:46 -06002639
2640 def testReadImageFail(self):
2641 """Test failing to read an image image's FDT map"""
2642 self._DoReadFile('005_simple.dts')
2643 image_fname = tools.GetOutputFilename('image.bin')
2644 with self.assertRaises(ValueError) as e:
2645 image = Image.FromFile(image_fname)
2646 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glassc2f1aed2019-07-08 13:18:56 -06002647
Simon Glassb2fd11d2019-07-08 14:25:48 -06002648 def testListCmd(self):
2649 """Test listing the files in an image using an Fdtmap"""
2650 self._CheckLz4()
2651 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2652
2653 # lz4 compression size differs depending on the version
2654 image = control.images['image']
2655 entries = image.GetEntries()
2656 section_size = entries['section'].size
2657 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2658 fdtmap_offset = entries['fdtmap'].offset
2659
Simon Glassb3d6fc72019-07-20 12:24:10 -06002660 try:
2661 tmpdir, updated_fname = self._SetupImageInTmpdir()
2662 with test_util.capture_sys_output() as (stdout, stderr):
2663 self._DoBinman('ls', '-i', updated_fname)
2664 finally:
2665 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002666 lines = stdout.getvalue().splitlines()
2667 expected = [
2668'Name Image-pos Size Entry-type Offset Uncomp-size',
2669'----------------------------------------------------------------------',
2670'main-section 0 c00 section 0',
2671' u-boot 0 4 u-boot 0',
2672' section 100 %x section 100' % section_size,
2673' cbfs 100 400 cbfs 0',
2674' u-boot 138 4 u-boot 38',
Simon Glassc5fd10a2019-10-31 07:43:03 -06002675' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002676' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassc5fd10a2019-10-31 07:43:03 -06002677' fdtmap %x 3bd fdtmap %x' %
Simon Glassb2fd11d2019-07-08 14:25:48 -06002678 (fdtmap_offset, fdtmap_offset),
2679' image-header bf8 8 image-header bf8',
2680 ]
2681 self.assertEqual(expected, lines)
2682
2683 def testListCmdFail(self):
2684 """Test failing to list an image"""
2685 self._DoReadFile('005_simple.dts')
Simon Glassb3d6fc72019-07-20 12:24:10 -06002686 try:
2687 tmpdir, updated_fname = self._SetupImageInTmpdir()
2688 with self.assertRaises(ValueError) as e:
2689 self._DoBinman('ls', '-i', updated_fname)
2690 finally:
2691 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002692 self.assertIn("Cannot find FDT map in image", str(e.exception))
2693
2694 def _RunListCmd(self, paths, expected):
2695 """List out entries and check the result
2696
2697 Args:
2698 paths: List of paths to pass to the list command
2699 expected: Expected list of filenames to be returned, in order
2700 """
2701 self._CheckLz4()
2702 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2703 image_fname = tools.GetOutputFilename('image.bin')
2704 image = Image.FromFile(image_fname)
2705 lines = image.GetListEntries(paths)[1]
2706 files = [line[0].strip() for line in lines[1:]]
2707 self.assertEqual(expected, files)
2708
2709 def testListCmdSection(self):
2710 """Test listing the files in a section"""
2711 self._RunListCmd(['section'],
2712 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2713
2714 def testListCmdFile(self):
2715 """Test listing a particular file"""
2716 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2717
2718 def testListCmdWildcard(self):
2719 """Test listing a wildcarded file"""
2720 self._RunListCmd(['*boot*'],
2721 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2722
2723 def testListCmdWildcardMulti(self):
2724 """Test listing a wildcarded file"""
2725 self._RunListCmd(['*cb*', '*head*'],
2726 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2727
2728 def testListCmdEmpty(self):
2729 """Test listing a wildcarded file"""
2730 self._RunListCmd(['nothing'], [])
2731
2732 def testListCmdPath(self):
2733 """Test listing the files in a sub-entry of a section"""
2734 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2735
Simon Glass4c613bf2019-07-08 14:25:50 -06002736 def _RunExtractCmd(self, entry_name, decomp=True):
2737 """Extract an entry from an image
2738
2739 Args:
2740 entry_name: Entry name to extract
2741 decomp: True to decompress the data if compressed, False to leave
2742 it in its raw uncompressed format
2743
2744 Returns:
2745 data from entry
2746 """
2747 self._CheckLz4()
2748 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2749 image_fname = tools.GetOutputFilename('image.bin')
2750 return control.ReadEntry(image_fname, entry_name, decomp)
2751
2752 def testExtractSimple(self):
2753 """Test extracting a single file"""
2754 data = self._RunExtractCmd('u-boot')
2755 self.assertEqual(U_BOOT_DATA, data)
2756
Simon Glass980a2842019-07-08 14:25:52 -06002757 def testExtractSection(self):
2758 """Test extracting the files in a section"""
2759 data = self._RunExtractCmd('section')
2760 cbfs_data = data[:0x400]
2761 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassc5fd10a2019-10-31 07:43:03 -06002762 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass980a2842019-07-08 14:25:52 -06002763 dtb_data = data[0x400:]
2764 dtb = self._decompress(dtb_data)
2765 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2766
2767 def testExtractCompressed(self):
2768 """Test extracting compressed data"""
2769 data = self._RunExtractCmd('section/u-boot-dtb')
2770 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2771
2772 def testExtractRaw(self):
2773 """Test extracting compressed data without decompressing it"""
2774 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2775 dtb = self._decompress(data)
2776 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2777
2778 def testExtractCbfs(self):
2779 """Test extracting CBFS data"""
2780 data = self._RunExtractCmd('section/cbfs/u-boot')
2781 self.assertEqual(U_BOOT_DATA, data)
2782
2783 def testExtractCbfsCompressed(self):
2784 """Test extracting CBFS compressed data"""
2785 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2786 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2787
2788 def testExtractCbfsRaw(self):
2789 """Test extracting CBFS compressed data without decompressing it"""
2790 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Simon Glass37fdd142019-07-20 12:24:06 -06002791 dtb = tools.Decompress(data, 'lzma', with_header=False)
Simon Glass980a2842019-07-08 14:25:52 -06002792 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2793
Simon Glass4c613bf2019-07-08 14:25:50 -06002794 def testExtractBadEntry(self):
2795 """Test extracting a bad section path"""
2796 with self.assertRaises(ValueError) as e:
2797 self._RunExtractCmd('section/does-not-exist')
2798 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2799 str(e.exception))
2800
2801 def testExtractMissingFile(self):
2802 """Test extracting file that does not exist"""
2803 with self.assertRaises(IOError) as e:
2804 control.ReadEntry('missing-file', 'name')
2805
2806 def testExtractBadFile(self):
2807 """Test extracting an invalid file"""
2808 fname = os.path.join(self._indir, 'badfile')
2809 tools.WriteFile(fname, b'')
2810 with self.assertRaises(ValueError) as e:
2811 control.ReadEntry(fname, 'name')
2812
Simon Glass980a2842019-07-08 14:25:52 -06002813 def testExtractCmd(self):
2814 """Test extracting a file fron an image on the command line"""
2815 self._CheckLz4()
2816 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass980a2842019-07-08 14:25:52 -06002817 fname = os.path.join(self._indir, 'output.extact')
Simon Glassb3d6fc72019-07-20 12:24:10 -06002818 try:
2819 tmpdir, updated_fname = self._SetupImageInTmpdir()
2820 with test_util.capture_sys_output() as (stdout, stderr):
2821 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2822 '-f', fname)
2823 finally:
2824 shutil.rmtree(tmpdir)
Simon Glass980a2842019-07-08 14:25:52 -06002825 data = tools.ReadFile(fname)
2826 self.assertEqual(U_BOOT_DATA, data)
2827
2828 def testExtractOneEntry(self):
2829 """Test extracting a single entry fron an image """
2830 self._CheckLz4()
2831 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2832 image_fname = tools.GetOutputFilename('image.bin')
2833 fname = os.path.join(self._indir, 'output.extact')
2834 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
2835 data = tools.ReadFile(fname)
2836 self.assertEqual(U_BOOT_DATA, data)
2837
2838 def _CheckExtractOutput(self, decomp):
2839 """Helper to test file output with and without decompression
2840
2841 Args:
2842 decomp: True to decompress entry data, False to output it raw
2843 """
2844 def _CheckPresent(entry_path, expect_data, expect_size=None):
2845 """Check and remove expected file
2846
2847 This checks the data/size of a file and removes the file both from
2848 the outfiles set and from the output directory. Once all files are
2849 processed, both the set and directory should be empty.
2850
2851 Args:
2852 entry_path: Entry path
2853 expect_data: Data to expect in file, or None to skip check
2854 expect_size: Size of data to expect in file, or None to skip
2855 """
2856 path = os.path.join(outdir, entry_path)
2857 data = tools.ReadFile(path)
2858 os.remove(path)
2859 if expect_data:
2860 self.assertEqual(expect_data, data)
2861 elif expect_size:
2862 self.assertEqual(expect_size, len(data))
2863 outfiles.remove(path)
2864
2865 def _CheckDirPresent(name):
2866 """Remove expected directory
2867
2868 This gives an error if the directory does not exist as expected
2869
2870 Args:
2871 name: Name of directory to remove
2872 """
2873 path = os.path.join(outdir, name)
2874 os.rmdir(path)
2875
2876 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2877 image_fname = tools.GetOutputFilename('image.bin')
2878 outdir = os.path.join(self._indir, 'extract')
2879 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2880
2881 # Create a set of all file that were output (should be 9)
2882 outfiles = set()
2883 for root, dirs, files in os.walk(outdir):
2884 outfiles |= set([os.path.join(root, fname) for fname in files])
2885 self.assertEqual(9, len(outfiles))
2886 self.assertEqual(9, len(einfos))
2887
2888 image = control.images['image']
2889 entries = image.GetEntries()
2890
2891 # Check the 9 files in various ways
2892 section = entries['section']
2893 section_entries = section.GetEntries()
2894 cbfs_entries = section_entries['cbfs'].GetEntries()
2895 _CheckPresent('u-boot', U_BOOT_DATA)
2896 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
2897 dtb_len = EXTRACT_DTB_SIZE
2898 if not decomp:
2899 dtb_len = cbfs_entries['u-boot-dtb'].size
2900 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
2901 if not decomp:
2902 dtb_len = section_entries['u-boot-dtb'].size
2903 _CheckPresent('section/u-boot-dtb', None, dtb_len)
2904
2905 fdtmap = entries['fdtmap']
2906 _CheckPresent('fdtmap', fdtmap.data)
2907 hdr = entries['image-header']
2908 _CheckPresent('image-header', hdr.data)
2909
2910 _CheckPresent('section/root', section.data)
2911 cbfs = section_entries['cbfs']
2912 _CheckPresent('section/cbfs/root', cbfs.data)
2913 data = tools.ReadFile(image_fname)
2914 _CheckPresent('root', data)
2915
2916 # There should be no files left. Remove all the directories to check.
2917 # If there are any files/dirs remaining, one of these checks will fail.
2918 self.assertEqual(0, len(outfiles))
2919 _CheckDirPresent('section/cbfs')
2920 _CheckDirPresent('section')
2921 _CheckDirPresent('')
2922 self.assertFalse(os.path.exists(outdir))
2923
2924 def testExtractAllEntries(self):
2925 """Test extracting all entries"""
2926 self._CheckLz4()
2927 self._CheckExtractOutput(decomp=True)
2928
2929 def testExtractAllEntriesRaw(self):
2930 """Test extracting all entries without decompressing them"""
2931 self._CheckLz4()
2932 self._CheckExtractOutput(decomp=False)
2933
2934 def testExtractSelectedEntries(self):
2935 """Test extracting some entries"""
2936 self._CheckLz4()
2937 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2938 image_fname = tools.GetOutputFilename('image.bin')
2939 outdir = os.path.join(self._indir, 'extract')
2940 einfos = control.ExtractEntries(image_fname, None, outdir,
2941 ['*cb*', '*head*'])
2942
2943 # File output is tested by testExtractAllEntries(), so just check that
2944 # the expected entries are selected
2945 names = [einfo.name for einfo in einfos]
2946 self.assertEqual(names,
2947 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2948
2949 def testExtractNoEntryPaths(self):
2950 """Test extracting some entries"""
2951 self._CheckLz4()
2952 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2953 image_fname = tools.GetOutputFilename('image.bin')
2954 with self.assertRaises(ValueError) as e:
2955 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassa772d3f2019-07-20 12:24:14 -06002956 self.assertIn('Must specify an entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06002957 str(e.exception))
2958
2959 def testExtractTooManyEntryPaths(self):
2960 """Test extracting some entries"""
2961 self._CheckLz4()
2962 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2963 image_fname = tools.GetOutputFilename('image.bin')
2964 with self.assertRaises(ValueError) as e:
2965 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassa772d3f2019-07-20 12:24:14 -06002966 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06002967 str(e.exception))
2968
Simon Glass52d06212019-07-08 14:25:53 -06002969 def testPackAlignSection(self):
2970 """Test that sections can have alignment"""
2971 self._DoReadFile('131_pack_align_section.dts')
2972
2973 self.assertIn('image', control.images)
2974 image = control.images['image']
2975 entries = image.GetEntries()
2976 self.assertEqual(3, len(entries))
2977
2978 # First u-boot
2979 self.assertIn('u-boot', entries)
2980 entry = entries['u-boot']
2981 self.assertEqual(0, entry.offset)
2982 self.assertEqual(0, entry.image_pos)
2983 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2984 self.assertEqual(len(U_BOOT_DATA), entry.size)
2985
2986 # Section0
2987 self.assertIn('section0', entries)
2988 section0 = entries['section0']
2989 self.assertEqual(0x10, section0.offset)
2990 self.assertEqual(0x10, section0.image_pos)
2991 self.assertEqual(len(U_BOOT_DATA), section0.size)
2992
2993 # Second u-boot
2994 section_entries = section0.GetEntries()
2995 self.assertIn('u-boot', section_entries)
2996 entry = section_entries['u-boot']
2997 self.assertEqual(0, entry.offset)
2998 self.assertEqual(0x10, entry.image_pos)
2999 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3000 self.assertEqual(len(U_BOOT_DATA), entry.size)
3001
3002 # Section1
3003 self.assertIn('section1', entries)
3004 section1 = entries['section1']
3005 self.assertEqual(0x14, section1.offset)
3006 self.assertEqual(0x14, section1.image_pos)
3007 self.assertEqual(0x20, section1.size)
3008
3009 # Second u-boot
3010 section_entries = section1.GetEntries()
3011 self.assertIn('u-boot', section_entries)
3012 entry = section_entries['u-boot']
3013 self.assertEqual(0, entry.offset)
3014 self.assertEqual(0x14, entry.image_pos)
3015 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3016 self.assertEqual(len(U_BOOT_DATA), entry.size)
3017
3018 # Section2
3019 self.assertIn('section2', section_entries)
3020 section2 = section_entries['section2']
3021 self.assertEqual(0x4, section2.offset)
3022 self.assertEqual(0x18, section2.image_pos)
3023 self.assertEqual(4, section2.size)
3024
3025 # Third u-boot
3026 section_entries = section2.GetEntries()
3027 self.assertIn('u-boot', section_entries)
3028 entry = section_entries['u-boot']
3029 self.assertEqual(0, entry.offset)
3030 self.assertEqual(0x18, entry.image_pos)
3031 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3032 self.assertEqual(len(U_BOOT_DATA), entry.size)
3033
Simon Glassf8a54bc2019-07-20 12:23:56 -06003034 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3035 dts='132_replace.dts'):
Simon Glass072959a2019-07-20 12:23:50 -06003036 """Replace an entry in an image
3037
3038 This writes the entry data to update it, then opens the updated file and
3039 returns the value that it now finds there.
3040
3041 Args:
3042 entry_name: Entry name to replace
3043 data: Data to replace it with
3044 decomp: True to compress the data if needed, False if data is
3045 already compressed so should be used as is
Simon Glassf8a54bc2019-07-20 12:23:56 -06003046 allow_resize: True to allow entries to change size, False to raise
3047 an exception
Simon Glass072959a2019-07-20 12:23:50 -06003048
3049 Returns:
3050 Tuple:
3051 data from entry
3052 data from fdtmap (excluding header)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003053 Image object that was modified
Simon Glass072959a2019-07-20 12:23:50 -06003054 """
Simon Glassf8a54bc2019-07-20 12:23:56 -06003055 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass072959a2019-07-20 12:23:50 -06003056 update_dtb=True)[1]
3057
3058 self.assertIn('image', control.images)
3059 image = control.images['image']
3060 entries = image.GetEntries()
3061 orig_dtb_data = entries['u-boot-dtb'].data
3062 orig_fdtmap_data = entries['fdtmap'].data
3063
3064 image_fname = tools.GetOutputFilename('image.bin')
3065 updated_fname = tools.GetOutputFilename('image-updated.bin')
3066 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
Simon Glassf8a54bc2019-07-20 12:23:56 -06003067 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3068 allow_resize)
Simon Glass072959a2019-07-20 12:23:50 -06003069 data = control.ReadEntry(updated_fname, entry_name, decomp)
3070
Simon Glassf8a54bc2019-07-20 12:23:56 -06003071 # The DT data should not change unless resized:
3072 if not allow_resize:
3073 new_dtb_data = entries['u-boot-dtb'].data
3074 self.assertEqual(new_dtb_data, orig_dtb_data)
3075 new_fdtmap_data = entries['fdtmap'].data
3076 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass072959a2019-07-20 12:23:50 -06003077
Simon Glassf8a54bc2019-07-20 12:23:56 -06003078 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass072959a2019-07-20 12:23:50 -06003079
3080 def testReplaceSimple(self):
3081 """Test replacing a single file"""
3082 expected = b'x' * len(U_BOOT_DATA)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003083 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3084 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003085 self.assertEqual(expected, data)
3086
3087 # Test that the state looks right. There should be an FDT for the fdtmap
3088 # that we jsut read back in, and it should match what we find in the
3089 # 'control' tables. Checking for an FDT that does not exist should
3090 # return None.
3091 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glassf8a54bc2019-07-20 12:23:56 -06003092 self.assertIsNotNone(path)
Simon Glass072959a2019-07-20 12:23:50 -06003093 self.assertEqual(expected_fdtmap, fdtmap)
3094
3095 dtb = state.GetFdtForEtype('fdtmap')
3096 self.assertEqual(dtb.GetContents(), fdtmap)
3097
3098 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3099 self.assertIsNone(missing_path)
3100 self.assertIsNone(missing_fdtmap)
3101
3102 missing_dtb = state.GetFdtForEtype('missing')
3103 self.assertIsNone(missing_dtb)
3104
3105 self.assertEqual('/binman', state.fdt_path_prefix)
3106
3107 def testReplaceResizeFail(self):
3108 """Test replacing a file by something larger"""
3109 expected = U_BOOT_DATA + b'x'
3110 with self.assertRaises(ValueError) as e:
Simon Glassf8a54bc2019-07-20 12:23:56 -06003111 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3112 dts='139_replace_repack.dts')
Simon Glass072959a2019-07-20 12:23:50 -06003113 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3114 str(e.exception))
3115
3116 def testReplaceMulti(self):
3117 """Test replacing entry data where multiple images are generated"""
3118 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3119 update_dtb=True)[0]
3120 expected = b'x' * len(U_BOOT_DATA)
3121 updated_fname = tools.GetOutputFilename('image-updated.bin')
3122 tools.WriteFile(updated_fname, data)
3123 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003124 control.WriteEntry(updated_fname, entry_name, expected,
3125 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003126 data = control.ReadEntry(updated_fname, entry_name)
3127 self.assertEqual(expected, data)
3128
3129 # Check the state looks right.
3130 self.assertEqual('/binman/image', state.fdt_path_prefix)
3131
3132 # Now check we can write the first image
3133 image_fname = tools.GetOutputFilename('first-image.bin')
3134 updated_fname = tools.GetOutputFilename('first-updated.bin')
3135 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
3136 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003137 control.WriteEntry(updated_fname, entry_name, expected,
3138 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003139 data = control.ReadEntry(updated_fname, entry_name)
3140 self.assertEqual(expected, data)
3141
3142 # Check the state looks right.
3143 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass39dd2152019-07-08 14:25:47 -06003144
Simon Glassfb30e292019-07-20 12:23:51 -06003145 def testUpdateFdtAllRepack(self):
3146 """Test that all device trees are updated with offset/size info"""
3147 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3148 SECTION_SIZE = 0x300
3149 DTB_SIZE = 602
3150 FDTMAP_SIZE = 608
3151 base_expected = {
3152 'offset': 0,
3153 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3154 'image-pos': 0,
3155 'section:offset': 0,
3156 'section:size': SECTION_SIZE,
3157 'section:image-pos': 0,
3158 'section/u-boot-dtb:offset': 4,
3159 'section/u-boot-dtb:size': 636,
3160 'section/u-boot-dtb:image-pos': 4,
3161 'u-boot-spl-dtb:offset': SECTION_SIZE,
3162 'u-boot-spl-dtb:size': DTB_SIZE,
3163 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3164 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3165 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3166 'u-boot-tpl-dtb:size': DTB_SIZE,
3167 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3168 'fdtmap:size': FDTMAP_SIZE,
3169 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3170 }
3171 main_expected = {
3172 'section:orig-size': SECTION_SIZE,
3173 'section/u-boot-dtb:orig-offset': 4,
3174 }
3175
3176 # We expect three device-tree files in the output, with the first one
3177 # within a fixed-size section.
3178 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3179 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3180 # main U-Boot tree. All three should have the same positions and offset
3181 # except that the main tree should include the main_expected properties
3182 start = 4
3183 for item in ['', 'spl', 'tpl', None]:
3184 if item is None:
3185 start += 16 # Move past fdtmap header
3186 dtb = fdt.Fdt.FromData(data[start:])
3187 dtb.Scan()
3188 props = self._GetPropTree(dtb,
3189 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3190 prefix='/' if item is None else '/binman/')
3191 expected = dict(base_expected)
3192 if item:
3193 expected[item] = 0
3194 else:
3195 # Main DTB and fdtdec should include the 'orig-' properties
3196 expected.update(main_expected)
3197 # Helpful for debugging:
3198 #for prop in sorted(props):
3199 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3200 self.assertEqual(expected, props)
3201 if item == '':
3202 start = SECTION_SIZE
3203 else:
3204 start += dtb._fdt_obj.totalsize()
3205
Simon Glass11453762019-07-20 12:23:55 -06003206 def testFdtmapHeaderMiddle(self):
3207 """Test an FDT map in the middle of an image when it should be at end"""
3208 with self.assertRaises(ValueError) as e:
3209 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3210 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3211 str(e.exception))
3212
3213 def testFdtmapHeaderStartBad(self):
3214 """Test an FDT map in middle of an image when it should be at start"""
3215 with self.assertRaises(ValueError) as e:
3216 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3217 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3218 str(e.exception))
3219
3220 def testFdtmapHeaderEndBad(self):
3221 """Test an FDT map at the start of an image when it should be at end"""
3222 with self.assertRaises(ValueError) as e:
3223 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3224 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3225 str(e.exception))
3226
3227 def testFdtmapHeaderNoSize(self):
3228 """Test an image header at the end of an image with undefined size"""
3229 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3230
Simon Glassf8a54bc2019-07-20 12:23:56 -06003231 def testReplaceResize(self):
3232 """Test replacing a single file in an entry with a larger file"""
3233 expected = U_BOOT_DATA + b'x'
3234 data, _, image = self._RunReplaceCmd('u-boot', expected,
3235 dts='139_replace_repack.dts')
3236 self.assertEqual(expected, data)
3237
3238 entries = image.GetEntries()
3239 dtb_data = entries['u-boot-dtb'].data
3240 dtb = fdt.Fdt.FromData(dtb_data)
3241 dtb.Scan()
3242
3243 # The u-boot section should now be larger in the dtb
3244 node = dtb.GetNode('/binman/u-boot')
3245 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3246
3247 # Same for the fdtmap
3248 fdata = entries['fdtmap'].data
3249 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3250 fdtb.Scan()
3251 fnode = fdtb.GetNode('/u-boot')
3252 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3253
3254 def testReplaceResizeNoRepack(self):
3255 """Test replacing an entry with a larger file when not allowed"""
3256 expected = U_BOOT_DATA + b'x'
3257 with self.assertRaises(ValueError) as e:
3258 self._RunReplaceCmd('u-boot', expected)
3259 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3260 str(e.exception))
3261
Simon Glass9d8ee322019-07-20 12:23:58 -06003262 def testEntryShrink(self):
3263 """Test contracting an entry after it is packed"""
3264 try:
3265 state.SetAllowEntryContraction(True)
3266 data = self._DoReadFileDtb('140_entry_shrink.dts',
3267 update_dtb=True)[0]
3268 finally:
3269 state.SetAllowEntryContraction(False)
3270 self.assertEqual(b'a', data[:1])
3271 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3272 self.assertEqual(b'a', data[-1:])
3273
3274 def testEntryShrinkFail(self):
3275 """Test not being allowed to contract an entry after it is packed"""
3276 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3277
3278 # In this case there is a spare byte at the end of the data. The size of
3279 # the contents is only 1 byte but we still have the size before it
3280 # shrunk.
3281 self.assertEqual(b'a\0', data[:2])
3282 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3283 self.assertEqual(b'a\0', data[-2:])
3284
Simon Glass70e32982019-07-20 12:24:01 -06003285 def testDescriptorOffset(self):
3286 """Test that the Intel descriptor is always placed at at the start"""
3287 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3288 image = control.images['image']
3289 entries = image.GetEntries()
3290 desc = entries['intel-descriptor']
3291 self.assertEqual(0xff800000, desc.offset);
3292 self.assertEqual(0xff800000, desc.image_pos);
3293
Simon Glass37fdd142019-07-20 12:24:06 -06003294 def testReplaceCbfs(self):
3295 """Test replacing a single file in CBFS without changing the size"""
3296 self._CheckLz4()
3297 expected = b'x' * len(U_BOOT_DATA)
3298 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3299 updated_fname = tools.GetOutputFilename('image-updated.bin')
3300 tools.WriteFile(updated_fname, data)
3301 entry_name = 'section/cbfs/u-boot'
3302 control.WriteEntry(updated_fname, entry_name, expected,
3303 allow_resize=True)
3304 data = control.ReadEntry(updated_fname, entry_name)
3305 self.assertEqual(expected, data)
3306
3307 def testReplaceResizeCbfs(self):
3308 """Test replacing a single file in CBFS with one of a different size"""
3309 self._CheckLz4()
3310 expected = U_BOOT_DATA + b'x'
3311 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3312 updated_fname = tools.GetOutputFilename('image-updated.bin')
3313 tools.WriteFile(updated_fname, data)
3314 entry_name = 'section/cbfs/u-boot'
3315 control.WriteEntry(updated_fname, entry_name, expected,
3316 allow_resize=True)
3317 data = control.ReadEntry(updated_fname, entry_name)
3318 self.assertEqual(expected, data)
3319
Simon Glass30033c22019-07-20 12:24:15 -06003320 def _SetupForReplace(self):
3321 """Set up some files to use to replace entries
3322
3323 This generates an image, copies it to a new file, extracts all the files
3324 in it and updates some of them
3325
3326 Returns:
3327 List
3328 Image filename
3329 Output directory
3330 Expected values for updated entries, each a string
3331 """
3332 data = self._DoReadFileRealDtb('143_replace_all.dts')
3333
3334 updated_fname = tools.GetOutputFilename('image-updated.bin')
3335 tools.WriteFile(updated_fname, data)
3336
3337 outdir = os.path.join(self._indir, 'extract')
3338 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3339
3340 expected1 = b'x' + U_BOOT_DATA + b'y'
3341 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3342 tools.WriteFile(u_boot_fname1, expected1)
3343
3344 expected2 = b'a' + U_BOOT_DATA + b'b'
3345 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
3346 tools.WriteFile(u_boot_fname2, expected2)
3347
3348 expected_text = b'not the same text'
3349 text_fname = os.path.join(outdir, 'text')
3350 tools.WriteFile(text_fname, expected_text)
3351
3352 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3353 dtb = fdt.FdtScan(dtb_fname)
3354 node = dtb.GetNode('/binman/text')
3355 node.AddString('my-property', 'the value')
3356 dtb.Sync(auto_resize=True)
3357 dtb.Flush()
3358
3359 return updated_fname, outdir, expected1, expected2, expected_text
3360
3361 def _CheckReplaceMultiple(self, entry_paths):
3362 """Handle replacing the contents of multiple entries
3363
3364 Args:
3365 entry_paths: List of entry paths to replace
3366
3367 Returns:
3368 List
3369 Dict of entries in the image:
3370 key: Entry name
3371 Value: Entry object
3372 Expected values for updated entries, each a string
3373 """
3374 updated_fname, outdir, expected1, expected2, expected_text = (
3375 self._SetupForReplace())
3376 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3377
3378 image = Image.FromFile(updated_fname)
3379 image.LoadData()
3380 return image.GetEntries(), expected1, expected2, expected_text
3381
3382 def testReplaceAll(self):
3383 """Test replacing the contents of all entries"""
3384 entries, expected1, expected2, expected_text = (
3385 self._CheckReplaceMultiple([]))
3386 data = entries['u-boot'].data
3387 self.assertEqual(expected1, data)
3388
3389 data = entries['u-boot2'].data
3390 self.assertEqual(expected2, data)
3391
3392 data = entries['text'].data
3393 self.assertEqual(expected_text, data)
3394
3395 # Check that the device tree is updated
3396 data = entries['u-boot-dtb'].data
3397 dtb = fdt.Fdt.FromData(data)
3398 dtb.Scan()
3399 node = dtb.GetNode('/binman/text')
3400 self.assertEqual('the value', node.props['my-property'].value)
3401
3402 def testReplaceSome(self):
3403 """Test replacing the contents of a few entries"""
3404 entries, expected1, expected2, expected_text = (
3405 self._CheckReplaceMultiple(['u-boot2', 'text']))
3406
3407 # This one should not change
3408 data = entries['u-boot'].data
3409 self.assertEqual(U_BOOT_DATA, data)
3410
3411 data = entries['u-boot2'].data
3412 self.assertEqual(expected2, data)
3413
3414 data = entries['text'].data
3415 self.assertEqual(expected_text, data)
3416
3417 def testReplaceCmd(self):
3418 """Test replacing a file fron an image on the command line"""
3419 self._DoReadFileRealDtb('143_replace_all.dts')
3420
3421 try:
3422 tmpdir, updated_fname = self._SetupImageInTmpdir()
3423
3424 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3425 expected = b'x' * len(U_BOOT_DATA)
3426 tools.WriteFile(fname, expected)
3427
3428 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
3429 data = tools.ReadFile(updated_fname)
3430 self.assertEqual(expected, data[:len(expected)])
3431 map_fname = os.path.join(tmpdir, 'image-updated.map')
3432 self.assertFalse(os.path.exists(map_fname))
3433 finally:
3434 shutil.rmtree(tmpdir)
3435
3436 def testReplaceCmdSome(self):
3437 """Test replacing some files fron an image on the command line"""
3438 updated_fname, outdir, expected1, expected2, expected_text = (
3439 self._SetupForReplace())
3440
3441 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3442 'u-boot2', 'text')
3443
3444 tools.PrepareOutputDir(None)
3445 image = Image.FromFile(updated_fname)
3446 image.LoadData()
3447 entries = image.GetEntries()
3448
3449 # This one should not change
3450 data = entries['u-boot'].data
3451 self.assertEqual(U_BOOT_DATA, data)
3452
3453 data = entries['u-boot2'].data
3454 self.assertEqual(expected2, data)
3455
3456 data = entries['text'].data
3457 self.assertEqual(expected_text, data)
3458
3459 def testReplaceMissing(self):
3460 """Test replacing entries where the file is missing"""
3461 updated_fname, outdir, expected1, expected2, expected_text = (
3462 self._SetupForReplace())
3463
3464 # Remove one of the files, to generate a warning
3465 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3466 os.remove(u_boot_fname1)
3467
3468 with test_util.capture_sys_output() as (stdout, stderr):
3469 control.ReplaceEntries(updated_fname, None, outdir, [])
3470 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass6e02f7c2020-07-09 18:39:39 -06003471 stderr.getvalue())
Simon Glass30033c22019-07-20 12:24:15 -06003472
3473 def testReplaceCmdMap(self):
3474 """Test replacing a file fron an image on the command line"""
3475 self._DoReadFileRealDtb('143_replace_all.dts')
3476
3477 try:
3478 tmpdir, updated_fname = self._SetupImageInTmpdir()
3479
3480 fname = os.path.join(self._indir, 'update-u-boot.bin')
3481 expected = b'x' * len(U_BOOT_DATA)
3482 tools.WriteFile(fname, expected)
3483
3484 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3485 '-f', fname, '-m')
3486 map_fname = os.path.join(tmpdir, 'image-updated.map')
3487 self.assertTrue(os.path.exists(map_fname))
3488 finally:
3489 shutil.rmtree(tmpdir)
3490
3491 def testReplaceNoEntryPaths(self):
3492 """Test replacing an entry without an entry path"""
3493 self._DoReadFileRealDtb('143_replace_all.dts')
3494 image_fname = tools.GetOutputFilename('image.bin')
3495 with self.assertRaises(ValueError) as e:
3496 control.ReplaceEntries(image_fname, 'fname', None, [])
3497 self.assertIn('Must specify an entry path to read with -f',
3498 str(e.exception))
3499
3500 def testReplaceTooManyEntryPaths(self):
3501 """Test extracting some entries"""
3502 self._DoReadFileRealDtb('143_replace_all.dts')
3503 image_fname = tools.GetOutputFilename('image.bin')
3504 with self.assertRaises(ValueError) as e:
3505 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3506 self.assertIn('Must specify exactly one entry path to write with -f',
3507 str(e.exception))
3508
Simon Glass0b074d62019-08-24 07:22:48 -06003509 def testPackReset16(self):
3510 """Test that an image with an x86 reset16 region can be created"""
3511 data = self._DoReadFile('144_x86_reset16.dts')
3512 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3513
3514 def testPackReset16Spl(self):
3515 """Test that an image with an x86 reset16-spl region can be created"""
3516 data = self._DoReadFile('145_x86_reset16_spl.dts')
3517 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3518
3519 def testPackReset16Tpl(self):
3520 """Test that an image with an x86 reset16-tpl region can be created"""
3521 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3522 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3523
Simon Glass232f90c2019-08-24 07:22:50 -06003524 def testPackIntelFit(self):
3525 """Test that an image with an Intel FIT and pointer can be created"""
3526 data = self._DoReadFile('147_intel_fit.dts')
3527 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3528 fit = data[16:32];
3529 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3530 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3531
3532 image = control.images['image']
3533 entries = image.GetEntries()
3534 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3535 self.assertEqual(expected_ptr, ptr)
3536
3537 def testPackIntelFitMissing(self):
3538 """Test detection of a FIT pointer with not FIT region"""
3539 with self.assertRaises(ValueError) as e:
3540 self._DoReadFile('148_intel_fit_missing.dts')
3541 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3542 str(e.exception))
3543
Simon Glass72555fa2019-11-06 17:22:44 -07003544 def _CheckSymbolsTplSection(self, dts, expected_vals):
3545 data = self._DoReadFile(dts)
3546 sym_values = struct.pack('<LQLL', *expected_vals)
Simon Glass3eb5b202019-08-24 07:23:00 -06003547 upto1 = 4 + len(U_BOOT_SPL_DATA)
Simon Glass3f8ff012019-08-24 07:23:05 -06003548 expected1 = tools.GetBytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[20:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003549 self.assertEqual(expected1, data[:upto1])
3550
3551 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Simon Glass3f8ff012019-08-24 07:23:05 -06003552 expected2 = tools.GetBytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[20:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003553 self.assertEqual(expected2, data[upto1:upto2])
3554
Simon Glass4e353e22019-08-24 07:23:04 -06003555 upto3 = 0x34 + len(U_BOOT_DATA)
3556 expected3 = tools.GetBytes(0xff, 1) + U_BOOT_DATA
Simon Glass3eb5b202019-08-24 07:23:00 -06003557 self.assertEqual(expected3, data[upto2:upto3])
3558
Simon Glass3f8ff012019-08-24 07:23:05 -06003559 expected4 = sym_values + U_BOOT_TPL_DATA[20:]
Simon Glass72555fa2019-11-06 17:22:44 -07003560 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3561
3562 def testSymbolsTplSection(self):
3563 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3564 self._SetupSplElf('u_boot_binman_syms')
3565 self._SetupTplElf('u_boot_binman_syms')
3566 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
3567 [0x04, 0x1c, 0x10 + 0x34, 0x04])
3568
3569 def testSymbolsTplSectionX86(self):
3570 """Test binman can assign symbols in a section with end-at-4gb"""
3571 self._SetupSplElf('u_boot_binman_syms_x86')
3572 self._SetupTplElf('u_boot_binman_syms_x86')
3573 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
3574 [0xffffff04, 0xffffff1c, 0xffffff34,
3575 0x04])
Simon Glass3eb5b202019-08-24 07:23:00 -06003576
Simon Glass98c59572019-08-24 07:23:03 -06003577 def testPackX86RomIfwiSectiom(self):
3578 """Test that a section can be placed in an IFWI region"""
3579 self._SetupIfwi('fitimage.bin')
3580 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3581 self._CheckIfwi(data)
3582
Simon Glassba7985d2019-08-24 07:23:07 -06003583 def testPackFspM(self):
3584 """Test that an image with a FSP memory-init binary can be created"""
3585 data = self._DoReadFile('152_intel_fsp_m.dts')
3586 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3587
Simon Glass4d9086d2019-10-20 21:31:35 -06003588 def testPackFspS(self):
3589 """Test that an image with a FSP silicon-init binary can be created"""
3590 data = self._DoReadFile('153_intel_fsp_s.dts')
3591 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassba7985d2019-08-24 07:23:07 -06003592
Simon Glass9ea87b22019-10-20 21:31:36 -06003593 def testPackFspT(self):
3594 """Test that an image with a FSP temp-ram-init binary can be created"""
3595 data = self._DoReadFile('154_intel_fsp_t.dts')
3596 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3597
Simon Glass48f3aad2020-07-09 18:39:31 -06003598 def testMkimage(self):
3599 """Test using mkimage to build an image"""
3600 data = self._DoReadFile('156_mkimage.dts')
3601
3602 # Just check that the data appears in the file somewhere
3603 self.assertIn(U_BOOT_SPL_DATA, data)
3604
Simon Glass5e560182020-07-09 18:39:36 -06003605 def testExtblob(self):
3606 """Test an image with an external blob"""
3607 data = self._DoReadFile('157_blob_ext.dts')
3608 self.assertEqual(REFCODE_DATA, data)
3609
3610 def testExtblobMissing(self):
3611 """Test an image with a missing external blob"""
3612 with self.assertRaises(ValueError) as e:
3613 self._DoReadFile('158_blob_ext_missing.dts')
3614 self.assertIn("Filename 'missing-file' not found in input path",
3615 str(e.exception))
3616
Simon Glass5d94cc62020-07-09 18:39:38 -06003617 def testExtblobMissingOk(self):
3618 """Test an image with an missing external blob that is allowed"""
Simon Glassa003cd32020-07-09 18:39:40 -06003619 with test_util.capture_sys_output() as (stdout, stderr):
3620 self._DoTestFile('158_blob_ext_missing.dts', allow_missing=True)
3621 err = stderr.getvalue()
3622 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
3623
3624 def testExtblobMissingOkSect(self):
3625 """Test an image with an missing external blob that is allowed"""
3626 with test_util.capture_sys_output() as (stdout, stderr):
3627 self._DoTestFile('159_blob_ext_missing_sect.dts',
3628 allow_missing=True)
3629 err = stderr.getvalue()
3630 self.assertRegex(err, "Image 'main-section'.*missing.*: "
3631 "blob-ext blob-ext2")
Simon Glass5d94cc62020-07-09 18:39:38 -06003632
Simon Glasse88cef92020-07-09 18:39:41 -06003633 def testPackX86RomMeMissingDesc(self):
3634 """Test that an missing Intel descriptor entry is allowed"""
Simon Glasse88cef92020-07-09 18:39:41 -06003635 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass14c596c2020-07-25 15:11:19 -06003636 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glasse88cef92020-07-09 18:39:41 -06003637 err = stderr.getvalue()
3638 self.assertRegex(err,
3639 "Image 'main-section'.*missing.*: intel-descriptor")
3640
3641 def testPackX86RomMissingIfwi(self):
3642 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3643 self._SetupIfwi('fitimage.bin')
3644 pathname = os.path.join(self._indir, 'fitimage.bin')
3645 os.remove(pathname)
3646 with test_util.capture_sys_output() as (stdout, stderr):
3647 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3648 err = stderr.getvalue()
3649 self.assertRegex(err, "Image 'main-section'.*missing.*: intel-ifwi")
3650
Simon Glassd70829a2020-07-09 18:39:42 -06003651 def testPackOverlap(self):
3652 """Test that zero-size overlapping regions are ignored"""
3653 self._DoTestFile('160_pack_overlap_zero.dts')
3654
Simon Glass45d556d2020-07-09 18:39:45 -06003655 def testSimpleFit(self):
3656 """Test an image with a FIT inside"""
3657 data = self._DoReadFile('161_fit.dts')
3658 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3659 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3660 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3661
3662 # The data should be inside the FIT
3663 dtb = fdt.Fdt.FromData(fit_data)
3664 dtb.Scan()
3665 fnode = dtb.GetNode('/images/kernel')
3666 self.assertIn('data', fnode.props)
3667
3668 fname = os.path.join(self._indir, 'fit_data.fit')
3669 tools.WriteFile(fname, fit_data)
3670 out = tools.Run('dumpimage', '-l', fname)
3671
3672 # Check a few features to make sure the plumbing works. We don't need
3673 # to test the operation of mkimage or dumpimage here. First convert the
3674 # output into a dict where the keys are the fields printed by dumpimage
3675 # and the values are a list of values for each field
3676 lines = out.splitlines()
3677
3678 # Converts "Compression: gzip compressed" into two groups:
3679 # 'Compression' and 'gzip compressed'
3680 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3681 vals = collections.defaultdict(list)
3682 for line in lines:
3683 mat = re_line.match(line)
3684 vals[mat.group(1)].append(mat.group(2))
3685
3686 self.assertEquals('FIT description: test-desc', lines[0])
3687 self.assertIn('Created:', lines[1])
3688 self.assertIn('Image 0 (kernel)', vals)
3689 self.assertIn('Hash value', vals)
3690 data_sizes = vals.get('Data Size')
3691 self.assertIsNotNone(data_sizes)
3692 self.assertEqual(2, len(data_sizes))
3693 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
3694 self.assertEqual(len(U_BOOT_DATA), int(data_sizes[0].split()[0]))
3695 self.assertEqual(len(U_BOOT_SPL_DTB_DATA), int(data_sizes[1].split()[0]))
3696
3697 def testFitExternal(self):
Simon Glass31ee50f2020-09-01 05:13:55 -06003698 """Test an image with an FIT with external images"""
Simon Glass45d556d2020-07-09 18:39:45 -06003699 data = self._DoReadFile('162_fit_external.dts')
3700 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3701
3702 # The data should be outside the FIT
3703 dtb = fdt.Fdt.FromData(fit_data)
3704 dtb.Scan()
3705 fnode = dtb.GetNode('/images/kernel')
3706 self.assertNotIn('data', fnode.props)
Simon Glassfb30e292019-07-20 12:23:51 -06003707
Alper Nebi Yasak6aae2392020-08-31 12:58:18 +03003708 def testSectionIgnoreHashSignature(self):
3709 """Test that sections ignore hash, signature nodes for its data"""
3710 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
3711 expected = (U_BOOT_DATA + U_BOOT_DATA)
3712 self.assertEqual(expected, data)
3713
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03003714 def testPadInSections(self):
3715 """Test pad-before, pad-after for entries in sections"""
Simon Glassd12599d2020-10-26 17:40:09 -06003716 data, _, _, out_dtb_fname = self._DoReadFileDtb(
3717 '166_pad_in_sections.dts', update_dtb=True)
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03003718 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
3719 U_BOOT_DATA + tools.GetBytes(ord('!'), 6) +
3720 U_BOOT_DATA)
3721 self.assertEqual(expected, data)
3722
Simon Glassd12599d2020-10-26 17:40:09 -06003723 dtb = fdt.Fdt(out_dtb_fname)
3724 dtb.Scan()
3725 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
3726 expected = {
3727 'image-pos': 0,
3728 'offset': 0,
3729 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
3730
3731 'section:image-pos': 0,
3732 'section:offset': 0,
3733 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
3734
3735 'section/before:image-pos': 0,
3736 'section/before:offset': 0,
3737 'section/before:size': len(U_BOOT_DATA),
3738
3739 'section/u-boot:image-pos': 4,
3740 'section/u-boot:offset': 4,
3741 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
3742
3743 'section/after:image-pos': 26,
3744 'section/after:offset': 26,
3745 'section/after:size': len(U_BOOT_DATA),
3746 }
3747 self.assertEqual(expected, props)
3748
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03003749 def testFitImageSubentryAlignment(self):
3750 """Test relative alignability of FIT image subentries"""
3751 entry_args = {
3752 'test-id': TEXT_DATA,
3753 }
3754 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
3755 entry_args=entry_args)
3756 dtb = fdt.Fdt.FromData(data)
3757 dtb.Scan()
3758
3759 node = dtb.GetNode('/images/kernel')
3760 data = dtb.GetProps(node)["data"].bytes
3761 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
3762 expected = (tools.GetBytes(0, 0x20) + U_BOOT_SPL_DATA +
3763 tools.GetBytes(0, align_pad) + U_BOOT_DATA)
3764 self.assertEqual(expected, data)
3765
3766 node = dtb.GetNode('/images/fdt-1')
3767 data = dtb.GetProps(node)["data"].bytes
3768 expected = (U_BOOT_SPL_DTB_DATA + tools.GetBytes(0, 20) +
3769 tools.ToBytes(TEXT_DATA) + tools.GetBytes(0, 30) +
3770 U_BOOT_DTB_DATA)
3771 self.assertEqual(expected, data)
3772
3773 def testFitExtblobMissingOk(self):
3774 """Test a FIT with a missing external blob that is allowed"""
3775 with test_util.capture_sys_output() as (stdout, stderr):
3776 self._DoTestFile('168_fit_missing_blob.dts',
3777 allow_missing=True)
3778 err = stderr.getvalue()
Simon Glassa820af72020-09-06 10:39:09 -06003779 self.assertRegex(err, "Image 'main-section'.*missing.*: atf-bl31")
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03003780
Simon Glass21db0ff2020-09-01 05:13:54 -06003781 def testBlobNamedByArgMissing(self):
3782 """Test handling of a missing entry arg"""
3783 with self.assertRaises(ValueError) as e:
3784 self._DoReadFile('068_blob_named_by_arg.dts')
3785 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
3786 str(e.exception))
3787
Simon Glass559c4de2020-09-01 05:13:58 -06003788 def testPackBl31(self):
3789 """Test that an image with an ATF BL31 binary can be created"""
3790 data = self._DoReadFile('169_atf_bl31.dts')
3791 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
3792
Samuel Holland9d8cc632020-10-21 21:12:15 -05003793 def testPackScp(self):
3794 """Test that an image with an SCP binary can be created"""
3795 data = self._DoReadFile('172_scp.dts')
3796 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
3797
Simon Glassa435cd12020-09-01 05:13:59 -06003798 def testFitFdt(self):
3799 """Test an image with an FIT with multiple FDT images"""
3800 def _CheckFdt(seq, expected_data):
3801 """Check the FDT nodes
3802
3803 Args:
3804 seq: Sequence number to check (0 or 1)
3805 expected_data: Expected contents of 'data' property
3806 """
3807 name = 'fdt-%d' % seq
3808 fnode = dtb.GetNode('/images/%s' % name)
3809 self.assertIsNotNone(fnode)
3810 self.assertEqual({'description','type', 'compression', 'data'},
3811 set(fnode.props.keys()))
3812 self.assertEqual(expected_data, fnode.props['data'].bytes)
3813 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
3814 fnode.props['description'].value)
3815
3816 def _CheckConfig(seq, expected_data):
3817 """Check the configuration nodes
3818
3819 Args:
3820 seq: Sequence number to check (0 or 1)
3821 expected_data: Expected contents of 'data' property
3822 """
3823 cnode = dtb.GetNode('/configurations')
3824 self.assertIn('default', cnode.props)
Simon Glass1032acc2020-09-06 10:39:08 -06003825 self.assertEqual('config-2', cnode.props['default'].value)
Simon Glassa435cd12020-09-01 05:13:59 -06003826
3827 name = 'config-%d' % seq
3828 fnode = dtb.GetNode('/configurations/%s' % name)
3829 self.assertIsNotNone(fnode)
3830 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
3831 set(fnode.props.keys()))
3832 self.assertEqual('conf-test-fdt%d.dtb' % seq,
3833 fnode.props['description'].value)
3834 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
3835
3836 entry_args = {
3837 'of-list': 'test-fdt1 test-fdt2',
Simon Glass1032acc2020-09-06 10:39:08 -06003838 'default-dt': 'test-fdt2',
Simon Glassa435cd12020-09-01 05:13:59 -06003839 }
3840 data = self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08003841 '170_fit_fdt.dts',
Simon Glassa435cd12020-09-01 05:13:59 -06003842 entry_args=entry_args,
3843 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3844 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3845 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3846
3847 dtb = fdt.Fdt.FromData(fit_data)
3848 dtb.Scan()
3849 fnode = dtb.GetNode('/images/kernel')
3850 self.assertIn('data', fnode.props)
3851
3852 # Check all the properties in fdt-1 and fdt-2
3853 _CheckFdt(1, TEST_FDT1_DATA)
3854 _CheckFdt(2, TEST_FDT2_DATA)
3855
3856 # Check configurations
3857 _CheckConfig(1, TEST_FDT1_DATA)
3858 _CheckConfig(2, TEST_FDT2_DATA)
3859
3860 def testFitFdtMissingList(self):
3861 """Test handling of a missing 'of-list' entry arg"""
3862 with self.assertRaises(ValueError) as e:
Bin Meng16cf5662021-05-10 20:23:32 +08003863 self._DoReadFile('170_fit_fdt.dts')
Simon Glassa435cd12020-09-01 05:13:59 -06003864 self.assertIn("Generator node requires 'of-list' entry argument",
3865 str(e.exception))
3866
3867 def testFitFdtEmptyList(self):
3868 """Test handling of an empty 'of-list' entry arg"""
3869 entry_args = {
3870 'of-list': '',
3871 }
3872 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
3873
3874 def testFitFdtMissingProp(self):
3875 """Test handling of a missing 'fit,fdt-list' property"""
3876 with self.assertRaises(ValueError) as e:
3877 self._DoReadFile('171_fit_fdt_missing_prop.dts')
3878 self.assertIn("Generator node requires 'fit,fdt-list' property",
3879 str(e.exception))
Simon Glass559c4de2020-09-01 05:13:58 -06003880
Simon Glass1032acc2020-09-06 10:39:08 -06003881 def testFitFdtEmptyList(self):
3882 """Test handling of an empty 'of-list' entry arg"""
3883 entry_args = {
3884 'of-list': '',
3885 }
Bin Meng16cf5662021-05-10 20:23:32 +08003886 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
Simon Glass1032acc2020-09-06 10:39:08 -06003887
3888 def testFitFdtMissing(self):
3889 """Test handling of a missing 'default-dt' entry arg"""
3890 entry_args = {
3891 'of-list': 'test-fdt1 test-fdt2',
3892 }
3893 with self.assertRaises(ValueError) as e:
3894 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08003895 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06003896 entry_args=entry_args,
3897 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3898 self.assertIn("Generated 'default' node requires default-dt entry argument",
3899 str(e.exception))
3900
3901 def testFitFdtNotInList(self):
3902 """Test handling of a default-dt that is not in the of-list"""
3903 entry_args = {
3904 'of-list': 'test-fdt1 test-fdt2',
3905 'default-dt': 'test-fdt3',
3906 }
3907 with self.assertRaises(ValueError) as e:
3908 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08003909 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06003910 entry_args=entry_args,
3911 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3912 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
3913 str(e.exception))
3914
Simon Glassa820af72020-09-06 10:39:09 -06003915 def testFitExtblobMissingHelp(self):
3916 """Test display of help messages when an external blob is missing"""
3917 control.missing_blob_help = control._ReadMissingBlobHelp()
3918 control.missing_blob_help['wibble'] = 'Wibble test'
3919 control.missing_blob_help['another'] = 'Another test'
3920 with test_util.capture_sys_output() as (stdout, stderr):
3921 self._DoTestFile('168_fit_missing_blob.dts',
3922 allow_missing=True)
3923 err = stderr.getvalue()
3924
3925 # We can get the tag from the name, the type or the missing-msg
3926 # property. Check all three.
3927 self.assertIn('You may need to build ARM Trusted', err)
3928 self.assertIn('Wibble test', err)
3929 self.assertIn('Another test', err)
3930
Simon Glass6f1f4d42020-09-06 10:35:32 -06003931 def testMissingBlob(self):
3932 """Test handling of a blob containing a missing file"""
3933 with self.assertRaises(ValueError) as e:
3934 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
3935 self.assertIn("Filename 'missing' not found in input path",
3936 str(e.exception))
3937
Simon Glassa0729502020-09-06 10:35:33 -06003938 def testEnvironment(self):
3939 """Test adding a U-Boot environment"""
3940 data = self._DoReadFile('174_env.dts')
3941 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3942 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3943 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3944 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
3945 env)
3946
3947 def testEnvironmentNoSize(self):
3948 """Test that a missing 'size' property is detected"""
3949 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06003950 self._DoTestFile('175_env_no_size.dts')
Simon Glassa0729502020-09-06 10:35:33 -06003951 self.assertIn("'u-boot-env' entry must have a size property",
3952 str(e.exception))
3953
3954 def testEnvironmentTooSmall(self):
3955 """Test handling of an environment that does not fit"""
3956 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06003957 self._DoTestFile('176_env_too_small.dts')
Simon Glassa0729502020-09-06 10:35:33 -06003958
3959 # checksum, start byte, environment with \0 terminator, final \0
3960 need = 4 + 1 + len(ENV_DATA) + 1 + 1
3961 short = need - 0x8
3962 self.assertIn("too small to hold data (need %#x more bytes)" % short,
3963 str(e.exception))
3964
Simon Glassd1fdf752020-10-26 17:40:01 -06003965 def testSkipAtStart(self):
3966 """Test handling of skip-at-start section"""
3967 data = self._DoReadFile('177_skip_at_start.dts')
3968 self.assertEqual(U_BOOT_DATA, data)
3969
3970 image = control.images['image']
3971 entries = image.GetEntries()
3972 section = entries['section']
3973 self.assertEqual(0, section.offset)
3974 self.assertEqual(len(U_BOOT_DATA), section.size)
3975 self.assertEqual(U_BOOT_DATA, section.GetData())
3976
3977 entry = section.GetEntries()['u-boot']
3978 self.assertEqual(16, entry.offset)
3979 self.assertEqual(len(U_BOOT_DATA), entry.size)
3980 self.assertEqual(U_BOOT_DATA, entry.data)
3981
3982 def testSkipAtStartPad(self):
3983 """Test handling of skip-at-start section with padded entry"""
3984 data = self._DoReadFile('178_skip_at_start_pad.dts')
3985 before = tools.GetBytes(0, 8)
3986 after = tools.GetBytes(0, 4)
3987 all = before + U_BOOT_DATA + after
3988 self.assertEqual(all, data)
3989
3990 image = control.images['image']
3991 entries = image.GetEntries()
3992 section = entries['section']
3993 self.assertEqual(0, section.offset)
3994 self.assertEqual(len(all), section.size)
3995 self.assertEqual(all, section.GetData())
3996
3997 entry = section.GetEntries()['u-boot']
3998 self.assertEqual(16, entry.offset)
3999 self.assertEqual(len(all), entry.size)
4000 self.assertEqual(U_BOOT_DATA, entry.data)
4001
4002 def testSkipAtStartSectionPad(self):
4003 """Test handling of skip-at-start section with padding"""
4004 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
4005 before = tools.GetBytes(0, 8)
4006 after = tools.GetBytes(0, 4)
4007 all = before + U_BOOT_DATA + after
Simon Glass510ef0f2020-10-26 17:40:13 -06004008 self.assertEqual(all, data)
Simon Glassd1fdf752020-10-26 17:40:01 -06004009
4010 image = control.images['image']
4011 entries = image.GetEntries()
4012 section = entries['section']
4013 self.assertEqual(0, section.offset)
4014 self.assertEqual(len(all), section.size)
Simon Glass72eeff12020-10-26 17:40:16 -06004015 self.assertEqual(U_BOOT_DATA, section.data)
Simon Glass510ef0f2020-10-26 17:40:13 -06004016 self.assertEqual(all, section.GetPaddedData())
Simon Glassd1fdf752020-10-26 17:40:01 -06004017
4018 entry = section.GetEntries()['u-boot']
4019 self.assertEqual(16, entry.offset)
4020 self.assertEqual(len(U_BOOT_DATA), entry.size)
4021 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassa0729502020-09-06 10:35:33 -06004022
Simon Glassbb395742020-10-26 17:40:14 -06004023 def testSectionPad(self):
4024 """Testing padding with sections"""
4025 data = self._DoReadFile('180_section_pad.dts')
4026 expected = (tools.GetBytes(ord('&'), 3) +
4027 tools.GetBytes(ord('!'), 5) +
4028 U_BOOT_DATA +
4029 tools.GetBytes(ord('!'), 1) +
4030 tools.GetBytes(ord('&'), 2))
4031 self.assertEqual(expected, data)
4032
4033 def testSectionAlign(self):
4034 """Testing alignment with sections"""
4035 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4036 expected = (b'\0' + # fill section
4037 tools.GetBytes(ord('&'), 1) + # padding to section align
4038 b'\0' + # fill section
4039 tools.GetBytes(ord('!'), 3) + # padding to u-boot align
4040 U_BOOT_DATA +
4041 tools.GetBytes(ord('!'), 4) + # padding to u-boot size
4042 tools.GetBytes(ord('!'), 4)) # padding to section size
4043 self.assertEqual(expected, data)
4044
Simon Glassd92c8362020-10-26 17:40:25 -06004045 def testCompressImage(self):
4046 """Test compression of the entire image"""
4047 self._CheckLz4()
4048 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4049 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4050 dtb = fdt.Fdt(out_dtb_fname)
4051 dtb.Scan()
4052 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4053 'uncomp-size'])
4054 orig = self._decompress(data)
4055 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4056
4057 # Do a sanity check on various fields
4058 image = control.images['image']
4059 entries = image.GetEntries()
4060 self.assertEqual(2, len(entries))
4061
4062 entry = entries['blob']
4063 self.assertEqual(COMPRESS_DATA, entry.data)
4064 self.assertEqual(len(COMPRESS_DATA), entry.size)
4065
4066 entry = entries['u-boot']
4067 self.assertEqual(U_BOOT_DATA, entry.data)
4068 self.assertEqual(len(U_BOOT_DATA), entry.size)
4069
4070 self.assertEqual(len(data), image.size)
4071 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4072 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4073 orig = self._decompress(image.data)
4074 self.assertEqual(orig, image.uncomp_data)
4075
4076 expected = {
4077 'blob:offset': 0,
4078 'blob:size': len(COMPRESS_DATA),
4079 'u-boot:offset': len(COMPRESS_DATA),
4080 'u-boot:size': len(U_BOOT_DATA),
4081 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4082 'offset': 0,
4083 'image-pos': 0,
4084 'size': len(data),
4085 }
4086 self.assertEqual(expected, props)
4087
4088 def testCompressImageLess(self):
4089 """Test compression where compression reduces the image size"""
4090 self._CheckLz4()
4091 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4092 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4093 dtb = fdt.Fdt(out_dtb_fname)
4094 dtb.Scan()
4095 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4096 'uncomp-size'])
4097 orig = self._decompress(data)
4098
4099 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
4100
4101 # Do a sanity check on various fields
4102 image = control.images['image']
4103 entries = image.GetEntries()
4104 self.assertEqual(2, len(entries))
4105
4106 entry = entries['blob']
4107 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4108 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4109
4110 entry = entries['u-boot']
4111 self.assertEqual(U_BOOT_DATA, entry.data)
4112 self.assertEqual(len(U_BOOT_DATA), entry.size)
4113
4114 self.assertEqual(len(data), image.size)
4115 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4116 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4117 image.uncomp_size)
4118 orig = self._decompress(image.data)
4119 self.assertEqual(orig, image.uncomp_data)
4120
4121 expected = {
4122 'blob:offset': 0,
4123 'blob:size': len(COMPRESS_DATA_BIG),
4124 'u-boot:offset': len(COMPRESS_DATA_BIG),
4125 'u-boot:size': len(U_BOOT_DATA),
4126 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4127 'offset': 0,
4128 'image-pos': 0,
4129 'size': len(data),
4130 }
4131 self.assertEqual(expected, props)
4132
4133 def testCompressSectionSize(self):
4134 """Test compression of a section with a fixed size"""
4135 self._CheckLz4()
4136 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4137 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4138 dtb = fdt.Fdt(out_dtb_fname)
4139 dtb.Scan()
4140 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4141 'uncomp-size'])
4142 orig = self._decompress(data)
4143 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4144 expected = {
4145 'section/blob:offset': 0,
4146 'section/blob:size': len(COMPRESS_DATA),
4147 'section/u-boot:offset': len(COMPRESS_DATA),
4148 'section/u-boot:size': len(U_BOOT_DATA),
4149 'section:offset': 0,
4150 'section:image-pos': 0,
4151 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4152 'section:size': 0x30,
4153 'offset': 0,
4154 'image-pos': 0,
4155 'size': 0x30,
4156 }
4157 self.assertEqual(expected, props)
4158
4159 def testCompressSection(self):
4160 """Test compression of a section with no fixed size"""
4161 self._CheckLz4()
4162 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4163 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4164 dtb = fdt.Fdt(out_dtb_fname)
4165 dtb.Scan()
4166 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4167 'uncomp-size'])
4168 orig = self._decompress(data)
4169 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4170 expected = {
4171 'section/blob:offset': 0,
4172 'section/blob:size': len(COMPRESS_DATA),
4173 'section/u-boot:offset': len(COMPRESS_DATA),
4174 'section/u-boot:size': len(U_BOOT_DATA),
4175 'section:offset': 0,
4176 'section:image-pos': 0,
4177 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4178 'section:size': len(data),
4179 'offset': 0,
4180 'image-pos': 0,
4181 'size': len(data),
4182 }
4183 self.assertEqual(expected, props)
4184
4185 def testCompressExtra(self):
4186 """Test compression of a section with no fixed size"""
4187 self._CheckLz4()
4188 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4189 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4190 dtb = fdt.Fdt(out_dtb_fname)
4191 dtb.Scan()
4192 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4193 'uncomp-size'])
4194
4195 base = data[len(U_BOOT_DATA):]
4196 self.assertEquals(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
4197 rest = base[len(U_BOOT_DATA):]
4198
4199 # Check compressed data
4200 section1 = self._decompress(rest)
4201 expect1 = tools.Compress(COMPRESS_DATA + U_BOOT_DATA, 'lz4')
4202 self.assertEquals(expect1, rest[:len(expect1)])
4203 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, section1)
4204 rest1 = rest[len(expect1):]
4205
4206 section2 = self._decompress(rest1)
4207 expect2 = tools.Compress(COMPRESS_DATA + COMPRESS_DATA, 'lz4')
4208 self.assertEquals(expect2, rest1[:len(expect2)])
4209 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA, section2)
4210 rest2 = rest1[len(expect2):]
4211
4212 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4213 len(expect2) + len(U_BOOT_DATA))
4214 #self.assertEquals(expect_size, len(data))
4215
4216 #self.assertEquals(U_BOOT_DATA, rest2)
4217
4218 self.maxDiff = None
4219 expected = {
4220 'u-boot:offset': 0,
4221 'u-boot:image-pos': 0,
4222 'u-boot:size': len(U_BOOT_DATA),
4223
4224 'base:offset': len(U_BOOT_DATA),
4225 'base:image-pos': len(U_BOOT_DATA),
4226 'base:size': len(data) - len(U_BOOT_DATA),
4227 'base/u-boot:offset': 0,
4228 'base/u-boot:image-pos': len(U_BOOT_DATA),
4229 'base/u-boot:size': len(U_BOOT_DATA),
4230 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4231 len(expect2),
4232 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4233 len(expect2),
4234 'base/u-boot2:size': len(U_BOOT_DATA),
4235
4236 'base/section:offset': len(U_BOOT_DATA),
4237 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4238 'base/section:size': len(expect1),
4239 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4240 'base/section/blob:offset': 0,
4241 'base/section/blob:size': len(COMPRESS_DATA),
4242 'base/section/u-boot:offset': len(COMPRESS_DATA),
4243 'base/section/u-boot:size': len(U_BOOT_DATA),
4244
4245 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4246 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4247 'base/section2:size': len(expect2),
4248 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4249 'base/section2/blob:offset': 0,
4250 'base/section2/blob:size': len(COMPRESS_DATA),
4251 'base/section2/blob2:offset': len(COMPRESS_DATA),
4252 'base/section2/blob2:size': len(COMPRESS_DATA),
4253
4254 'offset': 0,
4255 'image-pos': 0,
4256 'size': len(data),
4257 }
4258 self.assertEqual(expected, props)
4259
Simon Glassecbe4732021-01-06 21:35:15 -07004260 def testSymbolsSubsection(self):
4261 """Test binman can assign symbols from a subsection"""
Simon Glass31e04cb2021-03-18 20:24:56 +13004262 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x18)
Simon Glassecbe4732021-01-06 21:35:15 -07004263
Simon Glass3fb25402021-01-06 21:35:16 -07004264 def testReadImageEntryArg(self):
4265 """Test reading an image that would need an entry arg to generate"""
4266 entry_args = {
4267 'cros-ec-rw-path': 'ecrw.bin',
4268 }
4269 data = self.data = self._DoReadFileDtb(
4270 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4271 entry_args=entry_args)
4272
4273 image_fname = tools.GetOutputFilename('image.bin')
4274 orig_image = control.images['image']
4275
4276 # This should not generate an error about the missing 'cros-ec-rw-path'
4277 # since we are reading the image from a file. Compare with
4278 # testEntryArgsRequired()
4279 image = Image.FromFile(image_fname)
4280 self.assertEqual(orig_image.GetEntries().keys(),
4281 image.GetEntries().keys())
4282
Simon Glassa2af7302021-01-06 21:35:18 -07004283 def testFilesAlign(self):
4284 """Test alignment with files"""
4285 data = self._DoReadFile('190_files_align.dts')
4286
4287 # The first string is 15 bytes so will align to 16
4288 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4289 self.assertEqual(expect, data)
4290
Simon Glassdb84b562021-01-06 21:35:19 -07004291 def testReadImageSkip(self):
4292 """Test reading an image and accessing its FDT map"""
4293 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
4294 image_fname = tools.GetOutputFilename('image.bin')
4295 orig_image = control.images['image']
4296 image = Image.FromFile(image_fname)
4297 self.assertEqual(orig_image.GetEntries().keys(),
4298 image.GetEntries().keys())
4299
4300 orig_entry = orig_image.GetEntries()['fdtmap']
4301 entry = image.GetEntries()['fdtmap']
4302 self.assertEqual(orig_entry.offset, entry.offset)
4303 self.assertEqual(orig_entry.size, entry.size)
4304 self.assertEqual(16, entry.image_pos)
4305
4306 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4307
4308 self.assertEquals(U_BOOT_DATA, u_boot.ReadData())
4309
Simon Glassc98de972021-03-18 20:24:57 +13004310 def testTplNoDtb(self):
4311 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12004312 self._SetupTplElf()
Simon Glassc98de972021-03-18 20:24:57 +13004313 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4314 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4315 data[:len(U_BOOT_TPL_NODTB_DATA)])
4316
Simon Glass63f41d42021-03-18 20:24:58 +13004317 def testTplBssPad(self):
4318 """Test that we can pad TPL's BSS with zeros"""
4319 # ELF file with a '__bss_size' symbol
4320 self._SetupTplElf()
4321 data = self._DoReadFile('193_tpl_bss_pad.dts')
4322 self.assertEqual(U_BOOT_TPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
4323 data)
4324
4325 def testTplBssPadMissing(self):
4326 """Test that a missing symbol is detected"""
4327 self._SetupTplElf('u_boot_ucode_ptr')
4328 with self.assertRaises(ValueError) as e:
4329 self._DoReadFile('193_tpl_bss_pad.dts')
4330 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4331 str(e.exception))
4332
Simon Glass718b5292021-03-18 20:25:07 +13004333 def checkDtbSizes(self, data, pad_len, start):
4334 """Check the size arguments in a dtb embedded in an image
4335
4336 Args:
4337 data: The image data
4338 pad_len: Length of the pad section in the image, in bytes
4339 start: Start offset of the devicetree to examine, within the image
4340
4341 Returns:
4342 Size of the devicetree in bytes
4343 """
4344 dtb_data = data[start:]
4345 dtb = fdt.Fdt.FromData(dtb_data)
4346 fdt_size = dtb.GetFdtObj().totalsize()
4347 dtb.Scan()
4348 props = self._GetPropTree(dtb, 'size')
4349 self.assertEqual({
4350 'size': len(data),
4351 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4352 'u-boot-spl/u-boot-spl-dtb:size': 801,
4353 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4354 'u-boot-spl:size': 860,
4355 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4356 'u-boot/u-boot-dtb:size': 781,
4357 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4358 'u-boot:size': 827,
4359 }, props)
4360 return fdt_size
4361
4362 def testExpanded(self):
4363 """Test that an expanded entry type is selected when needed"""
4364 self._SetupSplElf()
4365 self._SetupTplElf()
4366
4367 # SPL has a devicetree, TPL does not
4368 entry_args = {
4369 'spl-dtb': '1',
4370 'spl-bss-pad': 'y',
4371 'tpl-dtb': '',
4372 }
4373 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4374 entry_args=entry_args)
4375 image = control.images['image']
4376 entries = image.GetEntries()
4377 self.assertEqual(3, len(entries))
4378
4379 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4380 self.assertIn('u-boot', entries)
4381 entry = entries['u-boot']
4382 self.assertEqual('u-boot-expanded', entry.etype)
4383 subent = entry.GetEntries()
4384 self.assertEqual(2, len(subent))
4385 self.assertIn('u-boot-nodtb', subent)
4386 self.assertIn('u-boot-dtb', subent)
4387
4388 # Second, u-boot-spl, which should be expanded into three parts
4389 self.assertIn('u-boot-spl', entries)
4390 entry = entries['u-boot-spl']
4391 self.assertEqual('u-boot-spl-expanded', entry.etype)
4392 subent = entry.GetEntries()
4393 self.assertEqual(3, len(subent))
4394 self.assertIn('u-boot-spl-nodtb', subent)
4395 self.assertIn('u-boot-spl-bss-pad', subent)
4396 self.assertIn('u-boot-spl-dtb', subent)
4397
4398 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4399 # devicetree
4400 self.assertIn('u-boot-tpl', entries)
4401 entry = entries['u-boot-tpl']
4402 self.assertEqual('u-boot-tpl', entry.etype)
4403 self.assertEqual(None, entry.GetEntries())
4404
4405 def testExpandedTpl(self):
4406 """Test that an expanded entry type is selected for TPL when needed"""
4407 self._SetupTplElf()
4408
4409 entry_args = {
4410 'tpl-bss-pad': 'y',
4411 'tpl-dtb': 'y',
4412 }
4413 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4414 entry_args=entry_args)
4415 image = control.images['image']
4416 entries = image.GetEntries()
4417 self.assertEqual(1, len(entries))
4418
4419 # We only have u-boot-tpl, which be expanded
4420 self.assertIn('u-boot-tpl', entries)
4421 entry = entries['u-boot-tpl']
4422 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4423 subent = entry.GetEntries()
4424 self.assertEqual(3, len(subent))
4425 self.assertIn('u-boot-tpl-nodtb', subent)
4426 self.assertIn('u-boot-tpl-bss-pad', subent)
4427 self.assertIn('u-boot-tpl-dtb', subent)
4428
4429 def testExpandedNoPad(self):
4430 """Test an expanded entry without BSS pad enabled"""
4431 self._SetupSplElf()
4432 self._SetupTplElf()
4433
4434 # SPL has a devicetree, TPL does not
4435 entry_args = {
4436 'spl-dtb': 'something',
4437 'spl-bss-pad': 'n',
4438 'tpl-dtb': '',
4439 }
4440 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4441 entry_args=entry_args)
4442 image = control.images['image']
4443 entries = image.GetEntries()
4444
4445 # Just check u-boot-spl, which should be expanded into two parts
4446 self.assertIn('u-boot-spl', entries)
4447 entry = entries['u-boot-spl']
4448 self.assertEqual('u-boot-spl-expanded', entry.etype)
4449 subent = entry.GetEntries()
4450 self.assertEqual(2, len(subent))
4451 self.assertIn('u-boot-spl-nodtb', subent)
4452 self.assertIn('u-boot-spl-dtb', subent)
4453
4454 def testExpandedTplNoPad(self):
4455 """Test that an expanded entry type with padding disabled in TPL"""
4456 self._SetupTplElf()
4457
4458 entry_args = {
4459 'tpl-bss-pad': '',
4460 'tpl-dtb': 'y',
4461 }
4462 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4463 entry_args=entry_args)
4464 image = control.images['image']
4465 entries = image.GetEntries()
4466 self.assertEqual(1, len(entries))
4467
4468 # We only have u-boot-tpl, which be expanded
4469 self.assertIn('u-boot-tpl', entries)
4470 entry = entries['u-boot-tpl']
4471 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4472 subent = entry.GetEntries()
4473 self.assertEqual(2, len(subent))
4474 self.assertIn('u-boot-tpl-nodtb', subent)
4475 self.assertIn('u-boot-tpl-dtb', subent)
4476
4477 def testFdtInclude(self):
4478 """Test that an Fdt is update within all binaries"""
4479 self._SetupSplElf()
4480 self._SetupTplElf()
4481
4482 # SPL has a devicetree, TPL does not
4483 self.maxDiff = None
4484 entry_args = {
4485 'spl-dtb': '1',
4486 'spl-bss-pad': 'y',
4487 'tpl-dtb': '',
4488 }
4489 # Build the image. It includes two separate devicetree binaries, each
4490 # with their own contents, but all contain the binman definition.
4491 data = self._DoReadFileDtb(
4492 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4493 update_dtb=True, entry_args=entry_args)[0]
4494 pad_len = 10
4495
4496 # Check the U-Boot dtb
4497 start = len(U_BOOT_NODTB_DATA)
4498 fdt_size = self.checkDtbSizes(data, pad_len, start)
4499
4500 # Now check SPL
4501 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4502 fdt_size = self.checkDtbSizes(data, pad_len, start)
4503
4504 # TPL has no devicetree
4505 start += fdt_size + len(U_BOOT_TPL_DATA)
4506 self.assertEqual(len(data), start)
Simon Glassbb395742020-10-26 17:40:14 -06004507
Simon Glass7098b7f2021-03-21 18:24:30 +13004508 def testSymbolsExpanded(self):
4509 """Test binman can assign symbols in expanded entries"""
4510 entry_args = {
4511 'spl-dtb': '1',
4512 }
4513 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4514 U_BOOT_SPL_DTB_DATA, 0x38,
4515 entry_args=entry_args, use_expanded=True)
4516
Simon Glasse1915782021-03-21 18:24:31 +13004517 def testCollection(self):
4518 """Test a collection"""
4519 data = self._DoReadFile('198_collection.dts')
4520 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
4521 tools.GetBytes(0xff, 2) + U_BOOT_NODTB_DATA +
4522 tools.GetBytes(0xfe, 3) + U_BOOT_DTB_DATA,
4523 data)
4524
Simon Glass27a7f772021-03-21 18:24:32 +13004525 def testCollectionSection(self):
4526 """Test a collection where a section must be built first"""
4527 # Sections never have their contents when GetData() is called, but when
4528 # _BuildSectionData() is called with required=True, a section will force
4529 # building the contents, producing an error is anything is still
4530 # missing.
4531 data = self._DoReadFile('199_collection_section.dts')
4532 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
4533 self.assertEqual(section + U_BOOT_DATA + tools.GetBytes(0xff, 2) +
4534 section + tools.GetBytes(0xfe, 3) + U_BOOT_DATA,
4535 data)
4536
Simon Glassf427c5f2021-03-21 18:24:33 +13004537 def testAlignDefault(self):
4538 """Test that default alignment works on sections"""
4539 data = self._DoReadFile('200_align_default.dts')
4540 expected = (U_BOOT_DATA + tools.GetBytes(0, 8 - len(U_BOOT_DATA)) +
4541 U_BOOT_DATA)
4542 # Special alignment for section
4543 expected += tools.GetBytes(0, 32 - len(expected))
4544 # No alignment within the nested section
4545 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
4546 # Now the final piece, which should be default-aligned
4547 expected += tools.GetBytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
4548 self.assertEqual(expected, data)
Simon Glass27a7f772021-03-21 18:24:32 +13004549
Bin Mengc0b15742021-05-10 20:23:33 +08004550 def testPackOpenSBI(self):
4551 """Test that an image with an OpenSBI binary can be created"""
4552 data = self._DoReadFile('201_opensbi.dts')
4553 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
4554
Simon Glass76f496d2021-07-06 10:36:37 -06004555 def testSectionsSingleThread(self):
4556 """Test sections without multithreading"""
4557 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
4558 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
4559 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
4560 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
4561 self.assertEqual(expected, data)
4562
4563 def testThreadTimeout(self):
4564 """Test handling a thread that takes too long"""
4565 with self.assertRaises(ValueError) as e:
4566 self._DoTestFile('202_section_timeout.dts',
4567 test_section_timeout=True)
4568 self.assertIn("Node '/binman/section@0': Timed out obtaining contents",
4569 str(e.exception))
4570
Simon Glass748a1d42021-07-06 10:36:41 -06004571 def testTiming(self):
4572 """Test output of timing information"""
4573 data = self._DoReadFile('055_sections.dts')
4574 with test_util.capture_sys_output() as (stdout, stderr):
4575 state.TimingShow()
4576 self.assertIn('read:', stdout.getvalue())
4577 self.assertIn('compress:', stdout.getvalue())
4578
Simon Glass76f496d2021-07-06 10:36:37 -06004579
Simon Glassac599912017-11-12 21:52:22 -07004580if __name__ == "__main__":
4581 unittest.main()