blob: b771b9d5df71c6cc6343bd1c5f1b5f1182801750 [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 Glass303f62f2019-05-17 22:00:46 -060073REFCODE_DATA = b'refcode'
Simon Glassba7985d2019-08-24 07:23:07 -060074FSP_M_DATA = b'fsp_m'
Simon Glass4d9086d2019-10-20 21:31:35 -060075FSP_S_DATA = b'fsp_s'
Simon Glass9ea87b22019-10-20 21:31:36 -060076FSP_T_DATA = b'fsp_t'
Simon Glass559c4de2020-09-01 05:13:58 -060077ATF_BL31_DATA = b'bl31'
Simon Glassa435cd12020-09-01 05:13:59 -060078TEST_FDT1_DATA = b'fdt1'
79TEST_FDT2_DATA = b'test-fdt2'
Simon Glassa0729502020-09-06 10:35:33 -060080ENV_DATA = b'var1=1\nvar2="2"'
Simon Glassa435cd12020-09-01 05:13:59 -060081
82# Subdirectory of the input dir to use to put test FDTs
83TEST_FDT_SUBDIR = 'fdts'
Simon Glassdb168d42018-07-17 13:25:39 -060084
Simon Glass2c6adba2019-07-20 12:23:47 -060085# The expected size for the device tree in some tests
Simon Glass4c613bf2019-07-08 14:25:50 -060086EXTRACT_DTB_SIZE = 0x3c9
87
Simon Glass2c6adba2019-07-20 12:23:47 -060088# Properties expected to be in the device tree when update_dtb is used
89BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
90
Simon Glassfb30e292019-07-20 12:23:51 -060091# Extra properties expected to be in the device tree when allow-repack is used
92REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
93
Simon Glass57454f42016-11-25 20:15:52 -070094
95class TestFunctional(unittest.TestCase):
96 """Functional tests for binman
97
98 Most of these use a sample .dts file to build an image and then check
99 that it looks correct. The sample files are in the test/ subdirectory
100 and are numbered.
101
102 For each entry type a very small test file is created using fixed
103 string contents. This makes it easy to test that things look right, and
104 debug problems.
105
106 In some cases a 'real' file must be used - these are also supplied in
107 the test/ diurectory.
108 """
109 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600110 def setUpClass(cls):
Simon Glassb3393262017-11-12 21:52:20 -0700111 global entry
Simon Glassc585dd42020-04-17 18:09:03 -0600112 from binman import entry
Simon Glassb3393262017-11-12 21:52:20 -0700113
Simon Glass57454f42016-11-25 20:15:52 -0700114 # Handle the case where argv[0] is 'python'
Simon Glass862f8e22019-08-24 07:22:43 -0600115 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
116 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
Simon Glass57454f42016-11-25 20:15:52 -0700117
118 # Create a temporary directory for input files
Simon Glass862f8e22019-08-24 07:22:43 -0600119 cls._indir = tempfile.mkdtemp(prefix='binmant.')
Simon Glass57454f42016-11-25 20:15:52 -0700120
121 # Create some test files
122 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
123 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
124 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glass8425a1f2018-07-17 13:25:48 -0600125 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700126 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glass72232452016-11-25 20:15:53 -0700127 TestFunctional._MakeInputFile('me.bin', ME_DATA)
128 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glass862f8e22019-08-24 07:22:43 -0600129 cls._ResetDtbs()
Simon Glass0b074d62019-08-24 07:22:48 -0600130
Jagdish Gediya311d4842018-09-03 21:35:08 +0530131 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glass0b074d62019-08-24 07:22:48 -0600132
Simon Glassabab18c2019-08-24 07:22:49 -0600133 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
134 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
Simon Glasse83679d2017-11-12 21:52:26 -0700135 X86_START16_SPL_DATA)
Simon Glassabab18c2019-08-24 07:22:49 -0600136 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
Simon Glassed40e962018-09-14 04:57:10 -0600137 X86_START16_TPL_DATA)
Simon Glass0b074d62019-08-24 07:22:48 -0600138
139 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
140 X86_RESET16_DATA)
141 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
142 X86_RESET16_SPL_DATA)
143 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
144 X86_RESET16_TPL_DATA)
145
Simon Glass57454f42016-11-25 20:15:52 -0700146 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass3d274232017-11-12 21:52:27 -0700147 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
148 U_BOOT_SPL_NODTB_DATA)
Simon Glass3fb4f422018-09-14 04:57:32 -0600149 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
150 U_BOOT_TPL_NODTB_DATA)
Simon Glassb4176d42016-11-25 20:15:56 -0700151 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
152 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Mengd7bcdf52017-08-15 22:41:54 -0700153 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassa409c932017-11-12 21:52:28 -0700154 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassdb168d42018-07-17 13:25:39 -0600155 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600156 TestFunctional._MakeInputDir('devkeys')
157 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass41902e42018-10-01 12:22:31 -0600158 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glassba7985d2019-08-24 07:23:07 -0600159 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
Simon Glass4d9086d2019-10-20 21:31:35 -0600160 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
Simon Glass9ea87b22019-10-20 21:31:36 -0600161 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700162
Simon Glassf6290892019-08-24 07:22:53 -0600163 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
164 elf_test.BuildElfTestFiles(cls._elf_testdir)
165
Simon Glass72232452016-11-25 20:15:53 -0700166 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glass4affd4b2019-08-24 07:22:54 -0600167 TestFunctional._MakeInputFile('u-boot',
168 tools.ReadFile(cls.ElfTestFile('u_boot_ucode_ptr')))
Simon Glass72232452016-11-25 20:15:53 -0700169
170 # Intel flash descriptor file
Simon Glasse88cef92020-07-09 18:39:41 -0600171 cls._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -0700172
Simon Glass862f8e22019-08-24 07:22:43 -0600173 shutil.copytree(cls.TestFile('files'),
174 os.path.join(cls._indir, 'files'))
Simon Glassac6328c2018-09-14 04:57:28 -0600175
Simon Glass7ba33592018-09-14 04:57:26 -0600176 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
Simon Glass559c4de2020-09-01 05:13:58 -0600177 TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
Simon Glass7ba33592018-09-14 04:57:26 -0600178
Simon Glassa435cd12020-09-01 05:13:59 -0600179 # Add a few .dtb files for testing
180 TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR,
181 TEST_FDT1_DATA)
182 TestFunctional._MakeInputFile('%s/test-fdt2.dtb' % TEST_FDT_SUBDIR,
183 TEST_FDT2_DATA)
184
Simon Glassa0729502020-09-06 10:35:33 -0600185 TestFunctional._MakeInputFile('env.txt', ENV_DATA)
186
Simon Glass1de34482019-07-08 13:18:53 -0600187 # Travis-CI may have an old lz4
Simon Glass862f8e22019-08-24 07:22:43 -0600188 cls.have_lz4 = True
Simon Glass1de34482019-07-08 13:18:53 -0600189 try:
190 tools.Run('lz4', '--no-frame-crc', '-c',
Simon Glasscc311ac2019-10-31 07:42:50 -0600191 os.path.join(cls._indir, 'u-boot.bin'), binary=True)
Simon Glass1de34482019-07-08 13:18:53 -0600192 except:
Simon Glass862f8e22019-08-24 07:22:43 -0600193 cls.have_lz4 = False
Simon Glass1de34482019-07-08 13:18:53 -0600194
Simon Glass57454f42016-11-25 20:15:52 -0700195 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600196 def tearDownClass(cls):
Simon Glass57454f42016-11-25 20:15:52 -0700197 """Remove the temporary input directory and its contents"""
Simon Glass862f8e22019-08-24 07:22:43 -0600198 if cls.preserve_indir:
199 print('Preserving input dir: %s' % cls._indir)
Simon Glass1c420c92019-07-08 13:18:49 -0600200 else:
Simon Glass862f8e22019-08-24 07:22:43 -0600201 if cls._indir:
202 shutil.rmtree(cls._indir)
203 cls._indir = None
Simon Glass57454f42016-11-25 20:15:52 -0700204
Simon Glass1c420c92019-07-08 13:18:49 -0600205 @classmethod
Simon Glasscebfab22019-07-08 13:18:50 -0600206 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
Simon Glassf46732a2019-07-08 14:25:29 -0600207 toolpath=None, verbosity=None):
Simon Glass1c420c92019-07-08 13:18:49 -0600208 """Accept arguments controlling test execution
209
210 Args:
211 preserve_indir: Preserve the shared input directory used by all
212 tests in this class.
213 preserve_outdir: Preserve the output directories used by tests. Each
214 test has its own, so this is normally only useful when running a
215 single test.
Simon Glasscebfab22019-07-08 13:18:50 -0600216 toolpath: ist of paths to use for tools
Simon Glass1c420c92019-07-08 13:18:49 -0600217 """
218 cls.preserve_indir = preserve_indir
219 cls.preserve_outdirs = preserve_outdirs
Simon Glasscebfab22019-07-08 13:18:50 -0600220 cls.toolpath = toolpath
Simon Glassf46732a2019-07-08 14:25:29 -0600221 cls.verbosity = verbosity
Simon Glass1c420c92019-07-08 13:18:49 -0600222
Simon Glass1de34482019-07-08 13:18:53 -0600223 def _CheckLz4(self):
224 if not self.have_lz4:
225 self.skipTest('lz4 --no-frame-crc not available')
226
Simon Glassee9d10d2019-07-20 12:24:09 -0600227 def _CleanupOutputDir(self):
228 """Remove the temporary output directory"""
229 if self.preserve_outdirs:
230 print('Preserving output dir: %s' % tools.outdir)
231 else:
232 tools._FinaliseForTest()
233
Simon Glass57454f42016-11-25 20:15:52 -0700234 def setUp(self):
235 # Enable this to turn on debugging output
236 # tout.Init(tout.DEBUG)
237 command.test_result = None
238
239 def tearDown(self):
240 """Remove the temporary output directory"""
Simon Glassee9d10d2019-07-20 12:24:09 -0600241 self._CleanupOutputDir()
Simon Glass57454f42016-11-25 20:15:52 -0700242
Simon Glassb3d6fc72019-07-20 12:24:10 -0600243 def _SetupImageInTmpdir(self):
244 """Set up the output image in a new temporary directory
245
246 This is used when an image has been generated in the output directory,
247 but we want to run binman again. This will create a new output
248 directory and fail to delete the original one.
249
250 This creates a new temporary directory, copies the image to it (with a
251 new name) and removes the old output directory.
252
253 Returns:
254 Tuple:
255 Temporary directory to use
256 New image filename
257 """
258 image_fname = tools.GetOutputFilename('image.bin')
259 tmpdir = tempfile.mkdtemp(prefix='binman.')
260 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
261 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
262 self._CleanupOutputDir()
263 return tmpdir, updated_fname
264
Simon Glass8425a1f2018-07-17 13:25:48 -0600265 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600266 def _ResetDtbs(cls):
Simon Glass8425a1f2018-07-17 13:25:48 -0600267 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
268 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
269 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
270
Simon Glass57454f42016-11-25 20:15:52 -0700271 def _RunBinman(self, *args, **kwargs):
272 """Run binman using the command line
273
274 Args:
275 Arguments to pass, as a list of strings
276 kwargs: Arguments to pass to Command.RunPipe()
277 """
278 result = command.RunPipe([[self._binman_pathname] + list(args)],
279 capture=True, capture_stderr=True, raise_on_error=False)
280 if result.return_code and kwargs.get('raise_on_error', True):
281 raise Exception("Error running '%s': %s" % (' '.join(args),
282 result.stdout + result.stderr))
283 return result
284
Simon Glassf46732a2019-07-08 14:25:29 -0600285 def _DoBinman(self, *argv):
Simon Glass57454f42016-11-25 20:15:52 -0700286 """Run binman using directly (in the same process)
287
288 Args:
289 Arguments to pass, as a list of strings
290 Returns:
291 Return value (0 for success)
292 """
Simon Glassf46732a2019-07-08 14:25:29 -0600293 argv = list(argv)
294 args = cmdline.ParseArgs(argv)
295 args.pager = 'binman-invalid-pager'
296 args.build_dir = self._indir
Simon Glass57454f42016-11-25 20:15:52 -0700297
298 # For testing, you can force an increase in verbosity here
Simon Glassf46732a2019-07-08 14:25:29 -0600299 # args.verbosity = tout.DEBUG
300 return control.Binman(args)
Simon Glass57454f42016-11-25 20:15:52 -0700301
Simon Glass91710b32018-07-17 13:25:32 -0600302 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glassb4595d82019-04-25 21:58:34 -0600303 entry_args=None, images=None, use_real_dtb=False,
Simon Glassa435cd12020-09-01 05:13:59 -0600304 verbosity=None, allow_missing=False, extra_indirs=None):
Simon Glass57454f42016-11-25 20:15:52 -0700305 """Run binman with a given test file
306
307 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600308 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600309 debug: True to enable debugging output
Simon Glass30732662018-06-01 09:38:20 -0600310 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600311 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600312 tree before packing it into the image
Simon Glass3b376c32018-09-14 04:57:12 -0600313 entry_args: Dict of entry args to supply to binman
314 key: arg name
315 value: value of that arg
316 images: List of image names to build
Simon Glass31ee50f2020-09-01 05:13:55 -0600317 use_real_dtb: True to use the test file as the contents of
318 the u-boot-dtb entry. Normally this is not needed and the
319 test contents (the U_BOOT_DTB_DATA string) can be used.
320 But in some test we need the real contents.
321 verbosity: Verbosity level to use (0-3, None=don't set it)
322 allow_missing: Set the '--allow-missing' flag so that missing
323 external binaries just produce a warning instead of an error
Simon Glassa435cd12020-09-01 05:13:59 -0600324 extra_indirs: Extra input directories to add using -I
Simon Glass57454f42016-11-25 20:15:52 -0700325 """
Simon Glassf46732a2019-07-08 14:25:29 -0600326 args = []
Simon Glass075a45c2017-11-13 18:55:00 -0700327 if debug:
328 args.append('-D')
Simon Glassf46732a2019-07-08 14:25:29 -0600329 if verbosity is not None:
330 args.append('-v%d' % verbosity)
331 elif self.verbosity:
332 args.append('-v%d' % self.verbosity)
333 if self.toolpath:
334 for path in self.toolpath:
335 args += ['--toolpath', path]
336 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass30732662018-06-01 09:38:20 -0600337 if map:
338 args.append('-m')
Simon Glassa87014e2018-07-06 10:27:42 -0600339 if update_dtb:
Simon Glass38a411c2019-07-08 13:18:47 -0600340 args.append('-u')
Simon Glass31402012018-09-14 04:57:23 -0600341 if not use_real_dtb:
342 args.append('--fake-dtb')
Simon Glass91710b32018-07-17 13:25:32 -0600343 if entry_args:
Simon Glass5f3645b2019-05-14 15:53:41 -0600344 for arg, value in entry_args.items():
Simon Glass91710b32018-07-17 13:25:32 -0600345 args.append('-a%s=%s' % (arg, value))
Simon Glass5d94cc62020-07-09 18:39:38 -0600346 if allow_missing:
347 args.append('-M')
Simon Glass3b376c32018-09-14 04:57:12 -0600348 if images:
349 for image in images:
350 args += ['-i', image]
Simon Glassa435cd12020-09-01 05:13:59 -0600351 if extra_indirs:
352 for indir in extra_indirs:
353 args += ['-I', indir]
Simon Glass075a45c2017-11-13 18:55:00 -0700354 return self._DoBinman(*args)
Simon Glass57454f42016-11-25 20:15:52 -0700355
356 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glass72232452016-11-25 20:15:53 -0700357 """Set up a new test device-tree file
358
359 The given file is compiled and set up as the device tree to be used
360 for ths test.
361
362 Args:
363 fname: Filename of .dts file to read
Simon Glass1e324002018-06-01 09:38:19 -0600364 outfile: Output filename for compiled device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700365
366 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600367 Contents of device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700368 """
Simon Glassb8d2daa2019-07-20 12:23:49 -0600369 tmpdir = tempfile.mkdtemp(prefix='binmant.')
370 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
Simon Glass33486662019-05-14 15:53:42 -0600371 with open(dtb, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700372 data = fd.read()
373 TestFunctional._MakeInputFile(outfile, data)
Simon Glassb8d2daa2019-07-20 12:23:49 -0600374 shutil.rmtree(tmpdir)
Simon Glass752e7552018-10-01 21:12:41 -0600375 return data
Simon Glass57454f42016-11-25 20:15:52 -0700376
Simon Glasse219aa42018-09-14 04:57:24 -0600377 def _GetDtbContentsForSplTpl(self, dtb_data, name):
378 """Create a version of the main DTB for SPL or SPL
379
380 For testing we don't actually have different versions of the DTB. With
381 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
382 we don't normally have any unwanted nodes.
383
384 We still want the DTBs for SPL and TPL to be different though, since
385 otherwise it is confusing to know which one we are looking at. So add
386 an 'spl' or 'tpl' property to the top-level node.
Simon Glass31ee50f2020-09-01 05:13:55 -0600387
388 Args:
389 dtb_data: dtb data to modify (this should be a value devicetree)
390 name: Name of a new property to add
391
392 Returns:
393 New dtb data with the property added
Simon Glasse219aa42018-09-14 04:57:24 -0600394 """
395 dtb = fdt.Fdt.FromData(dtb_data)
396 dtb.Scan()
397 dtb.GetNode('/binman').AddZeroProp(name)
398 dtb.Sync(auto_resize=True)
399 dtb.Pack()
400 return dtb.GetContents()
401
Simon Glassa87014e2018-07-06 10:27:42 -0600402 def _DoReadFileDtb(self, fname, use_real_dtb=False, map=False,
Simon Glassa435cd12020-09-01 05:13:59 -0600403 update_dtb=False, entry_args=None, reset_dtbs=True,
404 extra_indirs=None):
Simon Glass57454f42016-11-25 20:15:52 -0700405 """Run binman and return the resulting image
406
407 This runs binman with a given test file and then reads the resulting
408 output file. It is a shortcut function since most tests need to do
409 these steps.
410
411 Raises an assertion failure if binman returns a non-zero exit code.
412
413 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600414 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass57454f42016-11-25 20:15:52 -0700415 use_real_dtb: True to use the test file as the contents of
416 the u-boot-dtb entry. Normally this is not needed and the
417 test contents (the U_BOOT_DTB_DATA string) can be used.
418 But in some test we need the real contents.
Simon Glass30732662018-06-01 09:38:20 -0600419 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600420 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600421 tree before packing it into the image
Simon Glass31ee50f2020-09-01 05:13:55 -0600422 entry_args: Dict of entry args to supply to binman
423 key: arg name
424 value: value of that arg
425 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
426 function. If reset_dtbs is True, then the original test dtb
427 is written back before this function finishes
Simon Glassa435cd12020-09-01 05:13:59 -0600428 extra_indirs: Extra input directories to add using -I
Simon Glass72232452016-11-25 20:15:53 -0700429
430 Returns:
431 Tuple:
432 Resulting image contents
433 Device tree contents
Simon Glass30732662018-06-01 09:38:20 -0600434 Map data showing contents of image (or None if none)
Simon Glassdef77b52018-07-17 13:25:27 -0600435 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass57454f42016-11-25 20:15:52 -0700436 """
Simon Glass72232452016-11-25 20:15:53 -0700437 dtb_data = None
Simon Glass57454f42016-11-25 20:15:52 -0700438 # Use the compiled test file as the u-boot-dtb input
439 if use_real_dtb:
Simon Glass72232452016-11-25 20:15:53 -0700440 dtb_data = self._SetupDtb(fname)
Simon Glasse219aa42018-09-14 04:57:24 -0600441
442 # For testing purposes, make a copy of the DT for SPL and TPL. Add
443 # a node indicating which it is, so aid verification.
444 for name in ['spl', 'tpl']:
445 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
446 outfile = os.path.join(self._indir, dtb_fname)
447 TestFunctional._MakeInputFile(dtb_fname,
448 self._GetDtbContentsForSplTpl(dtb_data, name))
Simon Glass57454f42016-11-25 20:15:52 -0700449
450 try:
Simon Glass91710b32018-07-17 13:25:32 -0600451 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glassa435cd12020-09-01 05:13:59 -0600452 entry_args=entry_args, use_real_dtb=use_real_dtb,
453 extra_indirs=extra_indirs)
Simon Glass57454f42016-11-25 20:15:52 -0700454 self.assertEqual(0, retcode)
Simon Glasse219aa42018-09-14 04:57:24 -0600455 out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
Simon Glass57454f42016-11-25 20:15:52 -0700456
457 # Find the (only) image, read it and return its contents
458 image = control.images['image']
Simon Glassa87014e2018-07-06 10:27:42 -0600459 image_fname = tools.GetOutputFilename('image.bin')
460 self.assertTrue(os.path.exists(image_fname))
Simon Glass30732662018-06-01 09:38:20 -0600461 if map:
462 map_fname = tools.GetOutputFilename('image.map')
463 with open(map_fname) as fd:
464 map_data = fd.read()
465 else:
466 map_data = None
Simon Glass33486662019-05-14 15:53:42 -0600467 with open(image_fname, 'rb') as fd:
Simon Glassa87014e2018-07-06 10:27:42 -0600468 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass57454f42016-11-25 20:15:52 -0700469 finally:
470 # Put the test file back
Simon Glasse219aa42018-09-14 04:57:24 -0600471 if reset_dtbs and use_real_dtb:
Simon Glass8425a1f2018-07-17 13:25:48 -0600472 self._ResetDtbs()
Simon Glass57454f42016-11-25 20:15:52 -0700473
Simon Glass5b4bce32019-07-08 14:25:26 -0600474 def _DoReadFileRealDtb(self, fname):
475 """Run binman with a real .dtb file and return the resulting data
476
477 Args:
478 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
479
480 Returns:
481 Resulting image contents
482 """
483 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
484
Simon Glass72232452016-11-25 20:15:53 -0700485 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass1e324002018-06-01 09:38:19 -0600486 """Helper function which discards the device-tree binary
487
488 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600489 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600490 use_real_dtb: True to use the test file as the contents of
491 the u-boot-dtb entry. Normally this is not needed and the
492 test contents (the U_BOOT_DTB_DATA string) can be used.
493 But in some test we need the real contents.
Simon Glassdef77b52018-07-17 13:25:27 -0600494
495 Returns:
496 Resulting image contents
Simon Glass1e324002018-06-01 09:38:19 -0600497 """
Simon Glass72232452016-11-25 20:15:53 -0700498 return self._DoReadFileDtb(fname, use_real_dtb)[0]
499
Simon Glass57454f42016-11-25 20:15:52 -0700500 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600501 def _MakeInputFile(cls, fname, contents):
Simon Glass57454f42016-11-25 20:15:52 -0700502 """Create a new test input file, creating directories as needed
503
504 Args:
Simon Glasse8561af2018-08-01 15:22:37 -0600505 fname: Filename to create
Simon Glass57454f42016-11-25 20:15:52 -0700506 contents: File contents to write in to the file
507 Returns:
508 Full pathname of file created
509 """
Simon Glass862f8e22019-08-24 07:22:43 -0600510 pathname = os.path.join(cls._indir, fname)
Simon Glass57454f42016-11-25 20:15:52 -0700511 dirname = os.path.dirname(pathname)
512 if dirname and not os.path.exists(dirname):
513 os.makedirs(dirname)
514 with open(pathname, 'wb') as fd:
515 fd.write(contents)
516 return pathname
517
518 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600519 def _MakeInputDir(cls, dirname):
Simon Glassc1ae83c2018-07-17 13:25:44 -0600520 """Create a new test input directory, creating directories as needed
521
522 Args:
523 dirname: Directory name to create
524
525 Returns:
526 Full pathname of directory created
527 """
Simon Glass862f8e22019-08-24 07:22:43 -0600528 pathname = os.path.join(cls._indir, dirname)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600529 if not os.path.exists(pathname):
530 os.makedirs(pathname)
531 return pathname
532
533 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600534 def _SetupSplElf(cls, src_fname='bss_data'):
Simon Glass7057d022018-10-01 21:12:47 -0600535 """Set up an ELF file with a '_dt_ucode_base_size' symbol
536
537 Args:
538 Filename of ELF file to use as SPL
539 """
Simon Glass93a806f2019-08-24 07:22:59 -0600540 TestFunctional._MakeInputFile('spl/u-boot-spl',
541 tools.ReadFile(cls.ElfTestFile(src_fname)))
Simon Glass7057d022018-10-01 21:12:47 -0600542
543 @classmethod
Simon Glass3eb5b202019-08-24 07:23:00 -0600544 def _SetupTplElf(cls, src_fname='bss_data'):
545 """Set up an ELF file with a '_dt_ucode_base_size' symbol
546
547 Args:
548 Filename of ELF file to use as TPL
549 """
550 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
551 tools.ReadFile(cls.ElfTestFile(src_fname)))
552
553 @classmethod
Simon Glasse88cef92020-07-09 18:39:41 -0600554 def _SetupDescriptor(cls):
555 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
556 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
557
558 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600559 def TestFile(cls, fname):
560 return os.path.join(cls._binman_dir, 'test', fname)
Simon Glass57454f42016-11-25 20:15:52 -0700561
Simon Glassf6290892019-08-24 07:22:53 -0600562 @classmethod
563 def ElfTestFile(cls, fname):
564 return os.path.join(cls._elf_testdir, fname)
565
Simon Glass57454f42016-11-25 20:15:52 -0700566 def AssertInList(self, grep_list, target):
567 """Assert that at least one of a list of things is in a target
568
569 Args:
570 grep_list: List of strings to check
571 target: Target string
572 """
573 for grep in grep_list:
574 if grep in target:
575 return
Simon Glass848cdb52019-05-17 22:00:50 -0600576 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass57454f42016-11-25 20:15:52 -0700577
578 def CheckNoGaps(self, entries):
579 """Check that all entries fit together without gaps
580
581 Args:
582 entries: List of entries to check
583 """
Simon Glasse8561af2018-08-01 15:22:37 -0600584 offset = 0
Simon Glass57454f42016-11-25 20:15:52 -0700585 for entry in entries.values():
Simon Glasse8561af2018-08-01 15:22:37 -0600586 self.assertEqual(offset, entry.offset)
587 offset += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700588
Simon Glass72232452016-11-25 20:15:53 -0700589 def GetFdtLen(self, dtb):
Simon Glass1e324002018-06-01 09:38:19 -0600590 """Get the totalsize field from a device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700591
592 Args:
Simon Glass1e324002018-06-01 09:38:19 -0600593 dtb: Device-tree binary contents
Simon Glass72232452016-11-25 20:15:53 -0700594
595 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600596 Total size of device-tree binary, from the header
Simon Glass72232452016-11-25 20:15:53 -0700597 """
598 return struct.unpack('>L', dtb[4:8])[0]
599
Simon Glass0f621332019-07-08 14:25:27 -0600600 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glassa87014e2018-07-06 10:27:42 -0600601 def AddNode(node, path):
602 if node.name != '/':
603 path += '/' + node.name
Simon Glass0f621332019-07-08 14:25:27 -0600604 for prop in node.props.values():
605 if prop.name in prop_names:
606 prop_path = path + ':' + prop.name
607 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
608 prop.value)
Simon Glassa87014e2018-07-06 10:27:42 -0600609 for subnode in node.subnodes:
Simon Glassa87014e2018-07-06 10:27:42 -0600610 AddNode(subnode, path)
611
612 tree = {}
Simon Glassa87014e2018-07-06 10:27:42 -0600613 AddNode(dtb.GetRoot(), '')
614 return tree
615
Simon Glass57454f42016-11-25 20:15:52 -0700616 def testRun(self):
617 """Test a basic run with valid args"""
618 result = self._RunBinman('-h')
619
620 def testFullHelp(self):
621 """Test that the full help is displayed with -H"""
622 result = self._RunBinman('-H')
623 help_file = os.path.join(self._binman_dir, 'README')
Tom Rinic3c0b6d2018-01-16 15:29:50 -0500624 # Remove possible extraneous strings
625 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
626 gothelp = result.stdout.replace(extra, '')
627 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass57454f42016-11-25 20:15:52 -0700628 self.assertEqual(0, len(result.stderr))
629 self.assertEqual(0, result.return_code)
630
631 def testFullHelpInternal(self):
632 """Test that the full help is displayed with -H"""
633 try:
634 command.test_result = command.CommandResult()
635 result = self._DoBinman('-H')
636 help_file = os.path.join(self._binman_dir, 'README')
637 finally:
638 command.test_result = None
639
640 def testHelp(self):
641 """Test that the basic help is displayed with -h"""
642 result = self._RunBinman('-h')
643 self.assertTrue(len(result.stdout) > 200)
644 self.assertEqual(0, len(result.stderr))
645 self.assertEqual(0, result.return_code)
646
Simon Glass57454f42016-11-25 20:15:52 -0700647 def testBoard(self):
648 """Test that we can run it with a specific board"""
Simon Glass511f6582018-10-01 12:22:30 -0600649 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass57454f42016-11-25 20:15:52 -0700650 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glassf46732a2019-07-08 14:25:29 -0600651 result = self._DoBinman('build', '-b', 'sandbox')
Simon Glass57454f42016-11-25 20:15:52 -0700652 self.assertEqual(0, result)
653
654 def testNeedBoard(self):
655 """Test that we get an error when no board ius supplied"""
656 with self.assertRaises(ValueError) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600657 result = self._DoBinman('build')
Simon Glass57454f42016-11-25 20:15:52 -0700658 self.assertIn("Must provide a board to process (use -b <board>)",
659 str(e.exception))
660
661 def testMissingDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600662 """Test that an invalid device-tree file generates an error"""
Simon Glass57454f42016-11-25 20:15:52 -0700663 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600664 self._RunBinman('build', '-d', 'missing_file')
Simon Glass57454f42016-11-25 20:15:52 -0700665 # We get one error from libfdt, and a different one from fdtget.
666 self.AssertInList(["Couldn't open blob from 'missing_file'",
667 'No such file or directory'], str(e.exception))
668
669 def testBrokenDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600670 """Test that an invalid device-tree source file generates an error
Simon Glass57454f42016-11-25 20:15:52 -0700671
672 Since this is a source file it should be compiled and the error
673 will come from the device-tree compiler (dtc).
674 """
675 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600676 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700677 self.assertIn("FATAL ERROR: Unable to parse input tree",
678 str(e.exception))
679
680 def testMissingNode(self):
681 """Test that a device tree without a 'binman' node generates an error"""
682 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600683 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700684 self.assertIn("does not have a 'binman' node", str(e.exception))
685
686 def testEmpty(self):
687 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glassf46732a2019-07-08 14:25:29 -0600688 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700689 self.assertEqual(0, len(result.stderr))
690 self.assertEqual(0, result.return_code)
691
692 def testInvalidEntry(self):
693 """Test that an invalid entry is flagged"""
694 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600695 result = self._RunBinman('build', '-d',
Simon Glass511f6582018-10-01 12:22:30 -0600696 self.TestFile('004_invalid_entry.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700697 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
698 "'/binman/not-a-valid-type'", str(e.exception))
699
700 def testSimple(self):
701 """Test a simple binman with a single file"""
Simon Glass511f6582018-10-01 12:22:30 -0600702 data = self._DoReadFile('005_simple.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700703 self.assertEqual(U_BOOT_DATA, data)
704
Simon Glass075a45c2017-11-13 18:55:00 -0700705 def testSimpleDebug(self):
706 """Test a simple binman run with debugging enabled"""
Simon Glass52d06212019-07-08 14:25:53 -0600707 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass075a45c2017-11-13 18:55:00 -0700708
Simon Glass57454f42016-11-25 20:15:52 -0700709 def testDual(self):
710 """Test that we can handle creating two images
711
712 This also tests image padding.
713 """
Simon Glass511f6582018-10-01 12:22:30 -0600714 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700715 self.assertEqual(0, retcode)
716
717 image = control.images['image1']
Simon Glass39dd2152019-07-08 14:25:47 -0600718 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700719 fname = tools.GetOutputFilename('image1.bin')
720 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600721 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700722 data = fd.read()
723 self.assertEqual(U_BOOT_DATA, data)
724
725 image = control.images['image2']
Simon Glass39dd2152019-07-08 14:25:47 -0600726 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700727 fname = tools.GetOutputFilename('image2.bin')
728 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600729 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700730 data = fd.read()
731 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glassac0d4952019-05-14 15:53:47 -0600732 self.assertEqual(tools.GetBytes(0, 3), data[:3])
733 self.assertEqual(tools.GetBytes(0, 5), data[7:])
Simon Glass57454f42016-11-25 20:15:52 -0700734
735 def testBadAlign(self):
736 """Test that an invalid alignment value is detected"""
737 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600738 self._DoTestFile('007_bad_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700739 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
740 "of two", str(e.exception))
741
742 def testPackSimple(self):
743 """Test that packing works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -0600744 retcode = self._DoTestFile('008_pack.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700745 self.assertEqual(0, retcode)
746 self.assertIn('image', control.images)
747 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600748 entries = image.GetEntries()
Simon Glass57454f42016-11-25 20:15:52 -0700749 self.assertEqual(5, len(entries))
750
751 # First u-boot
752 self.assertIn('u-boot', entries)
753 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600754 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700755 self.assertEqual(len(U_BOOT_DATA), entry.size)
756
757 # Second u-boot, aligned to 16-byte boundary
758 self.assertIn('u-boot-align', entries)
759 entry = entries['u-boot-align']
Simon Glasse8561af2018-08-01 15:22:37 -0600760 self.assertEqual(16, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700761 self.assertEqual(len(U_BOOT_DATA), entry.size)
762
763 # Third u-boot, size 23 bytes
764 self.assertIn('u-boot-size', entries)
765 entry = entries['u-boot-size']
Simon Glasse8561af2018-08-01 15:22:37 -0600766 self.assertEqual(20, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700767 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
768 self.assertEqual(23, entry.size)
769
770 # Fourth u-boot, placed immediate after the above
771 self.assertIn('u-boot-next', entries)
772 entry = entries['u-boot-next']
Simon Glasse8561af2018-08-01 15:22:37 -0600773 self.assertEqual(43, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700774 self.assertEqual(len(U_BOOT_DATA), entry.size)
775
Simon Glasse8561af2018-08-01 15:22:37 -0600776 # Fifth u-boot, placed at a fixed offset
Simon Glass57454f42016-11-25 20:15:52 -0700777 self.assertIn('u-boot-fixed', entries)
778 entry = entries['u-boot-fixed']
Simon Glasse8561af2018-08-01 15:22:37 -0600779 self.assertEqual(61, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700780 self.assertEqual(len(U_BOOT_DATA), entry.size)
781
Simon Glass39dd2152019-07-08 14:25:47 -0600782 self.assertEqual(65, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700783
784 def testPackExtra(self):
785 """Test that extra packing feature works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -0600786 retcode = self._DoTestFile('009_pack_extra.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700787
788 self.assertEqual(0, retcode)
789 self.assertIn('image', control.images)
790 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600791 entries = image.GetEntries()
Simon Glass57454f42016-11-25 20:15:52 -0700792 self.assertEqual(5, len(entries))
793
794 # First u-boot with padding before and after
795 self.assertIn('u-boot', entries)
796 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600797 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700798 self.assertEqual(3, entry.pad_before)
799 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
800
801 # Second u-boot has an aligned size, but it has no effect
802 self.assertIn('u-boot-align-size-nop', entries)
803 entry = entries['u-boot-align-size-nop']
Simon Glasse8561af2018-08-01 15:22:37 -0600804 self.assertEqual(12, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700805 self.assertEqual(4, entry.size)
806
807 # Third u-boot has an aligned size too
808 self.assertIn('u-boot-align-size', entries)
809 entry = entries['u-boot-align-size']
Simon Glasse8561af2018-08-01 15:22:37 -0600810 self.assertEqual(16, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700811 self.assertEqual(32, entry.size)
812
813 # Fourth u-boot has an aligned end
814 self.assertIn('u-boot-align-end', entries)
815 entry = entries['u-boot-align-end']
Simon Glasse8561af2018-08-01 15:22:37 -0600816 self.assertEqual(48, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700817 self.assertEqual(16, entry.size)
818
819 # Fifth u-boot immediately afterwards
820 self.assertIn('u-boot-align-both', entries)
821 entry = entries['u-boot-align-both']
Simon Glasse8561af2018-08-01 15:22:37 -0600822 self.assertEqual(64, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700823 self.assertEqual(64, entry.size)
824
825 self.CheckNoGaps(entries)
Simon Glass39dd2152019-07-08 14:25:47 -0600826 self.assertEqual(128, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700827
828 def testPackAlignPowerOf2(self):
829 """Test that invalid entry alignment is detected"""
830 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600831 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700832 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
833 "of two", str(e.exception))
834
835 def testPackAlignSizePowerOf2(self):
836 """Test that invalid entry size alignment is detected"""
837 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600838 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700839 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
840 "power of two", str(e.exception))
841
842 def testPackInvalidAlign(self):
Simon Glasse8561af2018-08-01 15:22:37 -0600843 """Test detection of an offset that does not match its alignment"""
Simon Glass57454f42016-11-25 20:15:52 -0700844 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600845 self._DoTestFile('012_pack_inv_align.dts')
Simon Glasse8561af2018-08-01 15:22:37 -0600846 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass57454f42016-11-25 20:15:52 -0700847 "align 0x4 (4)", str(e.exception))
848
849 def testPackInvalidSizeAlign(self):
850 """Test that invalid entry size alignment is detected"""
851 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600852 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700853 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
854 "align-size 0x4 (4)", str(e.exception))
855
856 def testPackOverlap(self):
857 """Test that overlapping regions are detected"""
858 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600859 self._DoTestFile('014_pack_overlap.dts')
Simon Glasse8561af2018-08-01 15:22:37 -0600860 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -0700861 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
862 str(e.exception))
863
864 def testPackEntryOverflow(self):
865 """Test that entries that overflow their size are detected"""
866 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600867 self._DoTestFile('015_pack_overflow.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700868 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
869 "but entry size is 0x3 (3)", str(e.exception))
870
871 def testPackImageOverflow(self):
872 """Test that entries which overflow the image size are detected"""
873 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600874 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glasseca32212018-06-01 09:38:12 -0600875 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass57454f42016-11-25 20:15:52 -0700876 "size 0x3 (3)", str(e.exception))
877
878 def testPackImageSize(self):
879 """Test that the image size can be set"""
Simon Glass511f6582018-10-01 12:22:30 -0600880 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700881 self.assertEqual(0, retcode)
882 self.assertIn('image', control.images)
883 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -0600884 self.assertEqual(7, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700885
886 def testPackImageSizeAlign(self):
887 """Test that image size alignemnt works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -0600888 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700889 self.assertEqual(0, retcode)
890 self.assertIn('image', control.images)
891 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -0600892 self.assertEqual(16, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700893
894 def testPackInvalidImageAlign(self):
895 """Test that invalid image alignment is detected"""
896 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600897 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glasseca32212018-06-01 09:38:12 -0600898 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass57454f42016-11-25 20:15:52 -0700899 "align-size 0x8 (8)", str(e.exception))
900
901 def testPackAlignPowerOf2(self):
902 """Test that invalid image alignment is detected"""
903 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600904 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass39dd2152019-07-08 14:25:47 -0600905 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass57454f42016-11-25 20:15:52 -0700906 "two", str(e.exception))
907
908 def testImagePadByte(self):
909 """Test that the image pad byte can be specified"""
Simon Glass7057d022018-10-01 21:12:47 -0600910 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -0600911 data = self._DoReadFile('021_image_pad.dts')
Simon Glassac0d4952019-05-14 15:53:47 -0600912 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0xff, 1) +
913 U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -0700914
915 def testImageName(self):
916 """Test that image files can be named"""
Simon Glass511f6582018-10-01 12:22:30 -0600917 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700918 self.assertEqual(0, retcode)
919 image = control.images['image1']
920 fname = tools.GetOutputFilename('test-name')
921 self.assertTrue(os.path.exists(fname))
922
923 image = control.images['image2']
924 fname = tools.GetOutputFilename('test-name.xx')
925 self.assertTrue(os.path.exists(fname))
926
927 def testBlobFilename(self):
928 """Test that generic blobs can be provided by filename"""
Simon Glass511f6582018-10-01 12:22:30 -0600929 data = self._DoReadFile('023_blob.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700930 self.assertEqual(BLOB_DATA, data)
931
932 def testPackSorted(self):
933 """Test that entries can be sorted"""
Simon Glass7057d022018-10-01 21:12:47 -0600934 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -0600935 data = self._DoReadFile('024_sorted.dts')
Simon Glassac0d4952019-05-14 15:53:47 -0600936 self.assertEqual(tools.GetBytes(0, 1) + U_BOOT_SPL_DATA +
937 tools.GetBytes(0, 2) + U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -0700938
Simon Glasse8561af2018-08-01 15:22:37 -0600939 def testPackZeroOffset(self):
940 """Test that an entry at offset 0 is not given a new offset"""
Simon Glass57454f42016-11-25 20:15:52 -0700941 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600942 self._DoTestFile('025_pack_zero_size.dts')
Simon Glasse8561af2018-08-01 15:22:37 -0600943 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -0700944 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
945 str(e.exception))
946
947 def testPackUbootDtb(self):
948 """Test that a device tree can be added to U-Boot"""
Simon Glass511f6582018-10-01 12:22:30 -0600949 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700950 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glass72232452016-11-25 20:15:53 -0700951
952 def testPackX86RomNoSize(self):
953 """Test that the end-at-4gb property requires a size property"""
954 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600955 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass39dd2152019-07-08 14:25:47 -0600956 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glass72232452016-11-25 20:15:53 -0700957 "using end-at-4gb", str(e.exception))
958
Jagdish Gediya0fb978c2018-09-03 21:35:07 +0530959 def test4gbAndSkipAtStartTogether(self):
960 """Test that the end-at-4gb and skip-at-size property can't be used
961 together"""
962 with self.assertRaises(ValueError) as e:
Simon Glass11f2bd02019-08-24 07:23:02 -0600963 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
Simon Glass39dd2152019-07-08 14:25:47 -0600964 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya0fb978c2018-09-03 21:35:07 +0530965 "'skip-at-start'", str(e.exception))
966
Simon Glass72232452016-11-25 20:15:53 -0700967 def testPackX86RomOutside(self):
Simon Glasse8561af2018-08-01 15:22:37 -0600968 """Test that the end-at-4gb property checks for offset boundaries"""
Simon Glass72232452016-11-25 20:15:53 -0700969 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600970 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glasse8561af2018-08-01 15:22:37 -0600971 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) is outside "
Simon Glasseca32212018-06-01 09:38:12 -0600972 "the section starting at 0xffffffe0 (4294967264)",
Simon Glass72232452016-11-25 20:15:53 -0700973 str(e.exception))
974
975 def testPackX86Rom(self):
976 """Test that a basic x86 ROM can be created"""
Simon Glass7057d022018-10-01 21:12:47 -0600977 self._SetupSplElf()
Simon Glass1d167762019-08-24 07:23:01 -0600978 data = self._DoReadFile('029_x86_rom.dts')
Simon Glass4e353e22019-08-24 07:23:04 -0600979 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 3) + U_BOOT_SPL_DATA +
Simon Glassac0d4952019-05-14 15:53:47 -0600980 tools.GetBytes(0, 2), data)
Simon Glass72232452016-11-25 20:15:53 -0700981
982 def testPackX86RomMeNoDesc(self):
983 """Test that an invalid Intel descriptor entry is detected"""
Simon Glasse88cef92020-07-09 18:39:41 -0600984 try:
Simon Glass14c596c2020-07-25 15:11:19 -0600985 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
Simon Glasse88cef92020-07-09 18:39:41 -0600986 with self.assertRaises(ValueError) as e:
Simon Glass14c596c2020-07-25 15:11:19 -0600987 self._DoTestFile('163_x86_rom_me_empty.dts')
Simon Glasse88cef92020-07-09 18:39:41 -0600988 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
989 str(e.exception))
990 finally:
991 self._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -0700992
993 def testPackX86RomBadDesc(self):
994 """Test that the Intel requires a descriptor entry"""
995 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -0600996 self._DoTestFile('030_x86_rom_me_no_desc.dts')
Simon Glasse8561af2018-08-01 15:22:37 -0600997 self.assertIn("Node '/binman/intel-me': No offset set with "
998 "offset-unset: should another entry provide this correct "
999 "offset?", str(e.exception))
Simon Glass72232452016-11-25 20:15:53 -07001000
1001 def testPackX86RomMe(self):
1002 """Test that an x86 ROM with an ME region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001003 data = self._DoReadFile('031_x86_rom_me.dts')
Simon Glass759af872019-07-08 13:18:54 -06001004 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
1005 if data[:0x1000] != expected_desc:
1006 self.fail('Expected descriptor binary at start of image')
Simon Glass72232452016-11-25 20:15:53 -07001007 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1008
1009 def testPackVga(self):
1010 """Test that an image with a VGA binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001011 data = self._DoReadFile('032_intel_vga.dts')
Simon Glass72232452016-11-25 20:15:53 -07001012 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1013
1014 def testPackStart16(self):
1015 """Test that an image with an x86 start16 region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001016 data = self._DoReadFile('033_x86_start16.dts')
Simon Glass72232452016-11-25 20:15:53 -07001017 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1018
Jagdish Gediya311d4842018-09-03 21:35:08 +05301019 def testPackPowerpcMpc85xxBootpgResetvec(self):
1020 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1021 created"""
Simon Glass11f2bd02019-08-24 07:23:02 -06001022 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
Jagdish Gediya311d4842018-09-03 21:35:08 +05301023 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1024
Simon Glass6ba679c2018-07-06 10:27:17 -06001025 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glass820af1d2018-07-06 10:27:16 -06001026 """Handle running a test for insertion of microcode
1027
1028 Args:
1029 dts_fname: Name of test .dts file
1030 nodtb_data: Data that we expect in the first section
Simon Glass6ba679c2018-07-06 10:27:17 -06001031 ucode_second: True if the microsecond entry is second instead of
1032 third
Simon Glass820af1d2018-07-06 10:27:16 -06001033
1034 Returns:
1035 Tuple:
1036 Contents of first region (U-Boot or SPL)
Simon Glasse8561af2018-08-01 15:22:37 -06001037 Offset and size components of microcode pointer, as inserted
Simon Glass820af1d2018-07-06 10:27:16 -06001038 in the above (two 4-byte words)
1039 """
Simon Glass3d274232017-11-12 21:52:27 -07001040 data = self._DoReadFile(dts_fname, True)
Simon Glass72232452016-11-25 20:15:53 -07001041
1042 # Now check the device tree has no microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001043 if ucode_second:
1044 ucode_content = data[len(nodtb_data):]
1045 ucode_pos = len(nodtb_data)
1046 dtb_with_ucode = ucode_content[16:]
1047 fdt_len = self.GetFdtLen(dtb_with_ucode)
1048 else:
1049 dtb_with_ucode = data[len(nodtb_data):]
1050 fdt_len = self.GetFdtLen(dtb_with_ucode)
1051 ucode_content = dtb_with_ucode[fdt_len:]
1052 ucode_pos = len(nodtb_data) + fdt_len
Simon Glass72232452016-11-25 20:15:53 -07001053 fname = tools.GetOutputFilename('test.dtb')
1054 with open(fname, 'wb') as fd:
Simon Glass820af1d2018-07-06 10:27:16 -06001055 fd.write(dtb_with_ucode)
Simon Glass22c92ca2017-05-27 07:38:29 -06001056 dtb = fdt.FdtScan(fname)
1057 ucode = dtb.GetNode('/microcode')
Simon Glass72232452016-11-25 20:15:53 -07001058 self.assertTrue(ucode)
1059 for node in ucode.subnodes:
1060 self.assertFalse(node.props.get('data'))
1061
Simon Glass72232452016-11-25 20:15:53 -07001062 # Check that the microcode appears immediately after the Fdt
1063 # This matches the concatenation of the data properties in
Simon Glasse83679d2017-11-12 21:52:26 -07001064 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glass72232452016-11-25 20:15:53 -07001065 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1066 0x78235609)
Simon Glass820af1d2018-07-06 10:27:16 -06001067 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glass72232452016-11-25 20:15:53 -07001068
1069 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001070 # expected offset and size
Simon Glass72232452016-11-25 20:15:53 -07001071 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1072 len(ucode_data))
Simon Glass6ba679c2018-07-06 10:27:17 -06001073 u_boot = data[:len(nodtb_data)]
1074 return u_boot, pos_and_size
Simon Glass3d274232017-11-12 21:52:27 -07001075
1076 def testPackUbootMicrocode(self):
1077 """Test that x86 microcode can be handled correctly
1078
1079 We expect to see the following in the image, in order:
1080 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1081 place
1082 u-boot.dtb with the microcode removed
1083 the microcode
1084 """
Simon Glass511f6582018-10-01 12:22:30 -06001085 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass3d274232017-11-12 21:52:27 -07001086 U_BOOT_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06001087 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1088 b' somewhere in here', first)
Simon Glass72232452016-11-25 20:15:53 -07001089
Simon Glassbac25c82017-05-27 07:38:26 -06001090 def _RunPackUbootSingleMicrocode(self):
Simon Glass72232452016-11-25 20:15:53 -07001091 """Test that x86 microcode can be handled correctly
1092
1093 We expect to see the following in the image, in order:
1094 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1095 place
1096 u-boot.dtb with the microcode
1097 an empty microcode region
1098 """
1099 # We need the libfdt library to run this test since only that allows
1100 # finding the offset of a property. This is required by
1101 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass511f6582018-10-01 12:22:30 -06001102 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glass72232452016-11-25 20:15:53 -07001103
1104 second = data[len(U_BOOT_NODTB_DATA):]
1105
1106 fdt_len = self.GetFdtLen(second)
1107 third = second[fdt_len:]
1108 second = second[:fdt_len]
1109
Simon Glassbac25c82017-05-27 07:38:26 -06001110 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1111 self.assertIn(ucode_data, second)
1112 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glass72232452016-11-25 20:15:53 -07001113
Simon Glassbac25c82017-05-27 07:38:26 -06001114 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001115 # expected offset and size
Simon Glassbac25c82017-05-27 07:38:26 -06001116 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1117 len(ucode_data))
1118 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glass303f62f2019-05-17 22:00:46 -06001119 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1120 b' somewhere in here', first)
Simon Glass996021e2016-11-25 20:15:54 -07001121
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001122 def testPackUbootSingleMicrocode(self):
1123 """Test that x86 microcode can be handled correctly with fdt_normal.
1124 """
Simon Glassbac25c82017-05-27 07:38:26 -06001125 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001126
Simon Glass996021e2016-11-25 20:15:54 -07001127 def testUBootImg(self):
1128 """Test that u-boot.img can be put in a file"""
Simon Glass511f6582018-10-01 12:22:30 -06001129 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glass996021e2016-11-25 20:15:54 -07001130 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001131
1132 def testNoMicrocode(self):
1133 """Test that a missing microcode region is detected"""
1134 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001135 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001136 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1137 "node found in ", str(e.exception))
1138
1139 def testMicrocodeWithoutNode(self):
1140 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1141 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001142 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001143 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1144 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1145
1146 def testMicrocodeWithoutNode2(self):
1147 """Test that a missing u-boot-ucode node is detected"""
1148 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001149 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001150 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1151 "microcode region u-boot-ucode", str(e.exception))
1152
1153 def testMicrocodeWithoutPtrInElf(self):
1154 """Test that a U-Boot binary without the microcode symbol is detected"""
1155 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001156 try:
Simon Glassfaaaa162019-08-24 07:22:55 -06001157 TestFunctional._MakeInputFile('u-boot',
1158 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001159
1160 with self.assertRaises(ValueError) as e:
Simon Glassbac25c82017-05-27 07:38:26 -06001161 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001162 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1163 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1164
1165 finally:
1166 # Put the original file back
Simon Glass4affd4b2019-08-24 07:22:54 -06001167 TestFunctional._MakeInputFile('u-boot',
1168 tools.ReadFile(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001169
1170 def testMicrocodeNotInImage(self):
1171 """Test that microcode must be placed within the image"""
1172 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001173 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001174 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1175 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glassad5a7712018-06-01 09:38:14 -06001176 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001177
1178 def testWithoutMicrocode(self):
1179 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glassfaaaa162019-08-24 07:22:55 -06001180 TestFunctional._MakeInputFile('u-boot',
1181 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass511f6582018-10-01 12:22:30 -06001182 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001183
1184 # Now check the device tree has no microcode
1185 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1186 second = data[len(U_BOOT_NODTB_DATA):]
1187
1188 fdt_len = self.GetFdtLen(second)
1189 self.assertEqual(dtb, second[:fdt_len])
1190
1191 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1192 third = data[used_len:]
Simon Glassac0d4952019-05-14 15:53:47 -06001193 self.assertEqual(tools.GetBytes(0, 0x200 - used_len), third)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001194
1195 def testUnknownPosSize(self):
1196 """Test that microcode must be placed within the image"""
1197 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001198 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glasse8561af2018-08-01 15:22:37 -06001199 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001200 "entry 'invalid-entry'", str(e.exception))
Simon Glassb4176d42016-11-25 20:15:56 -07001201
1202 def testPackFsp(self):
1203 """Test that an image with a FSP binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001204 data = self._DoReadFile('042_intel_fsp.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001205 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1206
1207 def testPackCmc(self):
Bin Mengd7bcdf52017-08-15 22:41:54 -07001208 """Test that an image with a CMC binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001209 data = self._DoReadFile('043_intel_cmc.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001210 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Mengd7bcdf52017-08-15 22:41:54 -07001211
1212 def testPackVbt(self):
1213 """Test that an image with a VBT binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001214 data = self._DoReadFile('046_intel_vbt.dts')
Bin Mengd7bcdf52017-08-15 22:41:54 -07001215 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glassac599912017-11-12 21:52:22 -07001216
Simon Glass7f94e832017-11-12 21:52:25 -07001217 def testSplBssPad(self):
1218 """Test that we can pad SPL's BSS with zeros"""
Simon Glass3d274232017-11-12 21:52:27 -07001219 # ELF file with a '__bss_size' symbol
Simon Glass7057d022018-10-01 21:12:47 -06001220 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001221 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassac0d4952019-05-14 15:53:47 -06001222 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
1223 data)
Simon Glass7f94e832017-11-12 21:52:25 -07001224
Simon Glass04cda032018-10-01 21:12:42 -06001225 def testSplBssPadMissing(self):
1226 """Test that a missing symbol is detected"""
Simon Glass7057d022018-10-01 21:12:47 -06001227 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass24ad3652017-11-13 18:54:54 -07001228 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001229 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass24ad3652017-11-13 18:54:54 -07001230 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1231 str(e.exception))
1232
Simon Glasse83679d2017-11-12 21:52:26 -07001233 def testPackStart16Spl(self):
Simon Glassed40e962018-09-14 04:57:10 -06001234 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001235 data = self._DoReadFile('048_x86_start16_spl.dts')
Simon Glasse83679d2017-11-12 21:52:26 -07001236 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1237
Simon Glass6ba679c2018-07-06 10:27:17 -06001238 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1239 """Helper function for microcode tests
Simon Glass3d274232017-11-12 21:52:27 -07001240
1241 We expect to see the following in the image, in order:
1242 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1243 correct place
1244 u-boot.dtb with the microcode removed
1245 the microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001246
1247 Args:
1248 dts: Device tree file to use for test
1249 ucode_second: True if the microsecond entry is second instead of
1250 third
Simon Glass3d274232017-11-12 21:52:27 -07001251 """
Simon Glass7057d022018-10-01 21:12:47 -06001252 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass6ba679c2018-07-06 10:27:17 -06001253 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1254 ucode_second=ucode_second)
Simon Glass303f62f2019-05-17 22:00:46 -06001255 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1256 b'ter somewhere in here', first)
Simon Glass3d274232017-11-12 21:52:27 -07001257
Simon Glass6ba679c2018-07-06 10:27:17 -06001258 def testPackUbootSplMicrocode(self):
1259 """Test that x86 microcode can be handled correctly in SPL"""
Simon Glass511f6582018-10-01 12:22:30 -06001260 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass6ba679c2018-07-06 10:27:17 -06001261
1262 def testPackUbootSplMicrocodeReorder(self):
1263 """Test that order doesn't matter for microcode entries
1264
1265 This is the same as testPackUbootSplMicrocode but when we process the
1266 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1267 entry, so we reply on binman to try later.
1268 """
Simon Glass511f6582018-10-01 12:22:30 -06001269 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass6ba679c2018-07-06 10:27:17 -06001270 ucode_second=True)
1271
Simon Glassa409c932017-11-12 21:52:28 -07001272 def testPackMrc(self):
1273 """Test that an image with an MRC binary can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001274 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassa409c932017-11-12 21:52:28 -07001275 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1276
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001277 def testSplDtb(self):
1278 """Test that an image with spl/u-boot-spl.dtb can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001279 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001280 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1281
Simon Glass0a6da312017-11-13 18:54:56 -07001282 def testSplNoDtb(self):
1283 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001284 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass0a6da312017-11-13 18:54:56 -07001285 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1286
Simon Glass4ca8e042017-11-13 18:55:01 -07001287 def testSymbols(self):
1288 """Test binman can assign symbols embedded in U-Boot"""
Simon Glass5d0c0262019-08-24 07:22:56 -06001289 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass4ca8e042017-11-13 18:55:01 -07001290 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1291 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Simon Glasse8561af2018-08-01 15:22:37 -06001292 self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr)
Simon Glass4ca8e042017-11-13 18:55:01 -07001293
Simon Glass7057d022018-10-01 21:12:47 -06001294 self._SetupSplElf('u_boot_binman_syms')
Simon Glass511f6582018-10-01 12:22:30 -06001295 data = self._DoReadFile('053_symbols.dts')
Simon Glass72555fa2019-11-06 17:22:44 -07001296 sym_values = struct.pack('<LQLL', 0x00, 0x1c, 0x28, 0x04)
Simon Glass3f8ff012019-08-24 07:23:05 -06001297 expected = (sym_values + U_BOOT_SPL_DATA[20:] +
Simon Glassac0d4952019-05-14 15:53:47 -06001298 tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
Simon Glass3f8ff012019-08-24 07:23:05 -06001299 U_BOOT_SPL_DATA[20:])
Simon Glass4ca8e042017-11-13 18:55:01 -07001300 self.assertEqual(expected, data)
1301
Simon Glasse76a3e62018-06-01 09:38:11 -06001302 def testPackUnitAddress(self):
1303 """Test that we support multiple binaries with the same name"""
Simon Glass511f6582018-10-01 12:22:30 -06001304 data = self._DoReadFile('054_unit_address.dts')
Simon Glasse76a3e62018-06-01 09:38:11 -06001305 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1306
Simon Glassa91e1152018-06-01 09:38:16 -06001307 def testSections(self):
1308 """Basic test of sections"""
Simon Glass511f6582018-10-01 12:22:30 -06001309 data = self._DoReadFile('055_sections.dts')
Simon Glass303f62f2019-05-17 22:00:46 -06001310 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1311 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
1312 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
Simon Glassa91e1152018-06-01 09:38:16 -06001313 self.assertEqual(expected, data)
Simon Glassac599912017-11-12 21:52:22 -07001314
Simon Glass30732662018-06-01 09:38:20 -06001315 def testMap(self):
1316 """Tests outputting a map of the images"""
Simon Glass511f6582018-10-01 12:22:30 -06001317 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001318 self.assertEqual('''ImagePos Offset Size Name
131900000000 00000000 00000028 main-section
132000000000 00000000 00000010 section@0
132100000000 00000000 00000004 u-boot
132200000010 00000010 00000010 section@1
132300000010 00000000 00000004 u-boot
132400000020 00000020 00000004 section@2
132500000020 00000000 00000004 u-boot
Simon Glass30732662018-06-01 09:38:20 -06001326''', map_data)
1327
Simon Glass3b78d532018-06-01 09:38:21 -06001328 def testNamePrefix(self):
1329 """Tests that name prefixes are used"""
Simon Glass511f6582018-10-01 12:22:30 -06001330 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001331 self.assertEqual('''ImagePos Offset Size Name
133200000000 00000000 00000028 main-section
133300000000 00000000 00000010 section@0
133400000000 00000000 00000004 ro-u-boot
133500000010 00000010 00000010 section@1
133600000010 00000000 00000004 rw-u-boot
Simon Glass3b78d532018-06-01 09:38:21 -06001337''', map_data)
1338
Simon Glass6ba679c2018-07-06 10:27:17 -06001339 def testUnknownContents(self):
1340 """Test that obtaining the contents works as expected"""
1341 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001342 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass39dd2152019-07-08 14:25:47 -06001343 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glassc585dd42020-04-17 18:09:03 -06001344 "processing of contents: remaining ["
1345 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass6ba679c2018-07-06 10:27:17 -06001346
Simon Glass2e1169f2018-07-06 10:27:19 -06001347 def testBadChangeSize(self):
1348 """Test that trying to change the size of an entry fails"""
Simon Glasse61b6f62019-07-08 14:25:37 -06001349 try:
1350 state.SetAllowEntryExpansion(False)
1351 with self.assertRaises(ValueError) as e:
1352 self._DoReadFile('059_change_size.dts', True)
Simon Glass8c702fb2019-07-20 12:23:57 -06001353 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glasse61b6f62019-07-08 14:25:37 -06001354 str(e.exception))
1355 finally:
1356 state.SetAllowEntryExpansion(True)
Simon Glass2e1169f2018-07-06 10:27:19 -06001357
Simon Glassa87014e2018-07-06 10:27:42 -06001358 def testUpdateFdt(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001359 """Test that we can update the device tree with offset/size info"""
Simon Glass511f6582018-10-01 12:22:30 -06001360 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glassa87014e2018-07-06 10:27:42 -06001361 update_dtb=True)
Simon Glass5463a6a2018-07-17 13:25:52 -06001362 dtb = fdt.Fdt(out_dtb_fname)
1363 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06001364 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glassa87014e2018-07-06 10:27:42 -06001365 self.assertEqual({
Simon Glass9dcc8612018-08-01 15:22:42 -06001366 'image-pos': 0,
Simon Glass3a9a2b82018-07-17 13:25:28 -06001367 'offset': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001368 '_testing:offset': 32,
Simon Glass8c702fb2019-07-20 12:23:57 -06001369 '_testing:size': 2,
Simon Glass9dcc8612018-08-01 15:22:42 -06001370 '_testing:image-pos': 32,
Simon Glasse8561af2018-08-01 15:22:37 -06001371 'section@0/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001372 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001373 'section@0/u-boot:image-pos': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001374 'section@0:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001375 'section@0:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001376 'section@0:image-pos': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001377
Simon Glasse8561af2018-08-01 15:22:37 -06001378 'section@1/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001379 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001380 'section@1/u-boot:image-pos': 16,
Simon Glasse8561af2018-08-01 15:22:37 -06001381 'section@1:offset': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001382 'section@1:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001383 'section@1:image-pos': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001384 'size': 40
1385 }, props)
1386
1387 def testUpdateFdtBad(self):
1388 """Test that we detect when ProcessFdt never completes"""
1389 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001390 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glassa87014e2018-07-06 10:27:42 -06001391 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glassc585dd42020-04-17 18:09:03 -06001392 '[<binman.etype._testing.Entry__testing',
1393 str(e.exception))
Simon Glass2e1169f2018-07-06 10:27:19 -06001394
Simon Glass91710b32018-07-17 13:25:32 -06001395 def testEntryArgs(self):
1396 """Test passing arguments to entries from the command line"""
1397 entry_args = {
1398 'test-str-arg': 'test1',
1399 'test-int-arg': '456',
1400 }
Simon Glass511f6582018-10-01 12:22:30 -06001401 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001402 self.assertIn('image', control.images)
1403 entry = control.images['image'].GetEntries()['_testing']
1404 self.assertEqual('test0', entry.test_str_fdt)
1405 self.assertEqual('test1', entry.test_str_arg)
1406 self.assertEqual(123, entry.test_int_fdt)
1407 self.assertEqual(456, entry.test_int_arg)
1408
1409 def testEntryArgsMissing(self):
1410 """Test missing arguments and properties"""
1411 entry_args = {
1412 'test-int-arg': '456',
1413 }
Simon Glass511f6582018-10-01 12:22:30 -06001414 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001415 entry = control.images['image'].GetEntries()['_testing']
1416 self.assertEqual('test0', entry.test_str_fdt)
1417 self.assertEqual(None, entry.test_str_arg)
1418 self.assertEqual(None, entry.test_int_fdt)
1419 self.assertEqual(456, entry.test_int_arg)
1420
1421 def testEntryArgsRequired(self):
1422 """Test missing arguments and properties"""
1423 entry_args = {
1424 'test-int-arg': '456',
1425 }
1426 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001427 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass21db0ff2020-09-01 05:13:54 -06001428 self.assertIn("Node '/binman/_testing': "
1429 'Missing required properties/entry args: test-str-arg, '
1430 'test-int-fdt, test-int-arg',
Simon Glass91710b32018-07-17 13:25:32 -06001431 str(e.exception))
1432
1433 def testEntryArgsInvalidFormat(self):
1434 """Test that an invalid entry-argument format is detected"""
Simon Glassf46732a2019-07-08 14:25:29 -06001435 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1436 '-ano-value']
Simon Glass91710b32018-07-17 13:25:32 -06001437 with self.assertRaises(ValueError) as e:
1438 self._DoBinman(*args)
1439 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1440
1441 def testEntryArgsInvalidInteger(self):
1442 """Test that an invalid entry-argument integer is detected"""
1443 entry_args = {
1444 'test-int-arg': 'abc',
1445 }
1446 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001447 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001448 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1449 "'test-int-arg' (value 'abc') to integer",
1450 str(e.exception))
1451
1452 def testEntryArgsInvalidDatatype(self):
1453 """Test that an invalid entry-argument datatype is detected
1454
1455 This test could be written in entry_test.py except that it needs
1456 access to control.entry_args, which seems more than that module should
1457 be able to see.
1458 """
1459 entry_args = {
1460 'test-bad-datatype-arg': '12',
1461 }
1462 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001463 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass91710b32018-07-17 13:25:32 -06001464 entry_args=entry_args)
1465 self.assertIn('GetArg() internal error: Unknown data type ',
1466 str(e.exception))
1467
Simon Glass2ca52032018-07-17 13:25:33 -06001468 def testText(self):
1469 """Test for a text entry type"""
1470 entry_args = {
1471 'test-id': TEXT_DATA,
1472 'test-id2': TEXT_DATA2,
1473 'test-id3': TEXT_DATA3,
1474 }
Simon Glass511f6582018-10-01 12:22:30 -06001475 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glass2ca52032018-07-17 13:25:33 -06001476 entry_args=entry_args)
Simon Glass303f62f2019-05-17 22:00:46 -06001477 expected = (tools.ToBytes(TEXT_DATA) +
1478 tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1479 tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
Simon Glass47f6a622019-07-08 13:18:40 -06001480 b'some text' + b'more text')
Simon Glass2ca52032018-07-17 13:25:33 -06001481 self.assertEqual(expected, data)
1482
Simon Glass969616c2018-07-17 13:25:36 -06001483 def testEntryDocs(self):
1484 """Test for creation of entry documentation"""
1485 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001486 control.WriteEntryDocs(control.GetEntryModules())
Simon Glass969616c2018-07-17 13:25:36 -06001487 self.assertTrue(len(stdout.getvalue()) > 0)
1488
1489 def testEntryDocsMissing(self):
1490 """Test handling of missing entry documentation"""
1491 with self.assertRaises(ValueError) as e:
1492 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001493 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glass969616c2018-07-17 13:25:36 -06001494 self.assertIn('Documentation is missing for modules: u_boot',
1495 str(e.exception))
1496
Simon Glass704784b2018-07-17 13:25:38 -06001497 def testFmap(self):
1498 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06001499 data = self._DoReadFile('067_fmap.dts')
Simon Glass704784b2018-07-17 13:25:38 -06001500 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass303f62f2019-05-17 22:00:46 -06001501 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1502 U_BOOT_DATA + tools.GetBytes(ord('a'), 12))
Simon Glass704784b2018-07-17 13:25:38 -06001503 self.assertEqual(expected, data[:32])
Simon Glass303f62f2019-05-17 22:00:46 -06001504 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass704784b2018-07-17 13:25:38 -06001505 self.assertEqual(1, fhdr.ver_major)
1506 self.assertEqual(0, fhdr.ver_minor)
1507 self.assertEqual(0, fhdr.base)
1508 self.assertEqual(16 + 16 +
1509 fmap_util.FMAP_HEADER_LEN +
1510 fmap_util.FMAP_AREA_LEN * 3, fhdr.image_size)
Simon Glass303f62f2019-05-17 22:00:46 -06001511 self.assertEqual(b'FMAP', fhdr.name)
Simon Glass704784b2018-07-17 13:25:38 -06001512 self.assertEqual(3, fhdr.nareas)
1513 for fentry in fentries:
1514 self.assertEqual(0, fentry.flags)
1515
1516 self.assertEqual(0, fentries[0].offset)
1517 self.assertEqual(4, fentries[0].size)
Simon Glass303f62f2019-05-17 22:00:46 -06001518 self.assertEqual(b'RO_U_BOOT', fentries[0].name)
Simon Glass704784b2018-07-17 13:25:38 -06001519
1520 self.assertEqual(16, fentries[1].offset)
1521 self.assertEqual(4, fentries[1].size)
Simon Glass303f62f2019-05-17 22:00:46 -06001522 self.assertEqual(b'RW_U_BOOT', fentries[1].name)
Simon Glass704784b2018-07-17 13:25:38 -06001523
1524 self.assertEqual(32, fentries[2].offset)
1525 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1526 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glass303f62f2019-05-17 22:00:46 -06001527 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glass704784b2018-07-17 13:25:38 -06001528
Simon Glassdb168d42018-07-17 13:25:39 -06001529 def testBlobNamedByArg(self):
1530 """Test we can add a blob with the filename coming from an entry arg"""
1531 entry_args = {
1532 'cros-ec-rw-path': 'ecrw.bin',
1533 }
Simon Glass21db0ff2020-09-01 05:13:54 -06001534 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassdb168d42018-07-17 13:25:39 -06001535
Simon Glass53f53992018-07-17 13:25:40 -06001536 def testFill(self):
1537 """Test for an fill entry type"""
Simon Glass511f6582018-10-01 12:22:30 -06001538 data = self._DoReadFile('069_fill.dts')
Simon Glassac0d4952019-05-14 15:53:47 -06001539 expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
Simon Glass53f53992018-07-17 13:25:40 -06001540 self.assertEqual(expected, data)
1541
1542 def testFillNoSize(self):
1543 """Test for an fill entry type with no size"""
1544 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001545 self._DoReadFile('070_fill_no_size.dts')
Simon Glass53f53992018-07-17 13:25:40 -06001546 self.assertIn("'fill' entry must have a size property",
1547 str(e.exception))
1548
Simon Glassc1ae83c2018-07-17 13:25:44 -06001549 def _HandleGbbCommand(self, pipe_list):
1550 """Fake calls to the futility utility"""
1551 if pipe_list[0][0] == 'futility':
1552 fname = pipe_list[0][-1]
1553 # Append our GBB data to the file, which will happen every time the
1554 # futility command is called.
Simon Glass33486662019-05-14 15:53:42 -06001555 with open(fname, 'ab') as fd:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001556 fd.write(GBB_DATA)
1557 return command.CommandResult()
1558
1559 def testGbb(self):
1560 """Test for the Chromium OS Google Binary Block"""
1561 command.test_result = self._HandleGbbCommand
1562 entry_args = {
1563 'keydir': 'devkeys',
1564 'bmpblk': 'bmpblk.bin',
1565 }
Simon Glass511f6582018-10-01 12:22:30 -06001566 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glassc1ae83c2018-07-17 13:25:44 -06001567
1568 # Since futility
Simon Glassac0d4952019-05-14 15:53:47 -06001569 expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1570 tools.GetBytes(0, 0x2180 - 16))
Simon Glassc1ae83c2018-07-17 13:25:44 -06001571 self.assertEqual(expected, data)
1572
1573 def testGbbTooSmall(self):
1574 """Test for the Chromium OS Google Binary Block being large enough"""
1575 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001576 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001577 self.assertIn("Node '/binman/gbb': GBB is too small",
1578 str(e.exception))
1579
1580 def testGbbNoSize(self):
1581 """Test for the Chromium OS Google Binary Block having a size"""
1582 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001583 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001584 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1585 str(e.exception))
1586
Simon Glass5c350162018-07-17 13:25:47 -06001587 def _HandleVblockCommand(self, pipe_list):
1588 """Fake calls to the futility utility"""
1589 if pipe_list[0][0] == 'futility':
1590 fname = pipe_list[0][3]
Simon Glass639505b2018-09-14 04:57:11 -06001591 with open(fname, 'wb') as fd:
Simon Glass5c350162018-07-17 13:25:47 -06001592 fd.write(VBLOCK_DATA)
1593 return command.CommandResult()
1594
1595 def testVblock(self):
1596 """Test for the Chromium OS Verified Boot Block"""
1597 command.test_result = self._HandleVblockCommand
1598 entry_args = {
1599 'keydir': 'devkeys',
1600 }
Simon Glass511f6582018-10-01 12:22:30 -06001601 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass5c350162018-07-17 13:25:47 -06001602 entry_args=entry_args)
1603 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1604 self.assertEqual(expected, data)
1605
1606 def testVblockNoContent(self):
1607 """Test we detect a vblock which has no content to sign"""
1608 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001609 self._DoReadFile('075_vblock_no_content.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001610 self.assertIn("Node '/binman/vblock': Vblock must have a 'content' "
1611 'property', str(e.exception))
1612
1613 def testVblockBadPhandle(self):
1614 """Test that we detect a vblock with an invalid phandle in contents"""
1615 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001616 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001617 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1618 '1000', str(e.exception))
1619
1620 def testVblockBadEntry(self):
1621 """Test that we detect an entry that points to a non-entry"""
1622 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001623 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001624 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1625 "'other'", str(e.exception))
1626
Simon Glass8425a1f2018-07-17 13:25:48 -06001627 def testTpl(self):
Simon Glass3eb5b202019-08-24 07:23:00 -06001628 """Test that an image with TPL and its device tree can be created"""
Simon Glass8425a1f2018-07-17 13:25:48 -06001629 # ELF file with a '__bss_size' symbol
Simon Glass3eb5b202019-08-24 07:23:00 -06001630 self._SetupTplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001631 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glass8425a1f2018-07-17 13:25:48 -06001632 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1633
Simon Glass24b97442018-07-17 13:25:51 -06001634 def testUsesPos(self):
1635 """Test that the 'pos' property cannot be used anymore"""
1636 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001637 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass24b97442018-07-17 13:25:51 -06001638 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1639 "'pos'", str(e.exception))
1640
Simon Glass274bf092018-09-14 04:57:08 -06001641 def testFillZero(self):
1642 """Test for an fill entry type with a size of 0"""
Simon Glass511f6582018-10-01 12:22:30 -06001643 data = self._DoReadFile('080_fill_empty.dts')
Simon Glassac0d4952019-05-14 15:53:47 -06001644 self.assertEqual(tools.GetBytes(0, 16), data)
Simon Glass274bf092018-09-14 04:57:08 -06001645
Simon Glass267de432018-09-14 04:57:09 -06001646 def testTextMissing(self):
1647 """Test for a text entry type where there is no text"""
1648 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001649 self._DoReadFileDtb('066_text.dts',)
Simon Glass267de432018-09-14 04:57:09 -06001650 self.assertIn("Node '/binman/text': No value provided for text label "
1651 "'test-id'", str(e.exception))
1652
Simon Glassed40e962018-09-14 04:57:10 -06001653 def testPackStart16Tpl(self):
1654 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001655 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glassed40e962018-09-14 04:57:10 -06001656 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1657
Simon Glass3b376c32018-09-14 04:57:12 -06001658 def testSelectImage(self):
1659 """Test that we can select which images to build"""
Simon Glassb4595d82019-04-25 21:58:34 -06001660 expected = 'Skipping images: image1'
1661
1662 # We should only get the expected message in verbose mode
Simon Glass8a50b4a2019-07-08 13:18:48 -06001663 for verbosity in (0, 2):
Simon Glassb4595d82019-04-25 21:58:34 -06001664 with test_util.capture_sys_output() as (stdout, stderr):
1665 retcode = self._DoTestFile('006_dual_image.dts',
1666 verbosity=verbosity,
1667 images=['image2'])
1668 self.assertEqual(0, retcode)
1669 if verbosity:
1670 self.assertIn(expected, stdout.getvalue())
1671 else:
1672 self.assertNotIn(expected, stdout.getvalue())
Simon Glass3b376c32018-09-14 04:57:12 -06001673
Simon Glassb4595d82019-04-25 21:58:34 -06001674 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1675 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
Simon Glassb3d6fc72019-07-20 12:24:10 -06001676 self._CleanupOutputDir()
Simon Glass3b376c32018-09-14 04:57:12 -06001677
Simon Glasse219aa42018-09-14 04:57:24 -06001678 def testUpdateFdtAll(self):
1679 """Test that all device trees are updated with offset/size info"""
Simon Glass5b4bce32019-07-08 14:25:26 -06001680 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glasse219aa42018-09-14 04:57:24 -06001681
1682 base_expected = {
1683 'section:image-pos': 0,
1684 'u-boot-tpl-dtb:size': 513,
1685 'u-boot-spl-dtb:size': 513,
1686 'u-boot-spl-dtb:offset': 493,
1687 'image-pos': 0,
1688 'section/u-boot-dtb:image-pos': 0,
1689 'u-boot-spl-dtb:image-pos': 493,
1690 'section/u-boot-dtb:size': 493,
1691 'u-boot-tpl-dtb:image-pos': 1006,
1692 'section/u-boot-dtb:offset': 0,
1693 'section:size': 493,
1694 'offset': 0,
1695 'section:offset': 0,
1696 'u-boot-tpl-dtb:offset': 1006,
1697 'size': 1519
1698 }
1699
1700 # We expect three device-tree files in the output, one after the other.
1701 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1702 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1703 # main U-Boot tree. All three should have the same postions and offset.
1704 start = 0
1705 for item in ['', 'spl', 'tpl']:
1706 dtb = fdt.Fdt.FromData(data[start:])
1707 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06001708 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
1709 ['spl', 'tpl'])
Simon Glasse219aa42018-09-14 04:57:24 -06001710 expected = dict(base_expected)
1711 if item:
1712 expected[item] = 0
1713 self.assertEqual(expected, props)
1714 start += dtb._fdt_obj.totalsize()
1715
1716 def testUpdateFdtOutput(self):
1717 """Test that output DTB files are updated"""
1718 try:
Simon Glass511f6582018-10-01 12:22:30 -06001719 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glasse219aa42018-09-14 04:57:24 -06001720 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1721
1722 # Unfortunately, compiling a source file always results in a file
1723 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass511f6582018-10-01 12:22:30 -06001724 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glasse219aa42018-09-14 04:57:24 -06001725 # binman as a file called u-boot.dtb. To fix this, copy the file
1726 # over to the expected place.
Simon Glasse219aa42018-09-14 04:57:24 -06001727 start = 0
1728 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1729 'tpl/u-boot-tpl.dtb.out']:
1730 dtb = fdt.Fdt.FromData(data[start:])
1731 size = dtb._fdt_obj.totalsize()
1732 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1733 outdata = tools.ReadFile(pathname)
1734 name = os.path.split(fname)[0]
1735
1736 if name:
1737 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1738 else:
1739 orig_indata = dtb_data
1740 self.assertNotEqual(outdata, orig_indata,
1741 "Expected output file '%s' be updated" % pathname)
1742 self.assertEqual(outdata, data[start:start + size],
1743 "Expected output file '%s' to match output image" %
1744 pathname)
1745 start += size
1746 finally:
1747 self._ResetDtbs()
1748
Simon Glass7ba33592018-09-14 04:57:26 -06001749 def _decompress(self, data):
Simon Glassccec0262019-07-08 13:18:42 -06001750 return tools.Decompress(data, 'lz4')
Simon Glass7ba33592018-09-14 04:57:26 -06001751
1752 def testCompress(self):
1753 """Test compression of blobs"""
Simon Glass1de34482019-07-08 13:18:53 -06001754 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06001755 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass7ba33592018-09-14 04:57:26 -06001756 use_real_dtb=True, update_dtb=True)
1757 dtb = fdt.Fdt(out_dtb_fname)
1758 dtb.Scan()
1759 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1760 orig = self._decompress(data)
1761 self.assertEquals(COMPRESS_DATA, orig)
1762 expected = {
1763 'blob:uncomp-size': len(COMPRESS_DATA),
1764 'blob:size': len(data),
1765 'size': len(data),
1766 }
1767 self.assertEqual(expected, props)
1768
Simon Glassac6328c2018-09-14 04:57:28 -06001769 def testFiles(self):
1770 """Test bringing in multiple files"""
Simon Glass511f6582018-10-01 12:22:30 -06001771 data = self._DoReadFile('084_files.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06001772 self.assertEqual(FILES_DATA, data)
1773
1774 def testFilesCompress(self):
1775 """Test bringing in multiple files and compressing them"""
Simon Glass1de34482019-07-08 13:18:53 -06001776 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06001777 data = self._DoReadFile('085_files_compress.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06001778
1779 image = control.images['image']
1780 entries = image.GetEntries()
1781 files = entries['files']
Simon Glass39dd2152019-07-08 14:25:47 -06001782 entries = files._entries
Simon Glassac6328c2018-09-14 04:57:28 -06001783
Simon Glass303f62f2019-05-17 22:00:46 -06001784 orig = b''
Simon Glassac6328c2018-09-14 04:57:28 -06001785 for i in range(1, 3):
1786 key = '%d.dat' % i
1787 start = entries[key].image_pos
1788 len = entries[key].size
1789 chunk = data[start:start + len]
1790 orig += self._decompress(chunk)
1791
1792 self.assertEqual(FILES_DATA, orig)
1793
1794 def testFilesMissing(self):
1795 """Test missing files"""
1796 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001797 data = self._DoReadFile('086_files_none.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06001798 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1799 'no files', str(e.exception))
1800
1801 def testFilesNoPattern(self):
1802 """Test missing files"""
1803 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001804 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06001805 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1806 str(e.exception))
1807
Simon Glassfa79a812018-09-14 04:57:29 -06001808 def testExpandSize(self):
1809 """Test an expanding entry"""
Simon Glass511f6582018-10-01 12:22:30 -06001810 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
Simon Glassfa79a812018-09-14 04:57:29 -06001811 map=True)
Simon Glass303f62f2019-05-17 22:00:46 -06001812 expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA +
1813 MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA +
1814 tools.GetBytes(ord('c'), 8) + U_BOOT_DATA +
1815 tools.GetBytes(ord('d'), 8))
Simon Glassfa79a812018-09-14 04:57:29 -06001816 self.assertEqual(expect, data)
1817 self.assertEqual('''ImagePos Offset Size Name
181800000000 00000000 00000028 main-section
181900000000 00000000 00000008 fill
182000000008 00000008 00000004 u-boot
18210000000c 0000000c 00000004 section
18220000000c 00000000 00000003 intel-mrc
182300000010 00000010 00000004 u-boot2
182400000014 00000014 0000000c section2
182500000014 00000000 00000008 fill
18260000001c 00000008 00000004 u-boot
182700000020 00000020 00000008 fill2
1828''', map_data)
1829
1830 def testExpandSizeBad(self):
1831 """Test an expanding entry which fails to provide contents"""
Simon Glasscd817d52018-09-14 04:57:36 -06001832 with test_util.capture_sys_output() as (stdout, stderr):
1833 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001834 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
Simon Glassfa79a812018-09-14 04:57:29 -06001835 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
1836 'expanding entry', str(e.exception))
1837
Simon Glassae7cf032018-09-14 04:57:31 -06001838 def testHash(self):
1839 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06001840 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06001841 use_real_dtb=True, update_dtb=True)
1842 dtb = fdt.Fdt(out_dtb_fname)
1843 dtb.Scan()
1844 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
1845 m = hashlib.sha256()
1846 m.update(U_BOOT_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06001847 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06001848
1849 def testHashNoAlgo(self):
1850 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001851 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glassae7cf032018-09-14 04:57:31 -06001852 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
1853 'hash node', str(e.exception))
1854
1855 def testHashBadAlgo(self):
1856 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001857 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glassae7cf032018-09-14 04:57:31 -06001858 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
1859 str(e.exception))
1860
1861 def testHashSection(self):
1862 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06001863 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06001864 use_real_dtb=True, update_dtb=True)
1865 dtb = fdt.Fdt(out_dtb_fname)
1866 dtb.Scan()
1867 hash_node = dtb.GetNode('/binman/section/hash').props['value']
1868 m = hashlib.sha256()
1869 m.update(U_BOOT_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06001870 m.update(tools.GetBytes(ord('a'), 16))
1871 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06001872
Simon Glass3fb4f422018-09-14 04:57:32 -06001873 def testPackUBootTplMicrocode(self):
1874 """Test that x86 microcode can be handled correctly in TPL
1875
1876 We expect to see the following in the image, in order:
1877 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
1878 place
1879 u-boot-tpl.dtb with the microcode removed
1880 the microcode
1881 """
Simon Glass3eb5b202019-08-24 07:23:00 -06001882 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass511f6582018-10-01 12:22:30 -06001883 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glass3fb4f422018-09-14 04:57:32 -06001884 U_BOOT_TPL_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06001885 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
1886 b'ter somewhere in here', first)
Simon Glass3fb4f422018-09-14 04:57:32 -06001887
Simon Glassc64aea52018-09-14 04:57:34 -06001888 def testFmapX86(self):
1889 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06001890 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassc64aea52018-09-14 04:57:34 -06001891 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass303f62f2019-05-17 22:00:46 -06001892 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06001893 self.assertEqual(expected, data[:32])
1894 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1895
1896 self.assertEqual(0x100, fhdr.image_size)
1897
1898 self.assertEqual(0, fentries[0].offset)
1899 self.assertEqual(4, fentries[0].size)
Simon Glass303f62f2019-05-17 22:00:46 -06001900 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassc64aea52018-09-14 04:57:34 -06001901
1902 self.assertEqual(4, fentries[1].offset)
1903 self.assertEqual(3, fentries[1].size)
Simon Glass303f62f2019-05-17 22:00:46 -06001904 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassc64aea52018-09-14 04:57:34 -06001905
1906 self.assertEqual(32, fentries[2].offset)
1907 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1908 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glass303f62f2019-05-17 22:00:46 -06001909 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassc64aea52018-09-14 04:57:34 -06001910
1911 def testFmapX86Section(self):
1912 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06001913 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glass303f62f2019-05-17 22:00:46 -06001914 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06001915 self.assertEqual(expected, data[:32])
1916 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
1917
1918 self.assertEqual(0x100, fhdr.image_size)
1919
1920 self.assertEqual(0, fentries[0].offset)
1921 self.assertEqual(4, fentries[0].size)
Simon Glass303f62f2019-05-17 22:00:46 -06001922 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassc64aea52018-09-14 04:57:34 -06001923
1924 self.assertEqual(4, fentries[1].offset)
1925 self.assertEqual(3, fentries[1].size)
Simon Glass303f62f2019-05-17 22:00:46 -06001926 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassc64aea52018-09-14 04:57:34 -06001927
1928 self.assertEqual(36, fentries[2].offset)
1929 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1930 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glass303f62f2019-05-17 22:00:46 -06001931 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassc64aea52018-09-14 04:57:34 -06001932
Simon Glassb1714232018-09-14 04:57:35 -06001933 def testElf(self):
1934 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06001935 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06001936 self._SetupTplElf()
Simon Glassf6290892019-08-24 07:22:53 -06001937 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06001938 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06001939 data = self._DoReadFile('096_elf.dts')
Simon Glassb1714232018-09-14 04:57:35 -06001940
Simon Glass0d673792019-07-08 13:18:25 -06001941 def testElfStrip(self):
Simon Glassb1714232018-09-14 04:57:35 -06001942 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06001943 self._SetupSplElf()
Simon Glassf6290892019-08-24 07:22:53 -06001944 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06001945 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06001946 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassb1714232018-09-14 04:57:35 -06001947
Simon Glasscd817d52018-09-14 04:57:36 -06001948 def testPackOverlapMap(self):
1949 """Test that overlapping regions are detected"""
1950 with test_util.capture_sys_output() as (stdout, stderr):
1951 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001952 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glasscd817d52018-09-14 04:57:36 -06001953 map_fname = tools.GetOutputFilename('image.map')
1954 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
1955 stdout.getvalue())
1956
1957 # We should not get an inmage, but there should be a map file
1958 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
1959 self.assertTrue(os.path.exists(map_fname))
Simon Glassb3774752019-05-17 22:00:51 -06001960 map_data = tools.ReadFile(map_fname, binary=False)
Simon Glasscd817d52018-09-14 04:57:36 -06001961 self.assertEqual('''ImagePos Offset Size Name
1962<none> 00000000 00000007 main-section
1963<none> 00000000 00000004 u-boot
1964<none> 00000003 00000004 u-boot-align
1965''', map_data)
1966
Simon Glass0d673792019-07-08 13:18:25 -06001967 def testPackRefCode(self):
Simon Glass41902e42018-10-01 12:22:31 -06001968 """Test that an image with an Intel Reference code binary works"""
1969 data = self._DoReadFile('100_intel_refcode.dts')
1970 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
1971
Simon Glasseb023b32019-04-25 21:58:39 -06001972 def testSectionOffset(self):
1973 """Tests use of a section with an offset"""
1974 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
1975 map=True)
1976 self.assertEqual('''ImagePos Offset Size Name
197700000000 00000000 00000038 main-section
197800000004 00000004 00000010 section@0
197900000004 00000000 00000004 u-boot
198000000018 00000018 00000010 section@1
198100000018 00000000 00000004 u-boot
19820000002c 0000002c 00000004 section@2
19830000002c 00000000 00000004 u-boot
1984''', map_data)
1985 self.assertEqual(data,
Simon Glassac0d4952019-05-14 15:53:47 -06001986 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1987 tools.GetBytes(0x21, 12) +
1988 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1989 tools.GetBytes(0x61, 12) +
1990 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1991 tools.GetBytes(0x26, 8))
Simon Glasseb023b32019-04-25 21:58:39 -06001992
Simon Glass1de34482019-07-08 13:18:53 -06001993 def testCbfsRaw(self):
1994 """Test base handling of a Coreboot Filesystem (CBFS)
1995
1996 The exact contents of the CBFS is verified by similar tests in
1997 cbfs_util_test.py. The tests here merely check that the files added to
1998 the CBFS can be found in the final image.
1999 """
2000 data = self._DoReadFile('102_cbfs_raw.dts')
2001 size = 0xb0
2002
2003 cbfs = cbfs_util.CbfsReader(data)
2004 self.assertEqual(size, cbfs.rom_size)
2005
2006 self.assertIn('u-boot-dtb', cbfs.files)
2007 cfile = cbfs.files['u-boot-dtb']
2008 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2009
2010 def testCbfsArch(self):
2011 """Test on non-x86 architecture"""
2012 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2013 size = 0x100
2014
2015 cbfs = cbfs_util.CbfsReader(data)
2016 self.assertEqual(size, cbfs.rom_size)
2017
2018 self.assertIn('u-boot-dtb', cbfs.files)
2019 cfile = cbfs.files['u-boot-dtb']
2020 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2021
2022 def testCbfsStage(self):
2023 """Tests handling of a Coreboot Filesystem (CBFS)"""
2024 if not elf.ELF_TOOLS:
2025 self.skipTest('Python elftools not available')
2026 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2027 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2028 size = 0xb0
2029
2030 data = self._DoReadFile('104_cbfs_stage.dts')
2031 cbfs = cbfs_util.CbfsReader(data)
2032 self.assertEqual(size, cbfs.rom_size)
2033
2034 self.assertIn('u-boot', cbfs.files)
2035 cfile = cbfs.files['u-boot']
2036 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2037
2038 def testCbfsRawCompress(self):
2039 """Test handling of compressing raw files"""
2040 self._CheckLz4()
2041 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2042 size = 0x140
2043
2044 cbfs = cbfs_util.CbfsReader(data)
2045 self.assertIn('u-boot', cbfs.files)
2046 cfile = cbfs.files['u-boot']
2047 self.assertEqual(COMPRESS_DATA, cfile.data)
2048
2049 def testCbfsBadArch(self):
2050 """Test handling of a bad architecture"""
2051 with self.assertRaises(ValueError) as e:
2052 self._DoReadFile('106_cbfs_bad_arch.dts')
2053 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2054
2055 def testCbfsNoSize(self):
2056 """Test handling of a missing size property"""
2057 with self.assertRaises(ValueError) as e:
2058 self._DoReadFile('107_cbfs_no_size.dts')
2059 self.assertIn('entry must have a size property', str(e.exception))
2060
2061 def testCbfsNoCOntents(self):
2062 """Test handling of a CBFS entry which does not provide contentsy"""
2063 with self.assertRaises(ValueError) as e:
2064 self._DoReadFile('108_cbfs_no_contents.dts')
2065 self.assertIn('Could not complete processing of contents',
2066 str(e.exception))
2067
2068 def testCbfsBadCompress(self):
2069 """Test handling of a bad architecture"""
2070 with self.assertRaises(ValueError) as e:
2071 self._DoReadFile('109_cbfs_bad_compress.dts')
2072 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2073 str(e.exception))
2074
2075 def testCbfsNamedEntries(self):
2076 """Test handling of named entries"""
2077 data = self._DoReadFile('110_cbfs_name.dts')
2078
2079 cbfs = cbfs_util.CbfsReader(data)
2080 self.assertIn('FRED', cbfs.files)
2081 cfile1 = cbfs.files['FRED']
2082 self.assertEqual(U_BOOT_DATA, cfile1.data)
2083
2084 self.assertIn('hello', cbfs.files)
2085 cfile2 = cbfs.files['hello']
2086 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2087
Simon Glass759af872019-07-08 13:18:54 -06002088 def _SetupIfwi(self, fname):
2089 """Set up to run an IFWI test
2090
2091 Args:
2092 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2093 """
2094 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002095 self._SetupTplElf()
Simon Glass759af872019-07-08 13:18:54 -06002096
2097 # Intel Integrated Firmware Image (IFWI) file
2098 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2099 data = fd.read()
2100 TestFunctional._MakeInputFile(fname,data)
2101
2102 def _CheckIfwi(self, data):
2103 """Check that an image with an IFWI contains the correct output
2104
2105 Args:
2106 data: Conents of output file
2107 """
2108 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
2109 if data[:0x1000] != expected_desc:
2110 self.fail('Expected descriptor binary at start of image')
2111
2112 # We expect to find the TPL wil in subpart IBBP entry IBBL
2113 image_fname = tools.GetOutputFilename('image.bin')
2114 tpl_fname = tools.GetOutputFilename('tpl.out')
2115 tools.RunIfwiTool(image_fname, tools.CMD_EXTRACT, fname=tpl_fname,
2116 subpart='IBBP', entry_name='IBBL')
2117
2118 tpl_data = tools.ReadFile(tpl_fname)
Simon Glassf55bd692019-08-24 07:22:51 -06002119 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glass759af872019-07-08 13:18:54 -06002120
2121 def testPackX86RomIfwi(self):
2122 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2123 self._SetupIfwi('fitimage.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002124 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glass759af872019-07-08 13:18:54 -06002125 self._CheckIfwi(data)
2126
2127 def testPackX86RomIfwiNoDesc(self):
2128 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2129 self._SetupIfwi('ifwi.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002130 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glass759af872019-07-08 13:18:54 -06002131 self._CheckIfwi(data)
2132
2133 def testPackX86RomIfwiNoData(self):
2134 """Test that an x86 ROM with IFWI handles missing data"""
2135 self._SetupIfwi('ifwi.bin')
2136 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06002137 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glass759af872019-07-08 13:18:54 -06002138 self.assertIn('Could not complete processing of contents',
2139 str(e.exception))
Simon Glass91710b32018-07-17 13:25:32 -06002140
Simon Glassc2f1aed2019-07-08 13:18:56 -06002141 def testCbfsOffset(self):
2142 """Test a CBFS with files at particular offsets
2143
2144 Like all CFBS tests, this is just checking the logic that calls
2145 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2146 """
2147 data = self._DoReadFile('114_cbfs_offset.dts')
2148 size = 0x200
2149
2150 cbfs = cbfs_util.CbfsReader(data)
2151 self.assertEqual(size, cbfs.rom_size)
2152
2153 self.assertIn('u-boot', cbfs.files)
2154 cfile = cbfs.files['u-boot']
2155 self.assertEqual(U_BOOT_DATA, cfile.data)
2156 self.assertEqual(0x40, cfile.cbfs_offset)
2157
2158 self.assertIn('u-boot-dtb', cbfs.files)
2159 cfile2 = cbfs.files['u-boot-dtb']
2160 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2161 self.assertEqual(0x140, cfile2.cbfs_offset)
2162
Simon Glass0f621332019-07-08 14:25:27 -06002163 def testFdtmap(self):
2164 """Test an FDT map can be inserted in the image"""
2165 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2166 fdtmap_data = data[len(U_BOOT_DATA):]
2167 magic = fdtmap_data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002168 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass0f621332019-07-08 14:25:27 -06002169 self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
2170
2171 fdt_data = fdtmap_data[16:]
2172 dtb = fdt.Fdt.FromData(fdt_data)
2173 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002174 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass0f621332019-07-08 14:25:27 -06002175 self.assertEqual({
2176 'image-pos': 0,
2177 'offset': 0,
2178 'u-boot:offset': 0,
2179 'u-boot:size': len(U_BOOT_DATA),
2180 'u-boot:image-pos': 0,
2181 'fdtmap:image-pos': 4,
2182 'fdtmap:offset': 4,
2183 'fdtmap:size': len(fdtmap_data),
2184 'size': len(data),
2185 }, props)
2186
2187 def testFdtmapNoMatch(self):
2188 """Check handling of an FDT map when the section cannot be found"""
2189 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2190
2191 # Mangle the section name, which should cause a mismatch between the
2192 # correct FDT path and the one expected by the section
2193 image = control.images['image']
Simon Glasscec34ba2019-07-08 14:25:28 -06002194 image._node.path += '-suffix'
Simon Glass0f621332019-07-08 14:25:27 -06002195 entries = image.GetEntries()
2196 fdtmap = entries['fdtmap']
2197 with self.assertRaises(ValueError) as e:
2198 fdtmap._GetFdtmap()
2199 self.assertIn("Cannot locate node for path '/binman-suffix'",
2200 str(e.exception))
2201
Simon Glasscec34ba2019-07-08 14:25:28 -06002202 def testFdtmapHeader(self):
2203 """Test an FDT map and image header can be inserted in the image"""
2204 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2205 fdtmap_pos = len(U_BOOT_DATA)
2206 fdtmap_data = data[fdtmap_pos:]
2207 fdt_data = fdtmap_data[16:]
2208 dtb = fdt.Fdt.FromData(fdt_data)
2209 fdt_size = dtb.GetFdtObj().totalsize()
2210 hdr_data = data[-8:]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002211 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002212 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2213 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2214
2215 def testFdtmapHeaderStart(self):
2216 """Test an image header can be inserted at the image start"""
2217 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2218 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2219 hdr_data = data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002220 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002221 offset = struct.unpack('<I', hdr_data[4:])[0]
2222 self.assertEqual(fdtmap_pos, offset)
2223
2224 def testFdtmapHeaderPos(self):
2225 """Test an image header can be inserted at a chosen position"""
2226 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2227 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2228 hdr_data = data[0x80:0x88]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002229 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002230 offset = struct.unpack('<I', hdr_data[4:])[0]
2231 self.assertEqual(fdtmap_pos, offset)
2232
2233 def testHeaderMissingFdtmap(self):
2234 """Test an image header requires an fdtmap"""
2235 with self.assertRaises(ValueError) as e:
2236 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2237 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2238 str(e.exception))
2239
2240 def testHeaderNoLocation(self):
2241 """Test an image header with a no specified location is detected"""
2242 with self.assertRaises(ValueError) as e:
2243 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2244 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2245 str(e.exception))
2246
Simon Glasse61b6f62019-07-08 14:25:37 -06002247 def testEntryExpand(self):
2248 """Test expanding an entry after it is packed"""
2249 data = self._DoReadFile('121_entry_expand.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002250 self.assertEqual(b'aaa', data[:3])
2251 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2252 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002253
2254 def testEntryExpandBad(self):
2255 """Test expanding an entry after it is packed, twice"""
2256 with self.assertRaises(ValueError) as e:
2257 self._DoReadFile('122_entry_expand_twice.dts')
Simon Glass9d8ee322019-07-20 12:23:58 -06002258 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glasse61b6f62019-07-08 14:25:37 -06002259 str(e.exception))
2260
2261 def testEntryExpandSection(self):
2262 """Test expanding an entry within a section after it is packed"""
2263 data = self._DoReadFile('123_entry_expand_section.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002264 self.assertEqual(b'aaa', data[:3])
2265 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2266 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002267
Simon Glass90d29682019-07-08 14:25:38 -06002268 def testCompressDtb(self):
2269 """Test that compress of device-tree files is supported"""
2270 self._CheckLz4()
2271 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2272 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2273 comp_data = data[len(U_BOOT_DATA):]
2274 orig = self._decompress(comp_data)
2275 dtb = fdt.Fdt.FromData(orig)
2276 dtb.Scan()
2277 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2278 expected = {
2279 'u-boot:size': len(U_BOOT_DATA),
2280 'u-boot-dtb:uncomp-size': len(orig),
2281 'u-boot-dtb:size': len(comp_data),
2282 'size': len(data),
2283 }
2284 self.assertEqual(expected, props)
2285
Simon Glass151bbbf2019-07-08 14:25:41 -06002286 def testCbfsUpdateFdt(self):
2287 """Test that we can update the device tree with CBFS offset/size info"""
2288 self._CheckLz4()
2289 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2290 update_dtb=True)
2291 dtb = fdt.Fdt(out_dtb_fname)
2292 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002293 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass151bbbf2019-07-08 14:25:41 -06002294 del props['cbfs/u-boot:size']
2295 self.assertEqual({
2296 'offset': 0,
2297 'size': len(data),
2298 'image-pos': 0,
2299 'cbfs:offset': 0,
2300 'cbfs:size': len(data),
2301 'cbfs:image-pos': 0,
2302 'cbfs/u-boot:offset': 0x38,
2303 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2304 'cbfs/u-boot:image-pos': 0x38,
2305 'cbfs/u-boot-dtb:offset': 0xb8,
2306 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2307 'cbfs/u-boot-dtb:image-pos': 0xb8,
2308 }, props)
2309
Simon Glass3c9b4f22019-07-08 14:25:42 -06002310 def testCbfsBadType(self):
2311 """Test an image header with a no specified location is detected"""
2312 with self.assertRaises(ValueError) as e:
2313 self._DoReadFile('126_cbfs_bad_type.dts')
2314 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2315
Simon Glass6b156f82019-07-08 14:25:43 -06002316 def testList(self):
2317 """Test listing the files in an image"""
2318 self._CheckLz4()
2319 data = self._DoReadFile('127_list.dts')
2320 image = control.images['image']
2321 entries = image.BuildEntryList()
2322 self.assertEqual(7, len(entries))
2323
2324 ent = entries[0]
2325 self.assertEqual(0, ent.indent)
2326 self.assertEqual('main-section', ent.name)
2327 self.assertEqual('section', ent.etype)
2328 self.assertEqual(len(data), ent.size)
2329 self.assertEqual(0, ent.image_pos)
2330 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002331 self.assertEqual(0, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002332
2333 ent = entries[1]
2334 self.assertEqual(1, ent.indent)
2335 self.assertEqual('u-boot', ent.name)
2336 self.assertEqual('u-boot', ent.etype)
2337 self.assertEqual(len(U_BOOT_DATA), ent.size)
2338 self.assertEqual(0, ent.image_pos)
2339 self.assertEqual(None, ent.uncomp_size)
2340 self.assertEqual(0, ent.offset)
2341
2342 ent = entries[2]
2343 self.assertEqual(1, ent.indent)
2344 self.assertEqual('section', ent.name)
2345 self.assertEqual('section', ent.etype)
2346 section_size = ent.size
2347 self.assertEqual(0x100, ent.image_pos)
2348 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002349 self.assertEqual(0x100, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002350
2351 ent = entries[3]
2352 self.assertEqual(2, ent.indent)
2353 self.assertEqual('cbfs', ent.name)
2354 self.assertEqual('cbfs', ent.etype)
2355 self.assertEqual(0x400, ent.size)
2356 self.assertEqual(0x100, ent.image_pos)
2357 self.assertEqual(None, ent.uncomp_size)
2358 self.assertEqual(0, ent.offset)
2359
2360 ent = entries[4]
2361 self.assertEqual(3, ent.indent)
2362 self.assertEqual('u-boot', ent.name)
2363 self.assertEqual('u-boot', ent.etype)
2364 self.assertEqual(len(U_BOOT_DATA), ent.size)
2365 self.assertEqual(0x138, ent.image_pos)
2366 self.assertEqual(None, ent.uncomp_size)
2367 self.assertEqual(0x38, ent.offset)
2368
2369 ent = entries[5]
2370 self.assertEqual(3, ent.indent)
2371 self.assertEqual('u-boot-dtb', ent.name)
2372 self.assertEqual('text', ent.etype)
2373 self.assertGreater(len(COMPRESS_DATA), ent.size)
2374 self.assertEqual(0x178, ent.image_pos)
2375 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2376 self.assertEqual(0x78, ent.offset)
2377
2378 ent = entries[6]
2379 self.assertEqual(2, ent.indent)
2380 self.assertEqual('u-boot-dtb', ent.name)
2381 self.assertEqual('u-boot-dtb', ent.etype)
2382 self.assertEqual(0x500, ent.image_pos)
2383 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2384 dtb_size = ent.size
2385 # Compressing this data expands it since headers are added
2386 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2387 self.assertEqual(0x400, ent.offset)
2388
2389 self.assertEqual(len(data), 0x100 + section_size)
2390 self.assertEqual(section_size, 0x400 + dtb_size)
2391
Simon Glass8d8bf4e2019-07-08 14:25:44 -06002392 def testFindFdtmap(self):
2393 """Test locating an FDT map in an image"""
2394 self._CheckLz4()
2395 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2396 image = control.images['image']
2397 entries = image.GetEntries()
2398 entry = entries['fdtmap']
2399 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2400
2401 def testFindFdtmapMissing(self):
2402 """Test failing to locate an FDP map"""
2403 data = self._DoReadFile('005_simple.dts')
2404 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2405
Simon Glassed39a3c2019-07-08 14:25:45 -06002406 def testFindImageHeader(self):
2407 """Test locating a image header"""
2408 self._CheckLz4()
Simon Glassb8424fa2019-07-08 14:25:46 -06002409 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002410 image = control.images['image']
2411 entries = image.GetEntries()
2412 entry = entries['fdtmap']
2413 # The header should point to the FDT map
2414 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2415
2416 def testFindImageHeaderStart(self):
2417 """Test locating a image header located at the start of an image"""
Simon Glassb8424fa2019-07-08 14:25:46 -06002418 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002419 image = control.images['image']
2420 entries = image.GetEntries()
2421 entry = entries['fdtmap']
2422 # The header should point to the FDT map
2423 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2424
2425 def testFindImageHeaderMissing(self):
2426 """Test failing to locate an image header"""
2427 data = self._DoReadFile('005_simple.dts')
2428 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2429
Simon Glassb8424fa2019-07-08 14:25:46 -06002430 def testReadImage(self):
2431 """Test reading an image and accessing its FDT map"""
2432 self._CheckLz4()
2433 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2434 image_fname = tools.GetOutputFilename('image.bin')
2435 orig_image = control.images['image']
2436 image = Image.FromFile(image_fname)
2437 self.assertEqual(orig_image.GetEntries().keys(),
2438 image.GetEntries().keys())
2439
2440 orig_entry = orig_image.GetEntries()['fdtmap']
2441 entry = image.GetEntries()['fdtmap']
2442 self.assertEquals(orig_entry.offset, entry.offset)
2443 self.assertEquals(orig_entry.size, entry.size)
2444 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2445
2446 def testReadImageNoHeader(self):
2447 """Test accessing an image's FDT map without an image header"""
2448 self._CheckLz4()
2449 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
2450 image_fname = tools.GetOutputFilename('image.bin')
2451 image = Image.FromFile(image_fname)
2452 self.assertTrue(isinstance(image, Image))
Simon Glass072959a2019-07-20 12:23:50 -06002453 self.assertEqual('image', image.image_name[-5:])
Simon Glassb8424fa2019-07-08 14:25:46 -06002454
2455 def testReadImageFail(self):
2456 """Test failing to read an image image's FDT map"""
2457 self._DoReadFile('005_simple.dts')
2458 image_fname = tools.GetOutputFilename('image.bin')
2459 with self.assertRaises(ValueError) as e:
2460 image = Image.FromFile(image_fname)
2461 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glassc2f1aed2019-07-08 13:18:56 -06002462
Simon Glassb2fd11d2019-07-08 14:25:48 -06002463 def testListCmd(self):
2464 """Test listing the files in an image using an Fdtmap"""
2465 self._CheckLz4()
2466 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2467
2468 # lz4 compression size differs depending on the version
2469 image = control.images['image']
2470 entries = image.GetEntries()
2471 section_size = entries['section'].size
2472 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2473 fdtmap_offset = entries['fdtmap'].offset
2474
Simon Glassb3d6fc72019-07-20 12:24:10 -06002475 try:
2476 tmpdir, updated_fname = self._SetupImageInTmpdir()
2477 with test_util.capture_sys_output() as (stdout, stderr):
2478 self._DoBinman('ls', '-i', updated_fname)
2479 finally:
2480 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002481 lines = stdout.getvalue().splitlines()
2482 expected = [
2483'Name Image-pos Size Entry-type Offset Uncomp-size',
2484'----------------------------------------------------------------------',
2485'main-section 0 c00 section 0',
2486' u-boot 0 4 u-boot 0',
2487' section 100 %x section 100' % section_size,
2488' cbfs 100 400 cbfs 0',
2489' u-boot 138 4 u-boot 38',
Simon Glassc5fd10a2019-10-31 07:43:03 -06002490' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002491' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassc5fd10a2019-10-31 07:43:03 -06002492' fdtmap %x 3bd fdtmap %x' %
Simon Glassb2fd11d2019-07-08 14:25:48 -06002493 (fdtmap_offset, fdtmap_offset),
2494' image-header bf8 8 image-header bf8',
2495 ]
2496 self.assertEqual(expected, lines)
2497
2498 def testListCmdFail(self):
2499 """Test failing to list an image"""
2500 self._DoReadFile('005_simple.dts')
Simon Glassb3d6fc72019-07-20 12:24:10 -06002501 try:
2502 tmpdir, updated_fname = self._SetupImageInTmpdir()
2503 with self.assertRaises(ValueError) as e:
2504 self._DoBinman('ls', '-i', updated_fname)
2505 finally:
2506 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002507 self.assertIn("Cannot find FDT map in image", str(e.exception))
2508
2509 def _RunListCmd(self, paths, expected):
2510 """List out entries and check the result
2511
2512 Args:
2513 paths: List of paths to pass to the list command
2514 expected: Expected list of filenames to be returned, in order
2515 """
2516 self._CheckLz4()
2517 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2518 image_fname = tools.GetOutputFilename('image.bin')
2519 image = Image.FromFile(image_fname)
2520 lines = image.GetListEntries(paths)[1]
2521 files = [line[0].strip() for line in lines[1:]]
2522 self.assertEqual(expected, files)
2523
2524 def testListCmdSection(self):
2525 """Test listing the files in a section"""
2526 self._RunListCmd(['section'],
2527 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2528
2529 def testListCmdFile(self):
2530 """Test listing a particular file"""
2531 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2532
2533 def testListCmdWildcard(self):
2534 """Test listing a wildcarded file"""
2535 self._RunListCmd(['*boot*'],
2536 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2537
2538 def testListCmdWildcardMulti(self):
2539 """Test listing a wildcarded file"""
2540 self._RunListCmd(['*cb*', '*head*'],
2541 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2542
2543 def testListCmdEmpty(self):
2544 """Test listing a wildcarded file"""
2545 self._RunListCmd(['nothing'], [])
2546
2547 def testListCmdPath(self):
2548 """Test listing the files in a sub-entry of a section"""
2549 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2550
Simon Glass4c613bf2019-07-08 14:25:50 -06002551 def _RunExtractCmd(self, entry_name, decomp=True):
2552 """Extract an entry from an image
2553
2554 Args:
2555 entry_name: Entry name to extract
2556 decomp: True to decompress the data if compressed, False to leave
2557 it in its raw uncompressed format
2558
2559 Returns:
2560 data from entry
2561 """
2562 self._CheckLz4()
2563 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2564 image_fname = tools.GetOutputFilename('image.bin')
2565 return control.ReadEntry(image_fname, entry_name, decomp)
2566
2567 def testExtractSimple(self):
2568 """Test extracting a single file"""
2569 data = self._RunExtractCmd('u-boot')
2570 self.assertEqual(U_BOOT_DATA, data)
2571
Simon Glass980a2842019-07-08 14:25:52 -06002572 def testExtractSection(self):
2573 """Test extracting the files in a section"""
2574 data = self._RunExtractCmd('section')
2575 cbfs_data = data[:0x400]
2576 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassc5fd10a2019-10-31 07:43:03 -06002577 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass980a2842019-07-08 14:25:52 -06002578 dtb_data = data[0x400:]
2579 dtb = self._decompress(dtb_data)
2580 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2581
2582 def testExtractCompressed(self):
2583 """Test extracting compressed data"""
2584 data = self._RunExtractCmd('section/u-boot-dtb')
2585 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2586
2587 def testExtractRaw(self):
2588 """Test extracting compressed data without decompressing it"""
2589 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2590 dtb = self._decompress(data)
2591 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2592
2593 def testExtractCbfs(self):
2594 """Test extracting CBFS data"""
2595 data = self._RunExtractCmd('section/cbfs/u-boot')
2596 self.assertEqual(U_BOOT_DATA, data)
2597
2598 def testExtractCbfsCompressed(self):
2599 """Test extracting CBFS compressed data"""
2600 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2601 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2602
2603 def testExtractCbfsRaw(self):
2604 """Test extracting CBFS compressed data without decompressing it"""
2605 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Simon Glass37fdd142019-07-20 12:24:06 -06002606 dtb = tools.Decompress(data, 'lzma', with_header=False)
Simon Glass980a2842019-07-08 14:25:52 -06002607 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2608
Simon Glass4c613bf2019-07-08 14:25:50 -06002609 def testExtractBadEntry(self):
2610 """Test extracting a bad section path"""
2611 with self.assertRaises(ValueError) as e:
2612 self._RunExtractCmd('section/does-not-exist')
2613 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2614 str(e.exception))
2615
2616 def testExtractMissingFile(self):
2617 """Test extracting file that does not exist"""
2618 with self.assertRaises(IOError) as e:
2619 control.ReadEntry('missing-file', 'name')
2620
2621 def testExtractBadFile(self):
2622 """Test extracting an invalid file"""
2623 fname = os.path.join(self._indir, 'badfile')
2624 tools.WriteFile(fname, b'')
2625 with self.assertRaises(ValueError) as e:
2626 control.ReadEntry(fname, 'name')
2627
Simon Glass980a2842019-07-08 14:25:52 -06002628 def testExtractCmd(self):
2629 """Test extracting a file fron an image on the command line"""
2630 self._CheckLz4()
2631 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass980a2842019-07-08 14:25:52 -06002632 fname = os.path.join(self._indir, 'output.extact')
Simon Glassb3d6fc72019-07-20 12:24:10 -06002633 try:
2634 tmpdir, updated_fname = self._SetupImageInTmpdir()
2635 with test_util.capture_sys_output() as (stdout, stderr):
2636 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2637 '-f', fname)
2638 finally:
2639 shutil.rmtree(tmpdir)
Simon Glass980a2842019-07-08 14:25:52 -06002640 data = tools.ReadFile(fname)
2641 self.assertEqual(U_BOOT_DATA, data)
2642
2643 def testExtractOneEntry(self):
2644 """Test extracting a single entry fron an image """
2645 self._CheckLz4()
2646 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2647 image_fname = tools.GetOutputFilename('image.bin')
2648 fname = os.path.join(self._indir, 'output.extact')
2649 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
2650 data = tools.ReadFile(fname)
2651 self.assertEqual(U_BOOT_DATA, data)
2652
2653 def _CheckExtractOutput(self, decomp):
2654 """Helper to test file output with and without decompression
2655
2656 Args:
2657 decomp: True to decompress entry data, False to output it raw
2658 """
2659 def _CheckPresent(entry_path, expect_data, expect_size=None):
2660 """Check and remove expected file
2661
2662 This checks the data/size of a file and removes the file both from
2663 the outfiles set and from the output directory. Once all files are
2664 processed, both the set and directory should be empty.
2665
2666 Args:
2667 entry_path: Entry path
2668 expect_data: Data to expect in file, or None to skip check
2669 expect_size: Size of data to expect in file, or None to skip
2670 """
2671 path = os.path.join(outdir, entry_path)
2672 data = tools.ReadFile(path)
2673 os.remove(path)
2674 if expect_data:
2675 self.assertEqual(expect_data, data)
2676 elif expect_size:
2677 self.assertEqual(expect_size, len(data))
2678 outfiles.remove(path)
2679
2680 def _CheckDirPresent(name):
2681 """Remove expected directory
2682
2683 This gives an error if the directory does not exist as expected
2684
2685 Args:
2686 name: Name of directory to remove
2687 """
2688 path = os.path.join(outdir, name)
2689 os.rmdir(path)
2690
2691 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2692 image_fname = tools.GetOutputFilename('image.bin')
2693 outdir = os.path.join(self._indir, 'extract')
2694 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2695
2696 # Create a set of all file that were output (should be 9)
2697 outfiles = set()
2698 for root, dirs, files in os.walk(outdir):
2699 outfiles |= set([os.path.join(root, fname) for fname in files])
2700 self.assertEqual(9, len(outfiles))
2701 self.assertEqual(9, len(einfos))
2702
2703 image = control.images['image']
2704 entries = image.GetEntries()
2705
2706 # Check the 9 files in various ways
2707 section = entries['section']
2708 section_entries = section.GetEntries()
2709 cbfs_entries = section_entries['cbfs'].GetEntries()
2710 _CheckPresent('u-boot', U_BOOT_DATA)
2711 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
2712 dtb_len = EXTRACT_DTB_SIZE
2713 if not decomp:
2714 dtb_len = cbfs_entries['u-boot-dtb'].size
2715 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
2716 if not decomp:
2717 dtb_len = section_entries['u-boot-dtb'].size
2718 _CheckPresent('section/u-boot-dtb', None, dtb_len)
2719
2720 fdtmap = entries['fdtmap']
2721 _CheckPresent('fdtmap', fdtmap.data)
2722 hdr = entries['image-header']
2723 _CheckPresent('image-header', hdr.data)
2724
2725 _CheckPresent('section/root', section.data)
2726 cbfs = section_entries['cbfs']
2727 _CheckPresent('section/cbfs/root', cbfs.data)
2728 data = tools.ReadFile(image_fname)
2729 _CheckPresent('root', data)
2730
2731 # There should be no files left. Remove all the directories to check.
2732 # If there are any files/dirs remaining, one of these checks will fail.
2733 self.assertEqual(0, len(outfiles))
2734 _CheckDirPresent('section/cbfs')
2735 _CheckDirPresent('section')
2736 _CheckDirPresent('')
2737 self.assertFalse(os.path.exists(outdir))
2738
2739 def testExtractAllEntries(self):
2740 """Test extracting all entries"""
2741 self._CheckLz4()
2742 self._CheckExtractOutput(decomp=True)
2743
2744 def testExtractAllEntriesRaw(self):
2745 """Test extracting all entries without decompressing them"""
2746 self._CheckLz4()
2747 self._CheckExtractOutput(decomp=False)
2748
2749 def testExtractSelectedEntries(self):
2750 """Test extracting some entries"""
2751 self._CheckLz4()
2752 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2753 image_fname = tools.GetOutputFilename('image.bin')
2754 outdir = os.path.join(self._indir, 'extract')
2755 einfos = control.ExtractEntries(image_fname, None, outdir,
2756 ['*cb*', '*head*'])
2757
2758 # File output is tested by testExtractAllEntries(), so just check that
2759 # the expected entries are selected
2760 names = [einfo.name for einfo in einfos]
2761 self.assertEqual(names,
2762 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2763
2764 def testExtractNoEntryPaths(self):
2765 """Test extracting some entries"""
2766 self._CheckLz4()
2767 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2768 image_fname = tools.GetOutputFilename('image.bin')
2769 with self.assertRaises(ValueError) as e:
2770 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassa772d3f2019-07-20 12:24:14 -06002771 self.assertIn('Must specify an entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06002772 str(e.exception))
2773
2774 def testExtractTooManyEntryPaths(self):
2775 """Test extracting some entries"""
2776 self._CheckLz4()
2777 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2778 image_fname = tools.GetOutputFilename('image.bin')
2779 with self.assertRaises(ValueError) as e:
2780 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassa772d3f2019-07-20 12:24:14 -06002781 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06002782 str(e.exception))
2783
Simon Glass52d06212019-07-08 14:25:53 -06002784 def testPackAlignSection(self):
2785 """Test that sections can have alignment"""
2786 self._DoReadFile('131_pack_align_section.dts')
2787
2788 self.assertIn('image', control.images)
2789 image = control.images['image']
2790 entries = image.GetEntries()
2791 self.assertEqual(3, len(entries))
2792
2793 # First u-boot
2794 self.assertIn('u-boot', entries)
2795 entry = entries['u-boot']
2796 self.assertEqual(0, entry.offset)
2797 self.assertEqual(0, entry.image_pos)
2798 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2799 self.assertEqual(len(U_BOOT_DATA), entry.size)
2800
2801 # Section0
2802 self.assertIn('section0', entries)
2803 section0 = entries['section0']
2804 self.assertEqual(0x10, section0.offset)
2805 self.assertEqual(0x10, section0.image_pos)
2806 self.assertEqual(len(U_BOOT_DATA), section0.size)
2807
2808 # Second u-boot
2809 section_entries = section0.GetEntries()
2810 self.assertIn('u-boot', section_entries)
2811 entry = section_entries['u-boot']
2812 self.assertEqual(0, entry.offset)
2813 self.assertEqual(0x10, entry.image_pos)
2814 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2815 self.assertEqual(len(U_BOOT_DATA), entry.size)
2816
2817 # Section1
2818 self.assertIn('section1', entries)
2819 section1 = entries['section1']
2820 self.assertEqual(0x14, section1.offset)
2821 self.assertEqual(0x14, section1.image_pos)
2822 self.assertEqual(0x20, section1.size)
2823
2824 # Second u-boot
2825 section_entries = section1.GetEntries()
2826 self.assertIn('u-boot', section_entries)
2827 entry = section_entries['u-boot']
2828 self.assertEqual(0, entry.offset)
2829 self.assertEqual(0x14, entry.image_pos)
2830 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2831 self.assertEqual(len(U_BOOT_DATA), entry.size)
2832
2833 # Section2
2834 self.assertIn('section2', section_entries)
2835 section2 = section_entries['section2']
2836 self.assertEqual(0x4, section2.offset)
2837 self.assertEqual(0x18, section2.image_pos)
2838 self.assertEqual(4, section2.size)
2839
2840 # Third u-boot
2841 section_entries = section2.GetEntries()
2842 self.assertIn('u-boot', section_entries)
2843 entry = section_entries['u-boot']
2844 self.assertEqual(0, entry.offset)
2845 self.assertEqual(0x18, entry.image_pos)
2846 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2847 self.assertEqual(len(U_BOOT_DATA), entry.size)
2848
Simon Glassf8a54bc2019-07-20 12:23:56 -06002849 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
2850 dts='132_replace.dts'):
Simon Glass072959a2019-07-20 12:23:50 -06002851 """Replace an entry in an image
2852
2853 This writes the entry data to update it, then opens the updated file and
2854 returns the value that it now finds there.
2855
2856 Args:
2857 entry_name: Entry name to replace
2858 data: Data to replace it with
2859 decomp: True to compress the data if needed, False if data is
2860 already compressed so should be used as is
Simon Glassf8a54bc2019-07-20 12:23:56 -06002861 allow_resize: True to allow entries to change size, False to raise
2862 an exception
Simon Glass072959a2019-07-20 12:23:50 -06002863
2864 Returns:
2865 Tuple:
2866 data from entry
2867 data from fdtmap (excluding header)
Simon Glassf8a54bc2019-07-20 12:23:56 -06002868 Image object that was modified
Simon Glass072959a2019-07-20 12:23:50 -06002869 """
Simon Glassf8a54bc2019-07-20 12:23:56 -06002870 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass072959a2019-07-20 12:23:50 -06002871 update_dtb=True)[1]
2872
2873 self.assertIn('image', control.images)
2874 image = control.images['image']
2875 entries = image.GetEntries()
2876 orig_dtb_data = entries['u-boot-dtb'].data
2877 orig_fdtmap_data = entries['fdtmap'].data
2878
2879 image_fname = tools.GetOutputFilename('image.bin')
2880 updated_fname = tools.GetOutputFilename('image-updated.bin')
2881 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
Simon Glassf8a54bc2019-07-20 12:23:56 -06002882 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
2883 allow_resize)
Simon Glass072959a2019-07-20 12:23:50 -06002884 data = control.ReadEntry(updated_fname, entry_name, decomp)
2885
Simon Glassf8a54bc2019-07-20 12:23:56 -06002886 # The DT data should not change unless resized:
2887 if not allow_resize:
2888 new_dtb_data = entries['u-boot-dtb'].data
2889 self.assertEqual(new_dtb_data, orig_dtb_data)
2890 new_fdtmap_data = entries['fdtmap'].data
2891 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass072959a2019-07-20 12:23:50 -06002892
Simon Glassf8a54bc2019-07-20 12:23:56 -06002893 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass072959a2019-07-20 12:23:50 -06002894
2895 def testReplaceSimple(self):
2896 """Test replacing a single file"""
2897 expected = b'x' * len(U_BOOT_DATA)
Simon Glassf8a54bc2019-07-20 12:23:56 -06002898 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
2899 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06002900 self.assertEqual(expected, data)
2901
2902 # Test that the state looks right. There should be an FDT for the fdtmap
2903 # that we jsut read back in, and it should match what we find in the
2904 # 'control' tables. Checking for an FDT that does not exist should
2905 # return None.
2906 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glassf8a54bc2019-07-20 12:23:56 -06002907 self.assertIsNotNone(path)
Simon Glass072959a2019-07-20 12:23:50 -06002908 self.assertEqual(expected_fdtmap, fdtmap)
2909
2910 dtb = state.GetFdtForEtype('fdtmap')
2911 self.assertEqual(dtb.GetContents(), fdtmap)
2912
2913 missing_path, missing_fdtmap = state.GetFdtContents('missing')
2914 self.assertIsNone(missing_path)
2915 self.assertIsNone(missing_fdtmap)
2916
2917 missing_dtb = state.GetFdtForEtype('missing')
2918 self.assertIsNone(missing_dtb)
2919
2920 self.assertEqual('/binman', state.fdt_path_prefix)
2921
2922 def testReplaceResizeFail(self):
2923 """Test replacing a file by something larger"""
2924 expected = U_BOOT_DATA + b'x'
2925 with self.assertRaises(ValueError) as e:
Simon Glassf8a54bc2019-07-20 12:23:56 -06002926 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
2927 dts='139_replace_repack.dts')
Simon Glass072959a2019-07-20 12:23:50 -06002928 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
2929 str(e.exception))
2930
2931 def testReplaceMulti(self):
2932 """Test replacing entry data where multiple images are generated"""
2933 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
2934 update_dtb=True)[0]
2935 expected = b'x' * len(U_BOOT_DATA)
2936 updated_fname = tools.GetOutputFilename('image-updated.bin')
2937 tools.WriteFile(updated_fname, data)
2938 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06002939 control.WriteEntry(updated_fname, entry_name, expected,
2940 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06002941 data = control.ReadEntry(updated_fname, entry_name)
2942 self.assertEqual(expected, data)
2943
2944 # Check the state looks right.
2945 self.assertEqual('/binman/image', state.fdt_path_prefix)
2946
2947 # Now check we can write the first image
2948 image_fname = tools.GetOutputFilename('first-image.bin')
2949 updated_fname = tools.GetOutputFilename('first-updated.bin')
2950 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
2951 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06002952 control.WriteEntry(updated_fname, entry_name, expected,
2953 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06002954 data = control.ReadEntry(updated_fname, entry_name)
2955 self.assertEqual(expected, data)
2956
2957 # Check the state looks right.
2958 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass39dd2152019-07-08 14:25:47 -06002959
Simon Glassfb30e292019-07-20 12:23:51 -06002960 def testUpdateFdtAllRepack(self):
2961 """Test that all device trees are updated with offset/size info"""
2962 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
2963 SECTION_SIZE = 0x300
2964 DTB_SIZE = 602
2965 FDTMAP_SIZE = 608
2966 base_expected = {
2967 'offset': 0,
2968 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
2969 'image-pos': 0,
2970 'section:offset': 0,
2971 'section:size': SECTION_SIZE,
2972 'section:image-pos': 0,
2973 'section/u-boot-dtb:offset': 4,
2974 'section/u-boot-dtb:size': 636,
2975 'section/u-boot-dtb:image-pos': 4,
2976 'u-boot-spl-dtb:offset': SECTION_SIZE,
2977 'u-boot-spl-dtb:size': DTB_SIZE,
2978 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
2979 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
2980 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
2981 'u-boot-tpl-dtb:size': DTB_SIZE,
2982 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
2983 'fdtmap:size': FDTMAP_SIZE,
2984 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
2985 }
2986 main_expected = {
2987 'section:orig-size': SECTION_SIZE,
2988 'section/u-boot-dtb:orig-offset': 4,
2989 }
2990
2991 # We expect three device-tree files in the output, with the first one
2992 # within a fixed-size section.
2993 # Read them in sequence. We look for an 'spl' property in the SPL tree,
2994 # and 'tpl' in the TPL tree, to make sure they are distinct from the
2995 # main U-Boot tree. All three should have the same positions and offset
2996 # except that the main tree should include the main_expected properties
2997 start = 4
2998 for item in ['', 'spl', 'tpl', None]:
2999 if item is None:
3000 start += 16 # Move past fdtmap header
3001 dtb = fdt.Fdt.FromData(data[start:])
3002 dtb.Scan()
3003 props = self._GetPropTree(dtb,
3004 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3005 prefix='/' if item is None else '/binman/')
3006 expected = dict(base_expected)
3007 if item:
3008 expected[item] = 0
3009 else:
3010 # Main DTB and fdtdec should include the 'orig-' properties
3011 expected.update(main_expected)
3012 # Helpful for debugging:
3013 #for prop in sorted(props):
3014 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3015 self.assertEqual(expected, props)
3016 if item == '':
3017 start = SECTION_SIZE
3018 else:
3019 start += dtb._fdt_obj.totalsize()
3020
Simon Glass11453762019-07-20 12:23:55 -06003021 def testFdtmapHeaderMiddle(self):
3022 """Test an FDT map in the middle of an image when it should be at end"""
3023 with self.assertRaises(ValueError) as e:
3024 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3025 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3026 str(e.exception))
3027
3028 def testFdtmapHeaderStartBad(self):
3029 """Test an FDT map in middle of an image when it should be at start"""
3030 with self.assertRaises(ValueError) as e:
3031 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3032 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3033 str(e.exception))
3034
3035 def testFdtmapHeaderEndBad(self):
3036 """Test an FDT map at the start of an image when it should be at end"""
3037 with self.assertRaises(ValueError) as e:
3038 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3039 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3040 str(e.exception))
3041
3042 def testFdtmapHeaderNoSize(self):
3043 """Test an image header at the end of an image with undefined size"""
3044 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3045
Simon Glassf8a54bc2019-07-20 12:23:56 -06003046 def testReplaceResize(self):
3047 """Test replacing a single file in an entry with a larger file"""
3048 expected = U_BOOT_DATA + b'x'
3049 data, _, image = self._RunReplaceCmd('u-boot', expected,
3050 dts='139_replace_repack.dts')
3051 self.assertEqual(expected, data)
3052
3053 entries = image.GetEntries()
3054 dtb_data = entries['u-boot-dtb'].data
3055 dtb = fdt.Fdt.FromData(dtb_data)
3056 dtb.Scan()
3057
3058 # The u-boot section should now be larger in the dtb
3059 node = dtb.GetNode('/binman/u-boot')
3060 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3061
3062 # Same for the fdtmap
3063 fdata = entries['fdtmap'].data
3064 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3065 fdtb.Scan()
3066 fnode = fdtb.GetNode('/u-boot')
3067 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3068
3069 def testReplaceResizeNoRepack(self):
3070 """Test replacing an entry with a larger file when not allowed"""
3071 expected = U_BOOT_DATA + b'x'
3072 with self.assertRaises(ValueError) as e:
3073 self._RunReplaceCmd('u-boot', expected)
3074 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3075 str(e.exception))
3076
Simon Glass9d8ee322019-07-20 12:23:58 -06003077 def testEntryShrink(self):
3078 """Test contracting an entry after it is packed"""
3079 try:
3080 state.SetAllowEntryContraction(True)
3081 data = self._DoReadFileDtb('140_entry_shrink.dts',
3082 update_dtb=True)[0]
3083 finally:
3084 state.SetAllowEntryContraction(False)
3085 self.assertEqual(b'a', data[:1])
3086 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3087 self.assertEqual(b'a', data[-1:])
3088
3089 def testEntryShrinkFail(self):
3090 """Test not being allowed to contract an entry after it is packed"""
3091 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3092
3093 # In this case there is a spare byte at the end of the data. The size of
3094 # the contents is only 1 byte but we still have the size before it
3095 # shrunk.
3096 self.assertEqual(b'a\0', data[:2])
3097 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3098 self.assertEqual(b'a\0', data[-2:])
3099
Simon Glass70e32982019-07-20 12:24:01 -06003100 def testDescriptorOffset(self):
3101 """Test that the Intel descriptor is always placed at at the start"""
3102 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3103 image = control.images['image']
3104 entries = image.GetEntries()
3105 desc = entries['intel-descriptor']
3106 self.assertEqual(0xff800000, desc.offset);
3107 self.assertEqual(0xff800000, desc.image_pos);
3108
Simon Glass37fdd142019-07-20 12:24:06 -06003109 def testReplaceCbfs(self):
3110 """Test replacing a single file in CBFS without changing the size"""
3111 self._CheckLz4()
3112 expected = b'x' * len(U_BOOT_DATA)
3113 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3114 updated_fname = tools.GetOutputFilename('image-updated.bin')
3115 tools.WriteFile(updated_fname, data)
3116 entry_name = 'section/cbfs/u-boot'
3117 control.WriteEntry(updated_fname, entry_name, expected,
3118 allow_resize=True)
3119 data = control.ReadEntry(updated_fname, entry_name)
3120 self.assertEqual(expected, data)
3121
3122 def testReplaceResizeCbfs(self):
3123 """Test replacing a single file in CBFS with one of a different size"""
3124 self._CheckLz4()
3125 expected = U_BOOT_DATA + b'x'
3126 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3127 updated_fname = tools.GetOutputFilename('image-updated.bin')
3128 tools.WriteFile(updated_fname, data)
3129 entry_name = 'section/cbfs/u-boot'
3130 control.WriteEntry(updated_fname, entry_name, expected,
3131 allow_resize=True)
3132 data = control.ReadEntry(updated_fname, entry_name)
3133 self.assertEqual(expected, data)
3134
Simon Glass30033c22019-07-20 12:24:15 -06003135 def _SetupForReplace(self):
3136 """Set up some files to use to replace entries
3137
3138 This generates an image, copies it to a new file, extracts all the files
3139 in it and updates some of them
3140
3141 Returns:
3142 List
3143 Image filename
3144 Output directory
3145 Expected values for updated entries, each a string
3146 """
3147 data = self._DoReadFileRealDtb('143_replace_all.dts')
3148
3149 updated_fname = tools.GetOutputFilename('image-updated.bin')
3150 tools.WriteFile(updated_fname, data)
3151
3152 outdir = os.path.join(self._indir, 'extract')
3153 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3154
3155 expected1 = b'x' + U_BOOT_DATA + b'y'
3156 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3157 tools.WriteFile(u_boot_fname1, expected1)
3158
3159 expected2 = b'a' + U_BOOT_DATA + b'b'
3160 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
3161 tools.WriteFile(u_boot_fname2, expected2)
3162
3163 expected_text = b'not the same text'
3164 text_fname = os.path.join(outdir, 'text')
3165 tools.WriteFile(text_fname, expected_text)
3166
3167 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3168 dtb = fdt.FdtScan(dtb_fname)
3169 node = dtb.GetNode('/binman/text')
3170 node.AddString('my-property', 'the value')
3171 dtb.Sync(auto_resize=True)
3172 dtb.Flush()
3173
3174 return updated_fname, outdir, expected1, expected2, expected_text
3175
3176 def _CheckReplaceMultiple(self, entry_paths):
3177 """Handle replacing the contents of multiple entries
3178
3179 Args:
3180 entry_paths: List of entry paths to replace
3181
3182 Returns:
3183 List
3184 Dict of entries in the image:
3185 key: Entry name
3186 Value: Entry object
3187 Expected values for updated entries, each a string
3188 """
3189 updated_fname, outdir, expected1, expected2, expected_text = (
3190 self._SetupForReplace())
3191 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3192
3193 image = Image.FromFile(updated_fname)
3194 image.LoadData()
3195 return image.GetEntries(), expected1, expected2, expected_text
3196
3197 def testReplaceAll(self):
3198 """Test replacing the contents of all entries"""
3199 entries, expected1, expected2, expected_text = (
3200 self._CheckReplaceMultiple([]))
3201 data = entries['u-boot'].data
3202 self.assertEqual(expected1, data)
3203
3204 data = entries['u-boot2'].data
3205 self.assertEqual(expected2, data)
3206
3207 data = entries['text'].data
3208 self.assertEqual(expected_text, data)
3209
3210 # Check that the device tree is updated
3211 data = entries['u-boot-dtb'].data
3212 dtb = fdt.Fdt.FromData(data)
3213 dtb.Scan()
3214 node = dtb.GetNode('/binman/text')
3215 self.assertEqual('the value', node.props['my-property'].value)
3216
3217 def testReplaceSome(self):
3218 """Test replacing the contents of a few entries"""
3219 entries, expected1, expected2, expected_text = (
3220 self._CheckReplaceMultiple(['u-boot2', 'text']))
3221
3222 # This one should not change
3223 data = entries['u-boot'].data
3224 self.assertEqual(U_BOOT_DATA, data)
3225
3226 data = entries['u-boot2'].data
3227 self.assertEqual(expected2, data)
3228
3229 data = entries['text'].data
3230 self.assertEqual(expected_text, data)
3231
3232 def testReplaceCmd(self):
3233 """Test replacing a file fron an image on the command line"""
3234 self._DoReadFileRealDtb('143_replace_all.dts')
3235
3236 try:
3237 tmpdir, updated_fname = self._SetupImageInTmpdir()
3238
3239 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3240 expected = b'x' * len(U_BOOT_DATA)
3241 tools.WriteFile(fname, expected)
3242
3243 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
3244 data = tools.ReadFile(updated_fname)
3245 self.assertEqual(expected, data[:len(expected)])
3246 map_fname = os.path.join(tmpdir, 'image-updated.map')
3247 self.assertFalse(os.path.exists(map_fname))
3248 finally:
3249 shutil.rmtree(tmpdir)
3250
3251 def testReplaceCmdSome(self):
3252 """Test replacing some files fron an image on the command line"""
3253 updated_fname, outdir, expected1, expected2, expected_text = (
3254 self._SetupForReplace())
3255
3256 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3257 'u-boot2', 'text')
3258
3259 tools.PrepareOutputDir(None)
3260 image = Image.FromFile(updated_fname)
3261 image.LoadData()
3262 entries = image.GetEntries()
3263
3264 # This one should not change
3265 data = entries['u-boot'].data
3266 self.assertEqual(U_BOOT_DATA, data)
3267
3268 data = entries['u-boot2'].data
3269 self.assertEqual(expected2, data)
3270
3271 data = entries['text'].data
3272 self.assertEqual(expected_text, data)
3273
3274 def testReplaceMissing(self):
3275 """Test replacing entries where the file is missing"""
3276 updated_fname, outdir, expected1, expected2, expected_text = (
3277 self._SetupForReplace())
3278
3279 # Remove one of the files, to generate a warning
3280 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3281 os.remove(u_boot_fname1)
3282
3283 with test_util.capture_sys_output() as (stdout, stderr):
3284 control.ReplaceEntries(updated_fname, None, outdir, [])
3285 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass6e02f7c2020-07-09 18:39:39 -06003286 stderr.getvalue())
Simon Glass30033c22019-07-20 12:24:15 -06003287
3288 def testReplaceCmdMap(self):
3289 """Test replacing a file fron an image on the command line"""
3290 self._DoReadFileRealDtb('143_replace_all.dts')
3291
3292 try:
3293 tmpdir, updated_fname = self._SetupImageInTmpdir()
3294
3295 fname = os.path.join(self._indir, 'update-u-boot.bin')
3296 expected = b'x' * len(U_BOOT_DATA)
3297 tools.WriteFile(fname, expected)
3298
3299 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3300 '-f', fname, '-m')
3301 map_fname = os.path.join(tmpdir, 'image-updated.map')
3302 self.assertTrue(os.path.exists(map_fname))
3303 finally:
3304 shutil.rmtree(tmpdir)
3305
3306 def testReplaceNoEntryPaths(self):
3307 """Test replacing an entry without an entry path"""
3308 self._DoReadFileRealDtb('143_replace_all.dts')
3309 image_fname = tools.GetOutputFilename('image.bin')
3310 with self.assertRaises(ValueError) as e:
3311 control.ReplaceEntries(image_fname, 'fname', None, [])
3312 self.assertIn('Must specify an entry path to read with -f',
3313 str(e.exception))
3314
3315 def testReplaceTooManyEntryPaths(self):
3316 """Test extracting some entries"""
3317 self._DoReadFileRealDtb('143_replace_all.dts')
3318 image_fname = tools.GetOutputFilename('image.bin')
3319 with self.assertRaises(ValueError) as e:
3320 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3321 self.assertIn('Must specify exactly one entry path to write with -f',
3322 str(e.exception))
3323
Simon Glass0b074d62019-08-24 07:22:48 -06003324 def testPackReset16(self):
3325 """Test that an image with an x86 reset16 region can be created"""
3326 data = self._DoReadFile('144_x86_reset16.dts')
3327 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3328
3329 def testPackReset16Spl(self):
3330 """Test that an image with an x86 reset16-spl region can be created"""
3331 data = self._DoReadFile('145_x86_reset16_spl.dts')
3332 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3333
3334 def testPackReset16Tpl(self):
3335 """Test that an image with an x86 reset16-tpl region can be created"""
3336 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3337 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3338
Simon Glass232f90c2019-08-24 07:22:50 -06003339 def testPackIntelFit(self):
3340 """Test that an image with an Intel FIT and pointer can be created"""
3341 data = self._DoReadFile('147_intel_fit.dts')
3342 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3343 fit = data[16:32];
3344 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3345 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3346
3347 image = control.images['image']
3348 entries = image.GetEntries()
3349 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3350 self.assertEqual(expected_ptr, ptr)
3351
3352 def testPackIntelFitMissing(self):
3353 """Test detection of a FIT pointer with not FIT region"""
3354 with self.assertRaises(ValueError) as e:
3355 self._DoReadFile('148_intel_fit_missing.dts')
3356 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3357 str(e.exception))
3358
Simon Glass72555fa2019-11-06 17:22:44 -07003359 def _CheckSymbolsTplSection(self, dts, expected_vals):
3360 data = self._DoReadFile(dts)
3361 sym_values = struct.pack('<LQLL', *expected_vals)
Simon Glass3eb5b202019-08-24 07:23:00 -06003362 upto1 = 4 + len(U_BOOT_SPL_DATA)
Simon Glass3f8ff012019-08-24 07:23:05 -06003363 expected1 = tools.GetBytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[20:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003364 self.assertEqual(expected1, data[:upto1])
3365
3366 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Simon Glass3f8ff012019-08-24 07:23:05 -06003367 expected2 = tools.GetBytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[20:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003368 self.assertEqual(expected2, data[upto1:upto2])
3369
Simon Glass4e353e22019-08-24 07:23:04 -06003370 upto3 = 0x34 + len(U_BOOT_DATA)
3371 expected3 = tools.GetBytes(0xff, 1) + U_BOOT_DATA
Simon Glass3eb5b202019-08-24 07:23:00 -06003372 self.assertEqual(expected3, data[upto2:upto3])
3373
Simon Glass3f8ff012019-08-24 07:23:05 -06003374 expected4 = sym_values + U_BOOT_TPL_DATA[20:]
Simon Glass72555fa2019-11-06 17:22:44 -07003375 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3376
3377 def testSymbolsTplSection(self):
3378 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3379 self._SetupSplElf('u_boot_binman_syms')
3380 self._SetupTplElf('u_boot_binman_syms')
3381 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
3382 [0x04, 0x1c, 0x10 + 0x34, 0x04])
3383
3384 def testSymbolsTplSectionX86(self):
3385 """Test binman can assign symbols in a section with end-at-4gb"""
3386 self._SetupSplElf('u_boot_binman_syms_x86')
3387 self._SetupTplElf('u_boot_binman_syms_x86')
3388 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
3389 [0xffffff04, 0xffffff1c, 0xffffff34,
3390 0x04])
Simon Glass3eb5b202019-08-24 07:23:00 -06003391
Simon Glass98c59572019-08-24 07:23:03 -06003392 def testPackX86RomIfwiSectiom(self):
3393 """Test that a section can be placed in an IFWI region"""
3394 self._SetupIfwi('fitimage.bin')
3395 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3396 self._CheckIfwi(data)
3397
Simon Glassba7985d2019-08-24 07:23:07 -06003398 def testPackFspM(self):
3399 """Test that an image with a FSP memory-init binary can be created"""
3400 data = self._DoReadFile('152_intel_fsp_m.dts')
3401 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3402
Simon Glass4d9086d2019-10-20 21:31:35 -06003403 def testPackFspS(self):
3404 """Test that an image with a FSP silicon-init binary can be created"""
3405 data = self._DoReadFile('153_intel_fsp_s.dts')
3406 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassba7985d2019-08-24 07:23:07 -06003407
Simon Glass9ea87b22019-10-20 21:31:36 -06003408 def testPackFspT(self):
3409 """Test that an image with a FSP temp-ram-init binary can be created"""
3410 data = self._DoReadFile('154_intel_fsp_t.dts')
3411 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3412
Simon Glass48f3aad2020-07-09 18:39:31 -06003413 def testMkimage(self):
3414 """Test using mkimage to build an image"""
3415 data = self._DoReadFile('156_mkimage.dts')
3416
3417 # Just check that the data appears in the file somewhere
3418 self.assertIn(U_BOOT_SPL_DATA, data)
3419
Simon Glass5e560182020-07-09 18:39:36 -06003420 def testExtblob(self):
3421 """Test an image with an external blob"""
3422 data = self._DoReadFile('157_blob_ext.dts')
3423 self.assertEqual(REFCODE_DATA, data)
3424
3425 def testExtblobMissing(self):
3426 """Test an image with a missing external blob"""
3427 with self.assertRaises(ValueError) as e:
3428 self._DoReadFile('158_blob_ext_missing.dts')
3429 self.assertIn("Filename 'missing-file' not found in input path",
3430 str(e.exception))
3431
Simon Glass5d94cc62020-07-09 18:39:38 -06003432 def testExtblobMissingOk(self):
3433 """Test an image with an missing external blob that is allowed"""
Simon Glassa003cd32020-07-09 18:39:40 -06003434 with test_util.capture_sys_output() as (stdout, stderr):
3435 self._DoTestFile('158_blob_ext_missing.dts', allow_missing=True)
3436 err = stderr.getvalue()
3437 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
3438
3439 def testExtblobMissingOkSect(self):
3440 """Test an image with an missing external blob that is allowed"""
3441 with test_util.capture_sys_output() as (stdout, stderr):
3442 self._DoTestFile('159_blob_ext_missing_sect.dts',
3443 allow_missing=True)
3444 err = stderr.getvalue()
3445 self.assertRegex(err, "Image 'main-section'.*missing.*: "
3446 "blob-ext blob-ext2")
Simon Glass5d94cc62020-07-09 18:39:38 -06003447
Simon Glasse88cef92020-07-09 18:39:41 -06003448 def testPackX86RomMeMissingDesc(self):
3449 """Test that an missing Intel descriptor entry is allowed"""
Simon Glasse88cef92020-07-09 18:39:41 -06003450 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass14c596c2020-07-25 15:11:19 -06003451 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glasse88cef92020-07-09 18:39:41 -06003452 err = stderr.getvalue()
3453 self.assertRegex(err,
3454 "Image 'main-section'.*missing.*: intel-descriptor")
3455
3456 def testPackX86RomMissingIfwi(self):
3457 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3458 self._SetupIfwi('fitimage.bin')
3459 pathname = os.path.join(self._indir, 'fitimage.bin')
3460 os.remove(pathname)
3461 with test_util.capture_sys_output() as (stdout, stderr):
3462 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3463 err = stderr.getvalue()
3464 self.assertRegex(err, "Image 'main-section'.*missing.*: intel-ifwi")
3465
Simon Glassd70829a2020-07-09 18:39:42 -06003466 def testPackOverlap(self):
3467 """Test that zero-size overlapping regions are ignored"""
3468 self._DoTestFile('160_pack_overlap_zero.dts')
3469
Simon Glass45d556d2020-07-09 18:39:45 -06003470 def testSimpleFit(self):
3471 """Test an image with a FIT inside"""
3472 data = self._DoReadFile('161_fit.dts')
3473 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3474 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3475 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3476
3477 # The data should be inside the FIT
3478 dtb = fdt.Fdt.FromData(fit_data)
3479 dtb.Scan()
3480 fnode = dtb.GetNode('/images/kernel')
3481 self.assertIn('data', fnode.props)
3482
3483 fname = os.path.join(self._indir, 'fit_data.fit')
3484 tools.WriteFile(fname, fit_data)
3485 out = tools.Run('dumpimage', '-l', fname)
3486
3487 # Check a few features to make sure the plumbing works. We don't need
3488 # to test the operation of mkimage or dumpimage here. First convert the
3489 # output into a dict where the keys are the fields printed by dumpimage
3490 # and the values are a list of values for each field
3491 lines = out.splitlines()
3492
3493 # Converts "Compression: gzip compressed" into two groups:
3494 # 'Compression' and 'gzip compressed'
3495 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3496 vals = collections.defaultdict(list)
3497 for line in lines:
3498 mat = re_line.match(line)
3499 vals[mat.group(1)].append(mat.group(2))
3500
3501 self.assertEquals('FIT description: test-desc', lines[0])
3502 self.assertIn('Created:', lines[1])
3503 self.assertIn('Image 0 (kernel)', vals)
3504 self.assertIn('Hash value', vals)
3505 data_sizes = vals.get('Data Size')
3506 self.assertIsNotNone(data_sizes)
3507 self.assertEqual(2, len(data_sizes))
3508 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
3509 self.assertEqual(len(U_BOOT_DATA), int(data_sizes[0].split()[0]))
3510 self.assertEqual(len(U_BOOT_SPL_DTB_DATA), int(data_sizes[1].split()[0]))
3511
3512 def testFitExternal(self):
Simon Glass31ee50f2020-09-01 05:13:55 -06003513 """Test an image with an FIT with external images"""
Simon Glass45d556d2020-07-09 18:39:45 -06003514 data = self._DoReadFile('162_fit_external.dts')
3515 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3516
3517 # The data should be outside the FIT
3518 dtb = fdt.Fdt.FromData(fit_data)
3519 dtb.Scan()
3520 fnode = dtb.GetNode('/images/kernel')
3521 self.assertNotIn('data', fnode.props)
Simon Glassfb30e292019-07-20 12:23:51 -06003522
Alper Nebi Yasak6aae2392020-08-31 12:58:18 +03003523 def testSectionIgnoreHashSignature(self):
3524 """Test that sections ignore hash, signature nodes for its data"""
3525 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
3526 expected = (U_BOOT_DATA + U_BOOT_DATA)
3527 self.assertEqual(expected, data)
3528
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03003529 def testPadInSections(self):
3530 """Test pad-before, pad-after for entries in sections"""
3531 data = self._DoReadFile('166_pad_in_sections.dts')
3532 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
3533 U_BOOT_DATA + tools.GetBytes(ord('!'), 6) +
3534 U_BOOT_DATA)
3535 self.assertEqual(expected, data)
3536
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03003537 def testFitImageSubentryAlignment(self):
3538 """Test relative alignability of FIT image subentries"""
3539 entry_args = {
3540 'test-id': TEXT_DATA,
3541 }
3542 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
3543 entry_args=entry_args)
3544 dtb = fdt.Fdt.FromData(data)
3545 dtb.Scan()
3546
3547 node = dtb.GetNode('/images/kernel')
3548 data = dtb.GetProps(node)["data"].bytes
3549 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
3550 expected = (tools.GetBytes(0, 0x20) + U_BOOT_SPL_DATA +
3551 tools.GetBytes(0, align_pad) + U_BOOT_DATA)
3552 self.assertEqual(expected, data)
3553
3554 node = dtb.GetNode('/images/fdt-1')
3555 data = dtb.GetProps(node)["data"].bytes
3556 expected = (U_BOOT_SPL_DTB_DATA + tools.GetBytes(0, 20) +
3557 tools.ToBytes(TEXT_DATA) + tools.GetBytes(0, 30) +
3558 U_BOOT_DTB_DATA)
3559 self.assertEqual(expected, data)
3560
3561 def testFitExtblobMissingOk(self):
3562 """Test a FIT with a missing external blob that is allowed"""
3563 with test_util.capture_sys_output() as (stdout, stderr):
3564 self._DoTestFile('168_fit_missing_blob.dts',
3565 allow_missing=True)
3566 err = stderr.getvalue()
Simon Glassa820af72020-09-06 10:39:09 -06003567 self.assertRegex(err, "Image 'main-section'.*missing.*: atf-bl31")
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03003568
Simon Glass21db0ff2020-09-01 05:13:54 -06003569 def testBlobNamedByArgMissing(self):
3570 """Test handling of a missing entry arg"""
3571 with self.assertRaises(ValueError) as e:
3572 self._DoReadFile('068_blob_named_by_arg.dts')
3573 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
3574 str(e.exception))
3575
Simon Glass559c4de2020-09-01 05:13:58 -06003576 def testPackBl31(self):
3577 """Test that an image with an ATF BL31 binary can be created"""
3578 data = self._DoReadFile('169_atf_bl31.dts')
3579 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
3580
Simon Glassa435cd12020-09-01 05:13:59 -06003581 def testFitFdt(self):
3582 """Test an image with an FIT with multiple FDT images"""
3583 def _CheckFdt(seq, expected_data):
3584 """Check the FDT nodes
3585
3586 Args:
3587 seq: Sequence number to check (0 or 1)
3588 expected_data: Expected contents of 'data' property
3589 """
3590 name = 'fdt-%d' % seq
3591 fnode = dtb.GetNode('/images/%s' % name)
3592 self.assertIsNotNone(fnode)
3593 self.assertEqual({'description','type', 'compression', 'data'},
3594 set(fnode.props.keys()))
3595 self.assertEqual(expected_data, fnode.props['data'].bytes)
3596 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
3597 fnode.props['description'].value)
3598
3599 def _CheckConfig(seq, expected_data):
3600 """Check the configuration nodes
3601
3602 Args:
3603 seq: Sequence number to check (0 or 1)
3604 expected_data: Expected contents of 'data' property
3605 """
3606 cnode = dtb.GetNode('/configurations')
3607 self.assertIn('default', cnode.props)
Simon Glass1032acc2020-09-06 10:39:08 -06003608 self.assertEqual('config-2', cnode.props['default'].value)
Simon Glassa435cd12020-09-01 05:13:59 -06003609
3610 name = 'config-%d' % seq
3611 fnode = dtb.GetNode('/configurations/%s' % name)
3612 self.assertIsNotNone(fnode)
3613 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
3614 set(fnode.props.keys()))
3615 self.assertEqual('conf-test-fdt%d.dtb' % seq,
3616 fnode.props['description'].value)
3617 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
3618
3619 entry_args = {
3620 'of-list': 'test-fdt1 test-fdt2',
Simon Glass1032acc2020-09-06 10:39:08 -06003621 'default-dt': 'test-fdt2',
Simon Glassa435cd12020-09-01 05:13:59 -06003622 }
3623 data = self._DoReadFileDtb(
Simon Glass1032acc2020-09-06 10:39:08 -06003624 '172_fit_fdt.dts',
Simon Glassa435cd12020-09-01 05:13:59 -06003625 entry_args=entry_args,
3626 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3627 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3628 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3629
3630 dtb = fdt.Fdt.FromData(fit_data)
3631 dtb.Scan()
3632 fnode = dtb.GetNode('/images/kernel')
3633 self.assertIn('data', fnode.props)
3634
3635 # Check all the properties in fdt-1 and fdt-2
3636 _CheckFdt(1, TEST_FDT1_DATA)
3637 _CheckFdt(2, TEST_FDT2_DATA)
3638
3639 # Check configurations
3640 _CheckConfig(1, TEST_FDT1_DATA)
3641 _CheckConfig(2, TEST_FDT2_DATA)
3642
3643 def testFitFdtMissingList(self):
3644 """Test handling of a missing 'of-list' entry arg"""
3645 with self.assertRaises(ValueError) as e:
Simon Glass1032acc2020-09-06 10:39:08 -06003646 self._DoReadFile('172_fit_fdt.dts')
Simon Glassa435cd12020-09-01 05:13:59 -06003647 self.assertIn("Generator node requires 'of-list' entry argument",
3648 str(e.exception))
3649
3650 def testFitFdtEmptyList(self):
3651 """Test handling of an empty 'of-list' entry arg"""
3652 entry_args = {
3653 'of-list': '',
3654 }
3655 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
3656
3657 def testFitFdtMissingProp(self):
3658 """Test handling of a missing 'fit,fdt-list' property"""
3659 with self.assertRaises(ValueError) as e:
3660 self._DoReadFile('171_fit_fdt_missing_prop.dts')
3661 self.assertIn("Generator node requires 'fit,fdt-list' property",
3662 str(e.exception))
Simon Glass559c4de2020-09-01 05:13:58 -06003663
Simon Glass1032acc2020-09-06 10:39:08 -06003664 def testFitFdtEmptyList(self):
3665 """Test handling of an empty 'of-list' entry arg"""
3666 entry_args = {
3667 'of-list': '',
3668 }
3669 data = self._DoReadFileDtb('172_fit_fdt.dts', entry_args=entry_args)[0]
3670
3671 def testFitFdtMissing(self):
3672 """Test handling of a missing 'default-dt' entry arg"""
3673 entry_args = {
3674 'of-list': 'test-fdt1 test-fdt2',
3675 }
3676 with self.assertRaises(ValueError) as e:
3677 self._DoReadFileDtb(
3678 '172_fit_fdt.dts',
3679 entry_args=entry_args,
3680 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3681 self.assertIn("Generated 'default' node requires default-dt entry argument",
3682 str(e.exception))
3683
3684 def testFitFdtNotInList(self):
3685 """Test handling of a default-dt that is not in the of-list"""
3686 entry_args = {
3687 'of-list': 'test-fdt1 test-fdt2',
3688 'default-dt': 'test-fdt3',
3689 }
3690 with self.assertRaises(ValueError) as e:
3691 self._DoReadFileDtb(
3692 '172_fit_fdt.dts',
3693 entry_args=entry_args,
3694 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3695 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
3696 str(e.exception))
3697
Simon Glassa820af72020-09-06 10:39:09 -06003698 def testFitExtblobMissingHelp(self):
3699 """Test display of help messages when an external blob is missing"""
3700 control.missing_blob_help = control._ReadMissingBlobHelp()
3701 control.missing_blob_help['wibble'] = 'Wibble test'
3702 control.missing_blob_help['another'] = 'Another test'
3703 with test_util.capture_sys_output() as (stdout, stderr):
3704 self._DoTestFile('168_fit_missing_blob.dts',
3705 allow_missing=True)
3706 err = stderr.getvalue()
3707
3708 # We can get the tag from the name, the type or the missing-msg
3709 # property. Check all three.
3710 self.assertIn('You may need to build ARM Trusted', err)
3711 self.assertIn('Wibble test', err)
3712 self.assertIn('Another test', err)
3713
Simon Glass6f1f4d42020-09-06 10:35:32 -06003714 def testMissingBlob(self):
3715 """Test handling of a blob containing a missing file"""
3716 with self.assertRaises(ValueError) as e:
3717 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
3718 self.assertIn("Filename 'missing' not found in input path",
3719 str(e.exception))
3720
Simon Glassa0729502020-09-06 10:35:33 -06003721 def testEnvironment(self):
3722 """Test adding a U-Boot environment"""
3723 data = self._DoReadFile('174_env.dts')
3724 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3725 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3726 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3727 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
3728 env)
3729
3730 def testEnvironmentNoSize(self):
3731 """Test that a missing 'size' property is detected"""
3732 with self.assertRaises(ValueError) as e:
3733 data = self._DoTestFile('175_env_no_size.dts')
3734 self.assertIn("'u-boot-env' entry must have a size property",
3735 str(e.exception))
3736
3737 def testEnvironmentTooSmall(self):
3738 """Test handling of an environment that does not fit"""
3739 with self.assertRaises(ValueError) as e:
3740 data = self._DoTestFile('176_env_too_small.dts')
3741
3742 # checksum, start byte, environment with \0 terminator, final \0
3743 need = 4 + 1 + len(ENV_DATA) + 1 + 1
3744 short = need - 0x8
3745 self.assertIn("too small to hold data (need %#x more bytes)" % short,
3746 str(e.exception))
3747
3748
Simon Glassac599912017-11-12 21:52:22 -07003749if __name__ == "__main__":
3750 unittest.main()