blob: 4db25e43357bfebc0105a2f56cd84a0c83c7b796 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001# SPDX-License-Identifier: GPL-2.0+
Simon Glass4f443042016-11-25 20:15:52 -07002# Copyright (c) 2016 Google, Inc
3# Written by Simon Glass <sjg@chromium.org>
4#
Simon Glass4f443042016-11-25 20:15:52 -07005# To run a single test, change to this directory, and:
6#
7# python -m unittest func_test.TestFunctional.testHelp
8
Simon Glassfdc34362020-07-09 18:39:45 -06009import collections
Simon Glass16287932020-04-17 18:09:03 -060010import gzip
Simon Glasse0e5df92018-09-14 04:57:31 -060011import hashlib
Simon Glass4f443042016-11-25 20:15:52 -070012from optparse import OptionParser
13import os
Simon Glassfdc34362020-07-09 18:39:45 -060014import re
Simon Glass4f443042016-11-25 20:15:52 -070015import shutil
16import struct
17import sys
18import tempfile
19import unittest
20
Simon Glass16287932020-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 Glass16287932020-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 Glass07237982020-08-05 13:27:47 -060032from binman.image import Image
Simon Glassbf776672020-04-17 18:09:04 -060033from patman import command
34from patman import test_util
35from patman import tools
36from patman import tout
Simon Glass4f443042016-11-25 20:15:52 -070037
38# Contents of test files, corresponding to different entry types
Simon Glassc6c10e72019-05-17 22:00:46 -060039U_BOOT_DATA = b'1234'
40U_BOOT_IMG_DATA = b'img'
Simon Glasseb0086f2019-08-24 07:23:04 -060041U_BOOT_SPL_DATA = b'56780123456789abcdefghi'
42U_BOOT_TPL_DATA = b'tpl9876543210fedcbazyw'
Simon Glassc6c10e72019-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 Glass2250ee62019-08-24 07:22:48 -060052X86_RESET16_DATA = b'reset16'
53X86_RESET16_SPL_DATA = b'reset16spl'
54X86_RESET16_TPL_DATA = b'reset16tpl'
Simon Glassc6c10e72019-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 Glassbb748372018-07-17 13:25:33 -060063TEXT_DATA = 'text'
64TEXT_DATA2 = 'text2'
65TEXT_DATA3 = 'text3'
Simon Glassc6c10e72019-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 Glassff5c7e32019-07-08 13:18:42 -060072COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
Simon Glass8f5ef892020-10-26 17:40:25 -060073COMPRESS_DATA_BIG = COMPRESS_DATA * 2
Simon Glassc6c10e72019-05-17 22:00:46 -060074REFCODE_DATA = b'refcode'
Simon Glassea0fff92019-08-24 07:23:07 -060075FSP_M_DATA = b'fsp_m'
Simon Glassbc6a88f2019-10-20 21:31:35 -060076FSP_S_DATA = b'fsp_s'
Simon Glass998d1482019-10-20 21:31:36 -060077FSP_T_DATA = b'fsp_t'
Simon Glassdc2f81a2020-09-01 05:13:58 -060078ATF_BL31_DATA = b'bl31'
Samuel Holland18bd4552020-10-21 21:12:15 -050079SCP_DATA = b'scp'
Simon Glass6cf99532020-09-01 05:13:59 -060080TEST_FDT1_DATA = b'fdt1'
81TEST_FDT2_DATA = b'test-fdt2'
Simon Glassfb91d562020-09-06 10:35:33 -060082ENV_DATA = b'var1=1\nvar2="2"'
Simon Glass6cf99532020-09-01 05:13:59 -060083
84# Subdirectory of the input dir to use to put test FDTs
85TEST_FDT_SUBDIR = 'fdts'
Simon Glassec127af2018-07-17 13:25:39 -060086
Simon Glass6ccbfcd2019-07-20 12:23:47 -060087# The expected size for the device tree in some tests
Simon Glassf667e452019-07-08 14:25:50 -060088EXTRACT_DTB_SIZE = 0x3c9
89
Simon Glass6ccbfcd2019-07-20 12:23:47 -060090# Properties expected to be in the device tree when update_dtb is used
91BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
92
Simon Glass12bb1a92019-07-20 12:23:51 -060093# Extra properties expected to be in the device tree when allow-repack is used
94REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
95
Simon Glass4f443042016-11-25 20:15:52 -070096
97class TestFunctional(unittest.TestCase):
98 """Functional tests for binman
99
100 Most of these use a sample .dts file to build an image and then check
101 that it looks correct. The sample files are in the test/ subdirectory
102 and are numbered.
103
104 For each entry type a very small test file is created using fixed
105 string contents. This makes it easy to test that things look right, and
106 debug problems.
107
108 In some cases a 'real' file must be used - these are also supplied in
109 the test/ diurectory.
110 """
111 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600112 def setUpClass(cls):
Simon Glass4d5994f2017-11-12 21:52:20 -0700113 global entry
Simon Glass16287932020-04-17 18:09:03 -0600114 from binman import entry
Simon Glass4d5994f2017-11-12 21:52:20 -0700115
Simon Glass4f443042016-11-25 20:15:52 -0700116 # Handle the case where argv[0] is 'python'
Simon Glassb986b3b2019-08-24 07:22:43 -0600117 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
118 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
Simon Glass4f443042016-11-25 20:15:52 -0700119
120 # Create a temporary directory for input files
Simon Glassb986b3b2019-08-24 07:22:43 -0600121 cls._indir = tempfile.mkdtemp(prefix='binmant.')
Simon Glass4f443042016-11-25 20:15:52 -0700122
123 # Create some test files
124 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
125 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
126 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glassb8ef5b62018-07-17 13:25:48 -0600127 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700128 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -0700129 TestFunctional._MakeInputFile('me.bin', ME_DATA)
130 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glassb986b3b2019-08-24 07:22:43 -0600131 cls._ResetDtbs()
Simon Glass2250ee62019-08-24 07:22:48 -0600132
Jagdish Gediya9d368f32018-09-03 21:35:08 +0530133 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glass2250ee62019-08-24 07:22:48 -0600134
Simon Glass5e239182019-08-24 07:22:49 -0600135 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
136 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
Simon Glass87722132017-11-12 21:52:26 -0700137 X86_START16_SPL_DATA)
Simon Glass5e239182019-08-24 07:22:49 -0600138 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
Simon Glass35b384c2018-09-14 04:57:10 -0600139 X86_START16_TPL_DATA)
Simon Glass2250ee62019-08-24 07:22:48 -0600140
141 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
142 X86_RESET16_DATA)
143 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
144 X86_RESET16_SPL_DATA)
145 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
146 X86_RESET16_TPL_DATA)
147
Simon Glass4f443042016-11-25 20:15:52 -0700148 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass6b187df2017-11-12 21:52:27 -0700149 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
150 U_BOOT_SPL_NODTB_DATA)
Simon Glassf0253632018-09-14 04:57:32 -0600151 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
152 U_BOOT_TPL_NODTB_DATA)
Simon Glassda229092016-11-25 20:15:56 -0700153 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
154 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Meng59ea8c22017-08-15 22:41:54 -0700155 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassca4f4ff2017-11-12 21:52:28 -0700156 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassec127af2018-07-17 13:25:39 -0600157 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glass0ef87aa2018-07-17 13:25:44 -0600158 TestFunctional._MakeInputDir('devkeys')
159 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass3ae192c2018-10-01 12:22:31 -0600160 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glassea0fff92019-08-24 07:23:07 -0600161 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
Simon Glassbc6a88f2019-10-20 21:31:35 -0600162 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
Simon Glass998d1482019-10-20 21:31:36 -0600163 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700164
Simon Glass53e22bf2019-08-24 07:22:53 -0600165 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
166 elf_test.BuildElfTestFiles(cls._elf_testdir)
167
Simon Glasse0ff8552016-11-25 20:15:53 -0700168 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glassf514d8f2019-08-24 07:22:54 -0600169 TestFunctional._MakeInputFile('u-boot',
170 tools.ReadFile(cls.ElfTestFile('u_boot_ucode_ptr')))
Simon Glasse0ff8552016-11-25 20:15:53 -0700171
172 # Intel flash descriptor file
Simon Glass0ba4b3d2020-07-09 18:39:41 -0600173 cls._SetupDescriptor()
Simon Glasse0ff8552016-11-25 20:15:53 -0700174
Simon Glassb986b3b2019-08-24 07:22:43 -0600175 shutil.copytree(cls.TestFile('files'),
176 os.path.join(cls._indir, 'files'))
Simon Glass0a98b282018-09-14 04:57:28 -0600177
Simon Glass83d73c22018-09-14 04:57:26 -0600178 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
Simon Glass8f5ef892020-10-26 17:40:25 -0600179 TestFunctional._MakeInputFile('compress_big', COMPRESS_DATA_BIG)
Simon Glassdc2f81a2020-09-01 05:13:58 -0600180 TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
Samuel Holland18bd4552020-10-21 21:12:15 -0500181 TestFunctional._MakeInputFile('scp.bin', SCP_DATA)
Simon Glass83d73c22018-09-14 04:57:26 -0600182
Simon Glass6cf99532020-09-01 05:13:59 -0600183 # Add a few .dtb files for testing
184 TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR,
185 TEST_FDT1_DATA)
186 TestFunctional._MakeInputFile('%s/test-fdt2.dtb' % TEST_FDT_SUBDIR,
187 TEST_FDT2_DATA)
188
Simon Glassfb91d562020-09-06 10:35:33 -0600189 TestFunctional._MakeInputFile('env.txt', ENV_DATA)
190
Simon Glassac62fba2019-07-08 13:18:53 -0600191 # Travis-CI may have an old lz4
Simon Glassb986b3b2019-08-24 07:22:43 -0600192 cls.have_lz4 = True
Simon Glassac62fba2019-07-08 13:18:53 -0600193 try:
194 tools.Run('lz4', '--no-frame-crc', '-c',
Simon Glass3b3e3c02019-10-31 07:42:50 -0600195 os.path.join(cls._indir, 'u-boot.bin'), binary=True)
Simon Glassac62fba2019-07-08 13:18:53 -0600196 except:
Simon Glassb986b3b2019-08-24 07:22:43 -0600197 cls.have_lz4 = False
Simon Glassac62fba2019-07-08 13:18:53 -0600198
Simon Glass4f443042016-11-25 20:15:52 -0700199 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600200 def tearDownClass(cls):
Simon Glass4f443042016-11-25 20:15:52 -0700201 """Remove the temporary input directory and its contents"""
Simon Glassb986b3b2019-08-24 07:22:43 -0600202 if cls.preserve_indir:
203 print('Preserving input dir: %s' % cls._indir)
Simon Glassd5164a72019-07-08 13:18:49 -0600204 else:
Simon Glassb986b3b2019-08-24 07:22:43 -0600205 if cls._indir:
206 shutil.rmtree(cls._indir)
207 cls._indir = None
Simon Glass4f443042016-11-25 20:15:52 -0700208
Simon Glassd5164a72019-07-08 13:18:49 -0600209 @classmethod
Simon Glass8acce602019-07-08 13:18:50 -0600210 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
Simon Glass53cd5d92019-07-08 14:25:29 -0600211 toolpath=None, verbosity=None):
Simon Glassd5164a72019-07-08 13:18:49 -0600212 """Accept arguments controlling test execution
213
214 Args:
215 preserve_indir: Preserve the shared input directory used by all
216 tests in this class.
217 preserve_outdir: Preserve the output directories used by tests. Each
218 test has its own, so this is normally only useful when running a
219 single test.
Simon Glass8acce602019-07-08 13:18:50 -0600220 toolpath: ist of paths to use for tools
Simon Glassd5164a72019-07-08 13:18:49 -0600221 """
222 cls.preserve_indir = preserve_indir
223 cls.preserve_outdirs = preserve_outdirs
Simon Glass8acce602019-07-08 13:18:50 -0600224 cls.toolpath = toolpath
Simon Glass53cd5d92019-07-08 14:25:29 -0600225 cls.verbosity = verbosity
Simon Glassd5164a72019-07-08 13:18:49 -0600226
Simon Glassac62fba2019-07-08 13:18:53 -0600227 def _CheckLz4(self):
228 if not self.have_lz4:
229 self.skipTest('lz4 --no-frame-crc not available')
230
Simon Glassbf574f12019-07-20 12:24:09 -0600231 def _CleanupOutputDir(self):
232 """Remove the temporary output directory"""
233 if self.preserve_outdirs:
234 print('Preserving output dir: %s' % tools.outdir)
235 else:
236 tools._FinaliseForTest()
237
Simon Glass4f443042016-11-25 20:15:52 -0700238 def setUp(self):
239 # Enable this to turn on debugging output
240 # tout.Init(tout.DEBUG)
241 command.test_result = None
242
243 def tearDown(self):
244 """Remove the temporary output directory"""
Simon Glassbf574f12019-07-20 12:24:09 -0600245 self._CleanupOutputDir()
Simon Glass4f443042016-11-25 20:15:52 -0700246
Simon Glassf86a7362019-07-20 12:24:10 -0600247 def _SetupImageInTmpdir(self):
248 """Set up the output image in a new temporary directory
249
250 This is used when an image has been generated in the output directory,
251 but we want to run binman again. This will create a new output
252 directory and fail to delete the original one.
253
254 This creates a new temporary directory, copies the image to it (with a
255 new name) and removes the old output directory.
256
257 Returns:
258 Tuple:
259 Temporary directory to use
260 New image filename
261 """
262 image_fname = tools.GetOutputFilename('image.bin')
263 tmpdir = tempfile.mkdtemp(prefix='binman.')
264 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
265 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
266 self._CleanupOutputDir()
267 return tmpdir, updated_fname
268
Simon Glassb8ef5b62018-07-17 13:25:48 -0600269 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600270 def _ResetDtbs(cls):
Simon Glassb8ef5b62018-07-17 13:25:48 -0600271 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
272 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
273 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
274
Simon Glass4f443042016-11-25 20:15:52 -0700275 def _RunBinman(self, *args, **kwargs):
276 """Run binman using the command line
277
278 Args:
279 Arguments to pass, as a list of strings
280 kwargs: Arguments to pass to Command.RunPipe()
281 """
282 result = command.RunPipe([[self._binman_pathname] + list(args)],
283 capture=True, capture_stderr=True, raise_on_error=False)
284 if result.return_code and kwargs.get('raise_on_error', True):
285 raise Exception("Error running '%s': %s" % (' '.join(args),
286 result.stdout + result.stderr))
287 return result
288
Simon Glass53cd5d92019-07-08 14:25:29 -0600289 def _DoBinman(self, *argv):
Simon Glass4f443042016-11-25 20:15:52 -0700290 """Run binman using directly (in the same process)
291
292 Args:
293 Arguments to pass, as a list of strings
294 Returns:
295 Return value (0 for success)
296 """
Simon Glass53cd5d92019-07-08 14:25:29 -0600297 argv = list(argv)
298 args = cmdline.ParseArgs(argv)
299 args.pager = 'binman-invalid-pager'
300 args.build_dir = self._indir
Simon Glass4f443042016-11-25 20:15:52 -0700301
302 # For testing, you can force an increase in verbosity here
Simon Glass53cd5d92019-07-08 14:25:29 -0600303 # args.verbosity = tout.DEBUG
304 return control.Binman(args)
Simon Glass4f443042016-11-25 20:15:52 -0700305
Simon Glass53af22a2018-07-17 13:25:32 -0600306 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glasseb833d82019-04-25 21:58:34 -0600307 entry_args=None, images=None, use_real_dtb=False,
Simon Glass63aeaeb2021-03-18 20:25:05 +1300308 use_expanded=False, verbosity=None, allow_missing=False,
309 extra_indirs=None):
Simon Glass4f443042016-11-25 20:15:52 -0700310 """Run binman with a given test file
311
312 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600313 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600314 debug: True to enable debugging output
Simon Glass3b0c3822018-06-01 09:38:20 -0600315 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600316 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600317 tree before packing it into the image
Simon Glass0bfa7b02018-09-14 04:57:12 -0600318 entry_args: Dict of entry args to supply to binman
319 key: arg name
320 value: value of that arg
321 images: List of image names to build
Simon Glasse9d336d2020-09-01 05:13:55 -0600322 use_real_dtb: True to use the test file as the contents of
323 the u-boot-dtb entry. Normally this is not needed and the
324 test contents (the U_BOOT_DTB_DATA string) can be used.
325 But in some test we need the real contents.
Simon Glass63aeaeb2021-03-18 20:25:05 +1300326 use_expanded: True to use expanded entries where available, e.g.
327 'u-boot-expanded' instead of 'u-boot'
Simon Glasse9d336d2020-09-01 05:13:55 -0600328 verbosity: Verbosity level to use (0-3, None=don't set it)
329 allow_missing: Set the '--allow-missing' flag so that missing
330 external binaries just produce a warning instead of an error
Simon Glass6cf99532020-09-01 05:13:59 -0600331 extra_indirs: Extra input directories to add using -I
Simon Glass4f443042016-11-25 20:15:52 -0700332 """
Simon Glass53cd5d92019-07-08 14:25:29 -0600333 args = []
Simon Glass7fe91732017-11-13 18:55:00 -0700334 if debug:
335 args.append('-D')
Simon Glass53cd5d92019-07-08 14:25:29 -0600336 if verbosity is not None:
337 args.append('-v%d' % verbosity)
338 elif self.verbosity:
339 args.append('-v%d' % self.verbosity)
340 if self.toolpath:
341 for path in self.toolpath:
342 args += ['--toolpath', path]
343 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass3b0c3822018-06-01 09:38:20 -0600344 if map:
345 args.append('-m')
Simon Glass16b8d6b2018-07-06 10:27:42 -0600346 if update_dtb:
Simon Glass2569e102019-07-08 13:18:47 -0600347 args.append('-u')
Simon Glass93d17412018-09-14 04:57:23 -0600348 if not use_real_dtb:
349 args.append('--fake-dtb')
Simon Glass63aeaeb2021-03-18 20:25:05 +1300350 if not use_expanded:
351 args.append('--no-expanded')
Simon Glass53af22a2018-07-17 13:25:32 -0600352 if entry_args:
Simon Glass50979152019-05-14 15:53:41 -0600353 for arg, value in entry_args.items():
Simon Glass53af22a2018-07-17 13:25:32 -0600354 args.append('-a%s=%s' % (arg, value))
Simon Glass4f9f1052020-07-09 18:39:38 -0600355 if allow_missing:
356 args.append('-M')
Simon Glass0bfa7b02018-09-14 04:57:12 -0600357 if images:
358 for image in images:
359 args += ['-i', image]
Simon Glass6cf99532020-09-01 05:13:59 -0600360 if extra_indirs:
361 for indir in extra_indirs:
362 args += ['-I', indir]
Simon Glass7fe91732017-11-13 18:55:00 -0700363 return self._DoBinman(*args)
Simon Glass4f443042016-11-25 20:15:52 -0700364
365 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glasse0ff8552016-11-25 20:15:53 -0700366 """Set up a new test device-tree file
367
368 The given file is compiled and set up as the device tree to be used
369 for ths test.
370
371 Args:
372 fname: Filename of .dts file to read
Simon Glass7ae5f312018-06-01 09:38:19 -0600373 outfile: Output filename for compiled device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700374
375 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600376 Contents of device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700377 """
Simon Glassa004f292019-07-20 12:23:49 -0600378 tmpdir = tempfile.mkdtemp(prefix='binmant.')
379 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
Simon Glass1d0ebf72019-05-14 15:53:42 -0600380 with open(dtb, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700381 data = fd.read()
382 TestFunctional._MakeInputFile(outfile, data)
Simon Glassa004f292019-07-20 12:23:49 -0600383 shutil.rmtree(tmpdir)
Simon Glasse0e62752018-10-01 21:12:41 -0600384 return data
Simon Glass4f443042016-11-25 20:15:52 -0700385
Simon Glass6ed45ba2018-09-14 04:57:24 -0600386 def _GetDtbContentsForSplTpl(self, dtb_data, name):
387 """Create a version of the main DTB for SPL or SPL
388
389 For testing we don't actually have different versions of the DTB. With
390 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
391 we don't normally have any unwanted nodes.
392
393 We still want the DTBs for SPL and TPL to be different though, since
394 otherwise it is confusing to know which one we are looking at. So add
395 an 'spl' or 'tpl' property to the top-level node.
Simon Glasse9d336d2020-09-01 05:13:55 -0600396
397 Args:
398 dtb_data: dtb data to modify (this should be a value devicetree)
399 name: Name of a new property to add
400
401 Returns:
402 New dtb data with the property added
Simon Glass6ed45ba2018-09-14 04:57:24 -0600403 """
404 dtb = fdt.Fdt.FromData(dtb_data)
405 dtb.Scan()
406 dtb.GetNode('/binman').AddZeroProp(name)
407 dtb.Sync(auto_resize=True)
408 dtb.Pack()
409 return dtb.GetContents()
410
Simon Glass63aeaeb2021-03-18 20:25:05 +1300411 def _DoReadFileDtb(self, fname, use_real_dtb=False, use_expanded=False,
412 map=False, update_dtb=False, entry_args=None,
413 reset_dtbs=True, extra_indirs=None):
Simon Glass4f443042016-11-25 20:15:52 -0700414 """Run binman and return the resulting image
415
416 This runs binman with a given test file and then reads the resulting
417 output file. It is a shortcut function since most tests need to do
418 these steps.
419
420 Raises an assertion failure if binman returns a non-zero exit code.
421
422 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600423 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass4f443042016-11-25 20:15:52 -0700424 use_real_dtb: True to use the test file as the contents of
425 the u-boot-dtb entry. Normally this is not needed and the
426 test contents (the U_BOOT_DTB_DATA string) can be used.
427 But in some test we need the real contents.
Simon Glass63aeaeb2021-03-18 20:25:05 +1300428 use_expanded: True to use expanded entries where available, e.g.
429 'u-boot-expanded' instead of 'u-boot'
Simon Glass3b0c3822018-06-01 09:38:20 -0600430 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600431 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600432 tree before packing it into the image
Simon Glasse9d336d2020-09-01 05:13:55 -0600433 entry_args: Dict of entry args to supply to binman
434 key: arg name
435 value: value of that arg
436 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
437 function. If reset_dtbs is True, then the original test dtb
438 is written back before this function finishes
Simon Glass6cf99532020-09-01 05:13:59 -0600439 extra_indirs: Extra input directories to add using -I
Simon Glasse0ff8552016-11-25 20:15:53 -0700440
441 Returns:
442 Tuple:
443 Resulting image contents
444 Device tree contents
Simon Glass3b0c3822018-06-01 09:38:20 -0600445 Map data showing contents of image (or None if none)
Simon Glassea6922e2018-07-17 13:25:27 -0600446 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass4f443042016-11-25 20:15:52 -0700447 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700448 dtb_data = None
Simon Glass4f443042016-11-25 20:15:52 -0700449 # Use the compiled test file as the u-boot-dtb input
450 if use_real_dtb:
Simon Glasse0ff8552016-11-25 20:15:53 -0700451 dtb_data = self._SetupDtb(fname)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600452
453 # For testing purposes, make a copy of the DT for SPL and TPL. Add
454 # a node indicating which it is, so aid verification.
455 for name in ['spl', 'tpl']:
456 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
457 outfile = os.path.join(self._indir, dtb_fname)
458 TestFunctional._MakeInputFile(dtb_fname,
459 self._GetDtbContentsForSplTpl(dtb_data, name))
Simon Glass4f443042016-11-25 20:15:52 -0700460
461 try:
Simon Glass53af22a2018-07-17 13:25:32 -0600462 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glass6cf99532020-09-01 05:13:59 -0600463 entry_args=entry_args, use_real_dtb=use_real_dtb,
Simon Glass63aeaeb2021-03-18 20:25:05 +1300464 use_expanded=use_expanded, extra_indirs=extra_indirs)
Simon Glass4f443042016-11-25 20:15:52 -0700465 self.assertEqual(0, retcode)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600466 out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
Simon Glass4f443042016-11-25 20:15:52 -0700467
468 # Find the (only) image, read it and return its contents
469 image = control.images['image']
Simon Glass16b8d6b2018-07-06 10:27:42 -0600470 image_fname = tools.GetOutputFilename('image.bin')
471 self.assertTrue(os.path.exists(image_fname))
Simon Glass3b0c3822018-06-01 09:38:20 -0600472 if map:
473 map_fname = tools.GetOutputFilename('image.map')
474 with open(map_fname) as fd:
475 map_data = fd.read()
476 else:
477 map_data = None
Simon Glass1d0ebf72019-05-14 15:53:42 -0600478 with open(image_fname, 'rb') as fd:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600479 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass4f443042016-11-25 20:15:52 -0700480 finally:
481 # Put the test file back
Simon Glass6ed45ba2018-09-14 04:57:24 -0600482 if reset_dtbs and use_real_dtb:
Simon Glassb8ef5b62018-07-17 13:25:48 -0600483 self._ResetDtbs()
Simon Glass4f443042016-11-25 20:15:52 -0700484
Simon Glass3c081312019-07-08 14:25:26 -0600485 def _DoReadFileRealDtb(self, fname):
486 """Run binman with a real .dtb file and return the resulting data
487
488 Args:
489 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
490
491 Returns:
492 Resulting image contents
493 """
494 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
495
Simon Glasse0ff8552016-11-25 20:15:53 -0700496 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass7ae5f312018-06-01 09:38:19 -0600497 """Helper function which discards the device-tree binary
498
499 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600500 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600501 use_real_dtb: True to use the test file as the contents of
502 the u-boot-dtb entry. Normally this is not needed and the
503 test contents (the U_BOOT_DTB_DATA string) can be used.
504 But in some test we need the real contents.
Simon Glassea6922e2018-07-17 13:25:27 -0600505
506 Returns:
507 Resulting image contents
Simon Glass7ae5f312018-06-01 09:38:19 -0600508 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700509 return self._DoReadFileDtb(fname, use_real_dtb)[0]
510
Simon Glass4f443042016-11-25 20:15:52 -0700511 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600512 def _MakeInputFile(cls, fname, contents):
Simon Glass4f443042016-11-25 20:15:52 -0700513 """Create a new test input file, creating directories as needed
514
515 Args:
Simon Glass3ab95982018-08-01 15:22:37 -0600516 fname: Filename to create
Simon Glass4f443042016-11-25 20:15:52 -0700517 contents: File contents to write in to the file
518 Returns:
519 Full pathname of file created
520 """
Simon Glassb986b3b2019-08-24 07:22:43 -0600521 pathname = os.path.join(cls._indir, fname)
Simon Glass4f443042016-11-25 20:15:52 -0700522 dirname = os.path.dirname(pathname)
523 if dirname and not os.path.exists(dirname):
524 os.makedirs(dirname)
525 with open(pathname, 'wb') as fd:
526 fd.write(contents)
527 return pathname
528
529 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600530 def _MakeInputDir(cls, dirname):
Simon Glass0ef87aa2018-07-17 13:25:44 -0600531 """Create a new test input directory, creating directories as needed
532
533 Args:
534 dirname: Directory name to create
535
536 Returns:
537 Full pathname of directory created
538 """
Simon Glassb986b3b2019-08-24 07:22:43 -0600539 pathname = os.path.join(cls._indir, dirname)
Simon Glass0ef87aa2018-07-17 13:25:44 -0600540 if not os.path.exists(pathname):
541 os.makedirs(pathname)
542 return pathname
543
544 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600545 def _SetupSplElf(cls, src_fname='bss_data'):
Simon Glass11ae93e2018-10-01 21:12:47 -0600546 """Set up an ELF file with a '_dt_ucode_base_size' symbol
547
548 Args:
549 Filename of ELF file to use as SPL
550 """
Simon Glassc9a0b272019-08-24 07:22:59 -0600551 TestFunctional._MakeInputFile('spl/u-boot-spl',
552 tools.ReadFile(cls.ElfTestFile(src_fname)))
Simon Glass11ae93e2018-10-01 21:12:47 -0600553
554 @classmethod
Simon Glass2090f1e2019-08-24 07:23:00 -0600555 def _SetupTplElf(cls, src_fname='bss_data'):
556 """Set up an ELF file with a '_dt_ucode_base_size' symbol
557
558 Args:
559 Filename of ELF file to use as TPL
560 """
561 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
562 tools.ReadFile(cls.ElfTestFile(src_fname)))
563
564 @classmethod
Simon Glass0ba4b3d2020-07-09 18:39:41 -0600565 def _SetupDescriptor(cls):
566 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
567 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
568
569 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600570 def TestFile(cls, fname):
571 return os.path.join(cls._binman_dir, 'test', fname)
Simon Glass4f443042016-11-25 20:15:52 -0700572
Simon Glass53e22bf2019-08-24 07:22:53 -0600573 @classmethod
574 def ElfTestFile(cls, fname):
575 return os.path.join(cls._elf_testdir, fname)
576
Simon Glass4f443042016-11-25 20:15:52 -0700577 def AssertInList(self, grep_list, target):
578 """Assert that at least one of a list of things is in a target
579
580 Args:
581 grep_list: List of strings to check
582 target: Target string
583 """
584 for grep in grep_list:
585 if grep in target:
586 return
Simon Glass1fc62de2019-05-17 22:00:50 -0600587 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass4f443042016-11-25 20:15:52 -0700588
589 def CheckNoGaps(self, entries):
590 """Check that all entries fit together without gaps
591
592 Args:
593 entries: List of entries to check
594 """
Simon Glass3ab95982018-08-01 15:22:37 -0600595 offset = 0
Simon Glass4f443042016-11-25 20:15:52 -0700596 for entry in entries.values():
Simon Glass3ab95982018-08-01 15:22:37 -0600597 self.assertEqual(offset, entry.offset)
598 offset += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700599
Simon Glasse0ff8552016-11-25 20:15:53 -0700600 def GetFdtLen(self, dtb):
Simon Glass7ae5f312018-06-01 09:38:19 -0600601 """Get the totalsize field from a device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700602
603 Args:
Simon Glass7ae5f312018-06-01 09:38:19 -0600604 dtb: Device-tree binary contents
Simon Glasse0ff8552016-11-25 20:15:53 -0700605
606 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600607 Total size of device-tree binary, from the header
Simon Glasse0ff8552016-11-25 20:15:53 -0700608 """
609 return struct.unpack('>L', dtb[4:8])[0]
610
Simon Glass086cec92019-07-08 14:25:27 -0600611 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glass16b8d6b2018-07-06 10:27:42 -0600612 def AddNode(node, path):
613 if node.name != '/':
614 path += '/' + node.name
Simon Glass086cec92019-07-08 14:25:27 -0600615 for prop in node.props.values():
616 if prop.name in prop_names:
617 prop_path = path + ':' + prop.name
618 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
619 prop.value)
Simon Glass16b8d6b2018-07-06 10:27:42 -0600620 for subnode in node.subnodes:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600621 AddNode(subnode, path)
622
623 tree = {}
Simon Glass16b8d6b2018-07-06 10:27:42 -0600624 AddNode(dtb.GetRoot(), '')
625 return tree
626
Simon Glass4f443042016-11-25 20:15:52 -0700627 def testRun(self):
628 """Test a basic run with valid args"""
629 result = self._RunBinman('-h')
630
631 def testFullHelp(self):
632 """Test that the full help is displayed with -H"""
633 result = self._RunBinman('-H')
Simon Glass61adb2d2021-03-18 20:25:13 +1300634 help_file = os.path.join(self._binman_dir, 'README.rst')
Tom Rini3759df02018-01-16 15:29:50 -0500635 # Remove possible extraneous strings
636 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
637 gothelp = result.stdout.replace(extra, '')
638 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass4f443042016-11-25 20:15:52 -0700639 self.assertEqual(0, len(result.stderr))
640 self.assertEqual(0, result.return_code)
641
642 def testFullHelpInternal(self):
643 """Test that the full help is displayed with -H"""
644 try:
645 command.test_result = command.CommandResult()
646 result = self._DoBinman('-H')
Simon Glass61adb2d2021-03-18 20:25:13 +1300647 help_file = os.path.join(self._binman_dir, 'README.rst')
Simon Glass4f443042016-11-25 20:15:52 -0700648 finally:
649 command.test_result = None
650
651 def testHelp(self):
652 """Test that the basic help is displayed with -h"""
653 result = self._RunBinman('-h')
654 self.assertTrue(len(result.stdout) > 200)
655 self.assertEqual(0, len(result.stderr))
656 self.assertEqual(0, result.return_code)
657
Simon Glass4f443042016-11-25 20:15:52 -0700658 def testBoard(self):
659 """Test that we can run it with a specific board"""
Simon Glass741f2d62018-10-01 12:22:30 -0600660 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass4f443042016-11-25 20:15:52 -0700661 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glass63aeaeb2021-03-18 20:25:05 +1300662 result = self._DoBinman('build', '-n', '-b', 'sandbox')
Simon Glass4f443042016-11-25 20:15:52 -0700663 self.assertEqual(0, result)
664
665 def testNeedBoard(self):
666 """Test that we get an error when no board ius supplied"""
667 with self.assertRaises(ValueError) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600668 result = self._DoBinman('build')
Simon Glass4f443042016-11-25 20:15:52 -0700669 self.assertIn("Must provide a board to process (use -b <board>)",
670 str(e.exception))
671
672 def testMissingDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600673 """Test that an invalid device-tree file generates an error"""
Simon Glass4f443042016-11-25 20:15:52 -0700674 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600675 self._RunBinman('build', '-d', 'missing_file')
Simon Glass4f443042016-11-25 20:15:52 -0700676 # We get one error from libfdt, and a different one from fdtget.
677 self.AssertInList(["Couldn't open blob from 'missing_file'",
678 'No such file or directory'], str(e.exception))
679
680 def testBrokenDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600681 """Test that an invalid device-tree source file generates an error
Simon Glass4f443042016-11-25 20:15:52 -0700682
683 Since this is a source file it should be compiled and the error
684 will come from the device-tree compiler (dtc).
685 """
686 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600687 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700688 self.assertIn("FATAL ERROR: Unable to parse input tree",
689 str(e.exception))
690
691 def testMissingNode(self):
692 """Test that a device tree without a 'binman' node generates an error"""
693 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600694 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700695 self.assertIn("does not have a 'binman' node", str(e.exception))
696
697 def testEmpty(self):
698 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glass53cd5d92019-07-08 14:25:29 -0600699 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700700 self.assertEqual(0, len(result.stderr))
701 self.assertEqual(0, result.return_code)
702
703 def testInvalidEntry(self):
704 """Test that an invalid entry is flagged"""
705 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600706 result = self._RunBinman('build', '-d',
Simon Glass741f2d62018-10-01 12:22:30 -0600707 self.TestFile('004_invalid_entry.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700708 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
709 "'/binman/not-a-valid-type'", str(e.exception))
710
711 def testSimple(self):
712 """Test a simple binman with a single file"""
Simon Glass741f2d62018-10-01 12:22:30 -0600713 data = self._DoReadFile('005_simple.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700714 self.assertEqual(U_BOOT_DATA, data)
715
Simon Glass7fe91732017-11-13 18:55:00 -0700716 def testSimpleDebug(self):
717 """Test a simple binman run with debugging enabled"""
Simon Glasse2705fa2019-07-08 14:25:53 -0600718 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass7fe91732017-11-13 18:55:00 -0700719
Simon Glass4f443042016-11-25 20:15:52 -0700720 def testDual(self):
721 """Test that we can handle creating two images
722
723 This also tests image padding.
724 """
Simon Glass741f2d62018-10-01 12:22:30 -0600725 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700726 self.assertEqual(0, retcode)
727
728 image = control.images['image1']
Simon Glass8beb11e2019-07-08 14:25:47 -0600729 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700730 fname = tools.GetOutputFilename('image1.bin')
731 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600732 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700733 data = fd.read()
734 self.assertEqual(U_BOOT_DATA, data)
735
736 image = control.images['image2']
Simon Glass8beb11e2019-07-08 14:25:47 -0600737 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700738 fname = tools.GetOutputFilename('image2.bin')
739 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600740 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700741 data = fd.read()
742 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glasse6d85ff2019-05-14 15:53:47 -0600743 self.assertEqual(tools.GetBytes(0, 3), data[:3])
744 self.assertEqual(tools.GetBytes(0, 5), data[7:])
Simon Glass4f443042016-11-25 20:15:52 -0700745
746 def testBadAlign(self):
747 """Test that an invalid alignment value is detected"""
748 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600749 self._DoTestFile('007_bad_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700750 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
751 "of two", str(e.exception))
752
753 def testPackSimple(self):
754 """Test that packing works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600755 retcode = self._DoTestFile('008_pack.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700756 self.assertEqual(0, retcode)
757 self.assertIn('image', control.images)
758 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600759 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700760 self.assertEqual(5, len(entries))
761
762 # First u-boot
763 self.assertIn('u-boot', entries)
764 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600765 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700766 self.assertEqual(len(U_BOOT_DATA), entry.size)
767
768 # Second u-boot, aligned to 16-byte boundary
769 self.assertIn('u-boot-align', entries)
770 entry = entries['u-boot-align']
Simon Glass3ab95982018-08-01 15:22:37 -0600771 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700772 self.assertEqual(len(U_BOOT_DATA), entry.size)
773
774 # Third u-boot, size 23 bytes
775 self.assertIn('u-boot-size', entries)
776 entry = entries['u-boot-size']
Simon Glass3ab95982018-08-01 15:22:37 -0600777 self.assertEqual(20, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700778 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
779 self.assertEqual(23, entry.size)
780
781 # Fourth u-boot, placed immediate after the above
782 self.assertIn('u-boot-next', entries)
783 entry = entries['u-boot-next']
Simon Glass3ab95982018-08-01 15:22:37 -0600784 self.assertEqual(43, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700785 self.assertEqual(len(U_BOOT_DATA), entry.size)
786
Simon Glass3ab95982018-08-01 15:22:37 -0600787 # Fifth u-boot, placed at a fixed offset
Simon Glass4f443042016-11-25 20:15:52 -0700788 self.assertIn('u-boot-fixed', entries)
789 entry = entries['u-boot-fixed']
Simon Glass3ab95982018-08-01 15:22:37 -0600790 self.assertEqual(61, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700791 self.assertEqual(len(U_BOOT_DATA), entry.size)
792
Simon Glass8beb11e2019-07-08 14:25:47 -0600793 self.assertEqual(65, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700794
795 def testPackExtra(self):
796 """Test that extra packing feature works as expected"""
Simon Glass4eec34c2020-10-26 17:40:10 -0600797 data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
798 update_dtb=True)
Simon Glass4f443042016-11-25 20:15:52 -0700799
Simon Glass4f443042016-11-25 20:15:52 -0700800 self.assertIn('image', control.images)
801 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600802 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700803 self.assertEqual(5, len(entries))
804
805 # First u-boot with padding before and after
806 self.assertIn('u-boot', entries)
807 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600808 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700809 self.assertEqual(3, entry.pad_before)
810 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600811 self.assertEqual(U_BOOT_DATA, entry.data)
812 self.assertEqual(tools.GetBytes(0, 3) + U_BOOT_DATA +
813 tools.GetBytes(0, 5), data[:entry.size])
814 pos = entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700815
816 # Second u-boot has an aligned size, but it has no effect
817 self.assertIn('u-boot-align-size-nop', entries)
818 entry = entries['u-boot-align-size-nop']
Simon Glassef439ed2020-10-26 17:40:08 -0600819 self.assertEqual(pos, entry.offset)
820 self.assertEqual(len(U_BOOT_DATA), entry.size)
821 self.assertEqual(U_BOOT_DATA, entry.data)
822 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
823 pos += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700824
825 # Third u-boot has an aligned size too
826 self.assertIn('u-boot-align-size', entries)
827 entry = entries['u-boot-align-size']
Simon Glassef439ed2020-10-26 17:40:08 -0600828 self.assertEqual(pos, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700829 self.assertEqual(32, entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600830 self.assertEqual(U_BOOT_DATA, entry.data)
831 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 32 - len(U_BOOT_DATA)),
832 data[pos:pos + entry.size])
833 pos += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700834
835 # Fourth u-boot has an aligned end
836 self.assertIn('u-boot-align-end', entries)
837 entry = entries['u-boot-align-end']
Simon Glass3ab95982018-08-01 15:22:37 -0600838 self.assertEqual(48, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700839 self.assertEqual(16, entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600840 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
841 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 16 - len(U_BOOT_DATA)),
842 data[pos:pos + entry.size])
843 pos += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700844
845 # Fifth u-boot immediately afterwards
846 self.assertIn('u-boot-align-both', entries)
847 entry = entries['u-boot-align-both']
Simon Glass3ab95982018-08-01 15:22:37 -0600848 self.assertEqual(64, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700849 self.assertEqual(64, entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600850 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
851 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 64 - len(U_BOOT_DATA)),
852 data[pos:pos + entry.size])
Simon Glass4f443042016-11-25 20:15:52 -0700853
854 self.CheckNoGaps(entries)
Simon Glass8beb11e2019-07-08 14:25:47 -0600855 self.assertEqual(128, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700856
Simon Glass4eec34c2020-10-26 17:40:10 -0600857 dtb = fdt.Fdt(out_dtb_fname)
858 dtb.Scan()
859 props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
860 expected = {
861 'image-pos': 0,
862 'offset': 0,
863 'size': 128,
864
865 'u-boot:image-pos': 0,
866 'u-boot:offset': 0,
867 'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
868
869 'u-boot-align-size-nop:image-pos': 12,
870 'u-boot-align-size-nop:offset': 12,
871 'u-boot-align-size-nop:size': 4,
872
873 'u-boot-align-size:image-pos': 16,
874 'u-boot-align-size:offset': 16,
875 'u-boot-align-size:size': 32,
876
877 'u-boot-align-end:image-pos': 48,
878 'u-boot-align-end:offset': 48,
879 'u-boot-align-end:size': 16,
880
881 'u-boot-align-both:image-pos': 64,
882 'u-boot-align-both:offset': 64,
883 'u-boot-align-both:size': 64,
884 }
885 self.assertEqual(expected, props)
886
Simon Glass4f443042016-11-25 20:15:52 -0700887 def testPackAlignPowerOf2(self):
888 """Test that invalid entry alignment is detected"""
889 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600890 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700891 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
892 "of two", str(e.exception))
893
894 def testPackAlignSizePowerOf2(self):
895 """Test that invalid entry size alignment is detected"""
896 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600897 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700898 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
899 "power of two", str(e.exception))
900
901 def testPackInvalidAlign(self):
Simon Glass3ab95982018-08-01 15:22:37 -0600902 """Test detection of an offset that does not match its alignment"""
Simon Glass4f443042016-11-25 20:15:52 -0700903 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600904 self._DoTestFile('012_pack_inv_align.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600905 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700906 "align 0x4 (4)", str(e.exception))
907
908 def testPackInvalidSizeAlign(self):
909 """Test that invalid entry size alignment is detected"""
910 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600911 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700912 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
913 "align-size 0x4 (4)", str(e.exception))
914
915 def testPackOverlap(self):
916 """Test that overlapping regions are detected"""
917 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600918 self._DoTestFile('014_pack_overlap.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600919 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -0700920 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
921 str(e.exception))
922
923 def testPackEntryOverflow(self):
924 """Test that entries that overflow their size are detected"""
925 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600926 self._DoTestFile('015_pack_overflow.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700927 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
928 "but entry size is 0x3 (3)", str(e.exception))
929
930 def testPackImageOverflow(self):
931 """Test that entries which overflow the image size are detected"""
932 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600933 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600934 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass4f443042016-11-25 20:15:52 -0700935 "size 0x3 (3)", str(e.exception))
936
937 def testPackImageSize(self):
938 """Test that the image size can be set"""
Simon Glass741f2d62018-10-01 12:22:30 -0600939 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700940 self.assertEqual(0, retcode)
941 self.assertIn('image', control.images)
942 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -0600943 self.assertEqual(7, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700944
945 def testPackImageSizeAlign(self):
946 """Test that image size alignemnt works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600947 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700948 self.assertEqual(0, retcode)
949 self.assertIn('image', control.images)
950 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -0600951 self.assertEqual(16, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700952
953 def testPackInvalidImageAlign(self):
954 """Test that invalid image alignment is detected"""
955 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600956 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600957 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700958 "align-size 0x8 (8)", str(e.exception))
959
960 def testPackAlignPowerOf2(self):
961 """Test that invalid image alignment is detected"""
962 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600963 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -0600964 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass4f443042016-11-25 20:15:52 -0700965 "two", str(e.exception))
966
967 def testImagePadByte(self):
968 """Test that the image pad byte can be specified"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600969 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600970 data = self._DoReadFile('021_image_pad.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -0600971 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0xff, 1) +
972 U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -0700973
974 def testImageName(self):
975 """Test that image files can be named"""
Simon Glass741f2d62018-10-01 12:22:30 -0600976 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700977 self.assertEqual(0, retcode)
978 image = control.images['image1']
979 fname = tools.GetOutputFilename('test-name')
980 self.assertTrue(os.path.exists(fname))
981
982 image = control.images['image2']
983 fname = tools.GetOutputFilename('test-name.xx')
984 self.assertTrue(os.path.exists(fname))
985
986 def testBlobFilename(self):
987 """Test that generic blobs can be provided by filename"""
Simon Glass741f2d62018-10-01 12:22:30 -0600988 data = self._DoReadFile('023_blob.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700989 self.assertEqual(BLOB_DATA, data)
990
991 def testPackSorted(self):
992 """Test that entries can be sorted"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600993 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600994 data = self._DoReadFile('024_sorted.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -0600995 self.assertEqual(tools.GetBytes(0, 1) + U_BOOT_SPL_DATA +
996 tools.GetBytes(0, 2) + U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -0700997
Simon Glass3ab95982018-08-01 15:22:37 -0600998 def testPackZeroOffset(self):
999 """Test that an entry at offset 0 is not given a new offset"""
Simon Glass4f443042016-11-25 20:15:52 -07001000 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001001 self._DoTestFile('025_pack_zero_size.dts')
Simon Glass3ab95982018-08-01 15:22:37 -06001002 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -07001003 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1004 str(e.exception))
1005
1006 def testPackUbootDtb(self):
1007 """Test that a device tree can be added to U-Boot"""
Simon Glass741f2d62018-10-01 12:22:30 -06001008 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001009 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glasse0ff8552016-11-25 20:15:53 -07001010
1011 def testPackX86RomNoSize(self):
1012 """Test that the end-at-4gb property requires a size property"""
1013 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001014 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -06001015 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glasse0ff8552016-11-25 20:15:53 -07001016 "using end-at-4gb", str(e.exception))
1017
Jagdish Gediya94b57db2018-09-03 21:35:07 +05301018 def test4gbAndSkipAtStartTogether(self):
1019 """Test that the end-at-4gb and skip-at-size property can't be used
1020 together"""
1021 with self.assertRaises(ValueError) as e:
Simon Glassdfdd2b62019-08-24 07:23:02 -06001022 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -06001023 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya94b57db2018-09-03 21:35:07 +05301024 "'skip-at-start'", str(e.exception))
1025
Simon Glasse0ff8552016-11-25 20:15:53 -07001026 def testPackX86RomOutside(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001027 """Test that the end-at-4gb property checks for offset boundaries"""
Simon Glasse0ff8552016-11-25 20:15:53 -07001028 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001029 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glasse6bed4f2020-10-26 17:40:05 -06001030 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
1031 "is outside the section '/binman' starting at "
1032 '0xffffffe0 (4294967264) of size 0x20 (32)',
Simon Glasse0ff8552016-11-25 20:15:53 -07001033 str(e.exception))
1034
1035 def testPackX86Rom(self):
1036 """Test that a basic x86 ROM can be created"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001037 self._SetupSplElf()
Simon Glass9255f3c2019-08-24 07:23:01 -06001038 data = self._DoReadFile('029_x86_rom.dts')
Simon Glasseb0086f2019-08-24 07:23:04 -06001039 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 3) + U_BOOT_SPL_DATA +
Simon Glasse6d85ff2019-05-14 15:53:47 -06001040 tools.GetBytes(0, 2), data)
Simon Glasse0ff8552016-11-25 20:15:53 -07001041
1042 def testPackX86RomMeNoDesc(self):
1043 """Test that an invalid Intel descriptor entry is detected"""
Simon Glass0ba4b3d2020-07-09 18:39:41 -06001044 try:
Simon Glass52b10dd2020-07-25 15:11:19 -06001045 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
Simon Glass0ba4b3d2020-07-09 18:39:41 -06001046 with self.assertRaises(ValueError) as e:
Simon Glass52b10dd2020-07-25 15:11:19 -06001047 self._DoTestFile('163_x86_rom_me_empty.dts')
Simon Glass0ba4b3d2020-07-09 18:39:41 -06001048 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1049 str(e.exception))
1050 finally:
1051 self._SetupDescriptor()
Simon Glasse0ff8552016-11-25 20:15:53 -07001052
1053 def testPackX86RomBadDesc(self):
1054 """Test that the Intel requires a descriptor entry"""
1055 with self.assertRaises(ValueError) as e:
Simon Glass9255f3c2019-08-24 07:23:01 -06001056 self._DoTestFile('030_x86_rom_me_no_desc.dts')
Simon Glass3ab95982018-08-01 15:22:37 -06001057 self.assertIn("Node '/binman/intel-me': No offset set with "
1058 "offset-unset: should another entry provide this correct "
1059 "offset?", str(e.exception))
Simon Glasse0ff8552016-11-25 20:15:53 -07001060
1061 def testPackX86RomMe(self):
1062 """Test that an x86 ROM with an ME region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001063 data = self._DoReadFile('031_x86_rom_me.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06001064 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
1065 if data[:0x1000] != expected_desc:
1066 self.fail('Expected descriptor binary at start of image')
Simon Glasse0ff8552016-11-25 20:15:53 -07001067 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1068
1069 def testPackVga(self):
1070 """Test that an image with a VGA binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001071 data = self._DoReadFile('032_intel_vga.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -07001072 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1073
1074 def testPackStart16(self):
1075 """Test that an image with an x86 start16 region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001076 data = self._DoReadFile('033_x86_start16.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -07001077 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1078
Jagdish Gediya9d368f32018-09-03 21:35:08 +05301079 def testPackPowerpcMpc85xxBootpgResetvec(self):
1080 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1081 created"""
Simon Glassdfdd2b62019-08-24 07:23:02 -06001082 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
Jagdish Gediya9d368f32018-09-03 21:35:08 +05301083 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1084
Simon Glass736bb0a2018-07-06 10:27:17 -06001085 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glassadc57012018-07-06 10:27:16 -06001086 """Handle running a test for insertion of microcode
1087
1088 Args:
1089 dts_fname: Name of test .dts file
1090 nodtb_data: Data that we expect in the first section
Simon Glass736bb0a2018-07-06 10:27:17 -06001091 ucode_second: True if the microsecond entry is second instead of
1092 third
Simon Glassadc57012018-07-06 10:27:16 -06001093
1094 Returns:
1095 Tuple:
1096 Contents of first region (U-Boot or SPL)
Simon Glass3ab95982018-08-01 15:22:37 -06001097 Offset and size components of microcode pointer, as inserted
Simon Glassadc57012018-07-06 10:27:16 -06001098 in the above (two 4-byte words)
1099 """
Simon Glass6b187df2017-11-12 21:52:27 -07001100 data = self._DoReadFile(dts_fname, True)
Simon Glasse0ff8552016-11-25 20:15:53 -07001101
1102 # Now check the device tree has no microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001103 if ucode_second:
1104 ucode_content = data[len(nodtb_data):]
1105 ucode_pos = len(nodtb_data)
1106 dtb_with_ucode = ucode_content[16:]
1107 fdt_len = self.GetFdtLen(dtb_with_ucode)
1108 else:
1109 dtb_with_ucode = data[len(nodtb_data):]
1110 fdt_len = self.GetFdtLen(dtb_with_ucode)
1111 ucode_content = dtb_with_ucode[fdt_len:]
1112 ucode_pos = len(nodtb_data) + fdt_len
Simon Glasse0ff8552016-11-25 20:15:53 -07001113 fname = tools.GetOutputFilename('test.dtb')
1114 with open(fname, 'wb') as fd:
Simon Glassadc57012018-07-06 10:27:16 -06001115 fd.write(dtb_with_ucode)
Simon Glassec3f3782017-05-27 07:38:29 -06001116 dtb = fdt.FdtScan(fname)
1117 ucode = dtb.GetNode('/microcode')
Simon Glasse0ff8552016-11-25 20:15:53 -07001118 self.assertTrue(ucode)
1119 for node in ucode.subnodes:
1120 self.assertFalse(node.props.get('data'))
1121
Simon Glasse0ff8552016-11-25 20:15:53 -07001122 # Check that the microcode appears immediately after the Fdt
1123 # This matches the concatenation of the data properties in
Simon Glass87722132017-11-12 21:52:26 -07001124 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glasse0ff8552016-11-25 20:15:53 -07001125 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1126 0x78235609)
Simon Glassadc57012018-07-06 10:27:16 -06001127 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glasse0ff8552016-11-25 20:15:53 -07001128
1129 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -06001130 # expected offset and size
Simon Glasse0ff8552016-11-25 20:15:53 -07001131 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1132 len(ucode_data))
Simon Glass736bb0a2018-07-06 10:27:17 -06001133 u_boot = data[:len(nodtb_data)]
1134 return u_boot, pos_and_size
Simon Glass6b187df2017-11-12 21:52:27 -07001135
1136 def testPackUbootMicrocode(self):
1137 """Test that x86 microcode can be handled correctly
1138
1139 We expect to see the following in the image, in order:
1140 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1141 place
1142 u-boot.dtb with the microcode removed
1143 the microcode
1144 """
Simon Glass741f2d62018-10-01 12:22:30 -06001145 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass6b187df2017-11-12 21:52:27 -07001146 U_BOOT_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001147 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1148 b' somewhere in here', first)
Simon Glasse0ff8552016-11-25 20:15:53 -07001149
Simon Glass160a7662017-05-27 07:38:26 -06001150 def _RunPackUbootSingleMicrocode(self):
Simon Glasse0ff8552016-11-25 20:15:53 -07001151 """Test that x86 microcode can be handled correctly
1152
1153 We expect to see the following in the image, in order:
1154 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1155 place
1156 u-boot.dtb with the microcode
1157 an empty microcode region
1158 """
1159 # We need the libfdt library to run this test since only that allows
1160 # finding the offset of a property. This is required by
1161 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass741f2d62018-10-01 12:22:30 -06001162 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glasse0ff8552016-11-25 20:15:53 -07001163
1164 second = data[len(U_BOOT_NODTB_DATA):]
1165
1166 fdt_len = self.GetFdtLen(second)
1167 third = second[fdt_len:]
1168 second = second[:fdt_len]
1169
Simon Glass160a7662017-05-27 07:38:26 -06001170 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1171 self.assertIn(ucode_data, second)
1172 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -07001173
Simon Glass160a7662017-05-27 07:38:26 -06001174 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -06001175 # expected offset and size
Simon Glass160a7662017-05-27 07:38:26 -06001176 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1177 len(ucode_data))
1178 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glassc6c10e72019-05-17 22:00:46 -06001179 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1180 b' somewhere in here', first)
Simon Glassc49deb82016-11-25 20:15:54 -07001181
Simon Glass75db0862016-11-25 20:15:55 -07001182 def testPackUbootSingleMicrocode(self):
1183 """Test that x86 microcode can be handled correctly with fdt_normal.
1184 """
Simon Glass160a7662017-05-27 07:38:26 -06001185 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001186
Simon Glassc49deb82016-11-25 20:15:54 -07001187 def testUBootImg(self):
1188 """Test that u-boot.img can be put in a file"""
Simon Glass741f2d62018-10-01 12:22:30 -06001189 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glassc49deb82016-11-25 20:15:54 -07001190 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glass75db0862016-11-25 20:15:55 -07001191
1192 def testNoMicrocode(self):
1193 """Test that a missing microcode region is detected"""
1194 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001195 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001196 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1197 "node found in ", str(e.exception))
1198
1199 def testMicrocodeWithoutNode(self):
1200 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1201 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001202 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001203 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1204 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1205
1206 def testMicrocodeWithoutNode2(self):
1207 """Test that a missing u-boot-ucode node is detected"""
1208 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001209 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001210 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1211 "microcode region u-boot-ucode", str(e.exception))
1212
1213 def testMicrocodeWithoutPtrInElf(self):
1214 """Test that a U-Boot binary without the microcode symbol is detected"""
1215 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glass75db0862016-11-25 20:15:55 -07001216 try:
Simon Glassbccd91d2019-08-24 07:22:55 -06001217 TestFunctional._MakeInputFile('u-boot',
1218 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass75db0862016-11-25 20:15:55 -07001219
1220 with self.assertRaises(ValueError) as e:
Simon Glass160a7662017-05-27 07:38:26 -06001221 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001222 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1223 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1224
1225 finally:
1226 # Put the original file back
Simon Glassf514d8f2019-08-24 07:22:54 -06001227 TestFunctional._MakeInputFile('u-boot',
1228 tools.ReadFile(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glass75db0862016-11-25 20:15:55 -07001229
1230 def testMicrocodeNotInImage(self):
1231 """Test that microcode must be placed within the image"""
1232 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001233 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001234 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1235 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glass25ac0e62018-06-01 09:38:14 -06001236 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glass75db0862016-11-25 20:15:55 -07001237
1238 def testWithoutMicrocode(self):
1239 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glassbccd91d2019-08-24 07:22:55 -06001240 TestFunctional._MakeInputFile('u-boot',
1241 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass741f2d62018-10-01 12:22:30 -06001242 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001243
1244 # Now check the device tree has no microcode
1245 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1246 second = data[len(U_BOOT_NODTB_DATA):]
1247
1248 fdt_len = self.GetFdtLen(second)
1249 self.assertEqual(dtb, second[:fdt_len])
1250
1251 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1252 third = data[used_len:]
Simon Glasse6d85ff2019-05-14 15:53:47 -06001253 self.assertEqual(tools.GetBytes(0, 0x200 - used_len), third)
Simon Glass75db0862016-11-25 20:15:55 -07001254
1255 def testUnknownPosSize(self):
1256 """Test that microcode must be placed within the image"""
1257 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001258 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glass3ab95982018-08-01 15:22:37 -06001259 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glass75db0862016-11-25 20:15:55 -07001260 "entry 'invalid-entry'", str(e.exception))
Simon Glassda229092016-11-25 20:15:56 -07001261
1262 def testPackFsp(self):
1263 """Test that an image with a FSP binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001264 data = self._DoReadFile('042_intel_fsp.dts')
Simon Glassda229092016-11-25 20:15:56 -07001265 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1266
1267 def testPackCmc(self):
Bin Meng59ea8c22017-08-15 22:41:54 -07001268 """Test that an image with a CMC binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001269 data = self._DoReadFile('043_intel_cmc.dts')
Simon Glassda229092016-11-25 20:15:56 -07001270 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Meng59ea8c22017-08-15 22:41:54 -07001271
1272 def testPackVbt(self):
1273 """Test that an image with a VBT binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001274 data = self._DoReadFile('046_intel_vbt.dts')
Bin Meng59ea8c22017-08-15 22:41:54 -07001275 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glass9fc60b42017-11-12 21:52:22 -07001276
Simon Glass56509842017-11-12 21:52:25 -07001277 def testSplBssPad(self):
1278 """Test that we can pad SPL's BSS with zeros"""
Simon Glass6b187df2017-11-12 21:52:27 -07001279 # ELF file with a '__bss_size' symbol
Simon Glass11ae93e2018-10-01 21:12:47 -06001280 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001281 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001282 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
1283 data)
Simon Glass56509842017-11-12 21:52:25 -07001284
Simon Glass86af5112018-10-01 21:12:42 -06001285 def testSplBssPadMissing(self):
1286 """Test that a missing symbol is detected"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001287 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glassb50e5612017-11-13 18:54:54 -07001288 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001289 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassb50e5612017-11-13 18:54:54 -07001290 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1291 str(e.exception))
1292
Simon Glass87722132017-11-12 21:52:26 -07001293 def testPackStart16Spl(self):
Simon Glass35b384c2018-09-14 04:57:10 -06001294 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001295 data = self._DoReadFile('048_x86_start16_spl.dts')
Simon Glass87722132017-11-12 21:52:26 -07001296 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1297
Simon Glass736bb0a2018-07-06 10:27:17 -06001298 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1299 """Helper function for microcode tests
Simon Glass6b187df2017-11-12 21:52:27 -07001300
1301 We expect to see the following in the image, in order:
1302 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1303 correct place
1304 u-boot.dtb with the microcode removed
1305 the microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001306
1307 Args:
1308 dts: Device tree file to use for test
1309 ucode_second: True if the microsecond entry is second instead of
1310 third
Simon Glass6b187df2017-11-12 21:52:27 -07001311 """
Simon Glass11ae93e2018-10-01 21:12:47 -06001312 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass736bb0a2018-07-06 10:27:17 -06001313 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1314 ucode_second=ucode_second)
Simon Glassc6c10e72019-05-17 22:00:46 -06001315 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1316 b'ter somewhere in here', first)
Simon Glass6b187df2017-11-12 21:52:27 -07001317
Simon Glass736bb0a2018-07-06 10:27:17 -06001318 def testPackUbootSplMicrocode(self):
1319 """Test that x86 microcode can be handled correctly in SPL"""
Simon Glass741f2d62018-10-01 12:22:30 -06001320 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass736bb0a2018-07-06 10:27:17 -06001321
1322 def testPackUbootSplMicrocodeReorder(self):
1323 """Test that order doesn't matter for microcode entries
1324
1325 This is the same as testPackUbootSplMicrocode but when we process the
1326 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1327 entry, so we reply on binman to try later.
1328 """
Simon Glass741f2d62018-10-01 12:22:30 -06001329 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass736bb0a2018-07-06 10:27:17 -06001330 ucode_second=True)
1331
Simon Glassca4f4ff2017-11-12 21:52:28 -07001332 def testPackMrc(self):
1333 """Test that an image with an MRC binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001334 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassca4f4ff2017-11-12 21:52:28 -07001335 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1336
Simon Glass47419ea2017-11-13 18:54:55 -07001337 def testSplDtb(self):
1338 """Test that an image with spl/u-boot-spl.dtb can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001339 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass47419ea2017-11-13 18:54:55 -07001340 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1341
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001342 def testSplNoDtb(self):
1343 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass0fe44dc2021-04-25 08:39:32 +12001344 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001345 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001346 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1347
Simon Glass3d433382021-03-21 18:24:30 +13001348 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
1349 use_expanded=False):
Simon Glassf5898822021-03-18 20:24:56 +13001350 """Check the image contains the expected symbol values
1351
1352 Args:
1353 dts: Device tree file to use for test
1354 base_data: Data before and after 'u-boot' section
1355 u_boot_offset: Offset of 'u-boot' section in image
Simon Glass3d433382021-03-21 18:24:30 +13001356 entry_args: Dict of entry args to supply to binman
1357 key: arg name
1358 value: value of that arg
1359 use_expanded: True to use expanded entries where available, e.g.
1360 'u-boot-expanded' instead of 'u-boot'
Simon Glassf5898822021-03-18 20:24:56 +13001361 """
Simon Glass1542c8b2019-08-24 07:22:56 -06001362 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass19790632017-11-13 18:55:01 -07001363 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1364 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Simon Glassf5898822021-03-18 20:24:56 +13001365 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
1366 addr)
Simon Glass19790632017-11-13 18:55:01 -07001367
Simon Glass11ae93e2018-10-01 21:12:47 -06001368 self._SetupSplElf('u_boot_binman_syms')
Simon Glass3d433382021-03-21 18:24:30 +13001369 data = self._DoReadFileDtb(dts, entry_args=entry_args,
1370 use_expanded=use_expanded)[0]
Simon Glassf5898822021-03-18 20:24:56 +13001371 # The image should contain the symbols from u_boot_binman_syms.c
1372 # Note that image_pos is adjusted by the base address of the image,
1373 # which is 0x10 in our test image
1374 sym_values = struct.pack('<LQLL', 0x00,
1375 u_boot_offset + len(U_BOOT_DATA),
1376 0x10 + u_boot_offset, 0x04)
1377 expected = (sym_values + base_data[20:] +
Simon Glasse6d85ff2019-05-14 15:53:47 -06001378 tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
Simon Glassf5898822021-03-18 20:24:56 +13001379 base_data[20:])
Simon Glass19790632017-11-13 18:55:01 -07001380 self.assertEqual(expected, data)
1381
Simon Glassf5898822021-03-18 20:24:56 +13001382 def testSymbols(self):
1383 """Test binman can assign symbols embedded in U-Boot"""
1384 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x18)
1385
1386 def testSymbolsNoDtb(self):
1387 """Test binman can assign symbols embedded in U-Boot SPL"""
Simon Glasse9e0db82021-03-21 18:24:29 +13001388 self.checkSymbols('196_symbols_nodtb.dts',
Simon Glassf5898822021-03-18 20:24:56 +13001389 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1390 0x38)
1391
Simon Glassdd57c132018-06-01 09:38:11 -06001392 def testPackUnitAddress(self):
1393 """Test that we support multiple binaries with the same name"""
Simon Glass741f2d62018-10-01 12:22:30 -06001394 data = self._DoReadFile('054_unit_address.dts')
Simon Glassdd57c132018-06-01 09:38:11 -06001395 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1396
Simon Glass18546952018-06-01 09:38:16 -06001397 def testSections(self):
1398 """Basic test of sections"""
Simon Glass741f2d62018-10-01 12:22:30 -06001399 data = self._DoReadFile('055_sections.dts')
Simon Glassc6c10e72019-05-17 22:00:46 -06001400 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1401 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
1402 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
Simon Glass18546952018-06-01 09:38:16 -06001403 self.assertEqual(expected, data)
Simon Glass9fc60b42017-11-12 21:52:22 -07001404
Simon Glass3b0c3822018-06-01 09:38:20 -06001405 def testMap(self):
1406 """Tests outputting a map of the images"""
Simon Glass741f2d62018-10-01 12:22:30 -06001407 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001408 self.assertEqual('''ImagePos Offset Size Name
140900000000 00000000 00000028 main-section
141000000000 00000000 00000010 section@0
141100000000 00000000 00000004 u-boot
141200000010 00000010 00000010 section@1
141300000010 00000000 00000004 u-boot
141400000020 00000020 00000004 section@2
141500000020 00000000 00000004 u-boot
Simon Glass3b0c3822018-06-01 09:38:20 -06001416''', map_data)
1417
Simon Glassc8d48ef2018-06-01 09:38:21 -06001418 def testNamePrefix(self):
1419 """Tests that name prefixes are used"""
Simon Glass741f2d62018-10-01 12:22:30 -06001420 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001421 self.assertEqual('''ImagePos Offset Size Name
142200000000 00000000 00000028 main-section
142300000000 00000000 00000010 section@0
142400000000 00000000 00000004 ro-u-boot
142500000010 00000010 00000010 section@1
142600000010 00000000 00000004 rw-u-boot
Simon Glassc8d48ef2018-06-01 09:38:21 -06001427''', map_data)
1428
Simon Glass736bb0a2018-07-06 10:27:17 -06001429 def testUnknownContents(self):
1430 """Test that obtaining the contents works as expected"""
1431 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001432 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass8beb11e2019-07-08 14:25:47 -06001433 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glass16287932020-04-17 18:09:03 -06001434 "processing of contents: remaining ["
1435 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass736bb0a2018-07-06 10:27:17 -06001436
Simon Glass5c890232018-07-06 10:27:19 -06001437 def testBadChangeSize(self):
1438 """Test that trying to change the size of an entry fails"""
Simon Glassc52c9e72019-07-08 14:25:37 -06001439 try:
1440 state.SetAllowEntryExpansion(False)
1441 with self.assertRaises(ValueError) as e:
1442 self._DoReadFile('059_change_size.dts', True)
Simon Glass79d3c582019-07-20 12:23:57 -06001443 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glassc52c9e72019-07-08 14:25:37 -06001444 str(e.exception))
1445 finally:
1446 state.SetAllowEntryExpansion(True)
Simon Glass5c890232018-07-06 10:27:19 -06001447
Simon Glass16b8d6b2018-07-06 10:27:42 -06001448 def testUpdateFdt(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001449 """Test that we can update the device tree with offset/size info"""
Simon Glass741f2d62018-10-01 12:22:30 -06001450 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glass16b8d6b2018-07-06 10:27:42 -06001451 update_dtb=True)
Simon Glasscee02e62018-07-17 13:25:52 -06001452 dtb = fdt.Fdt(out_dtb_fname)
1453 dtb.Scan()
Simon Glass12bb1a92019-07-20 12:23:51 -06001454 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001455 self.assertEqual({
Simon Glassdbf6be92018-08-01 15:22:42 -06001456 'image-pos': 0,
Simon Glass8122f392018-07-17 13:25:28 -06001457 'offset': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001458 '_testing:offset': 32,
Simon Glass79d3c582019-07-20 12:23:57 -06001459 '_testing:size': 2,
Simon Glassdbf6be92018-08-01 15:22:42 -06001460 '_testing:image-pos': 32,
Simon Glass3ab95982018-08-01 15:22:37 -06001461 'section@0/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001462 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001463 'section@0/u-boot:image-pos': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001464 'section@0:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001465 'section@0:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001466 'section@0:image-pos': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001467
Simon Glass3ab95982018-08-01 15:22:37 -06001468 'section@1/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001469 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001470 'section@1/u-boot:image-pos': 16,
Simon Glass3ab95982018-08-01 15:22:37 -06001471 'section@1:offset': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001472 'section@1:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001473 'section@1:image-pos': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001474 'size': 40
1475 }, props)
1476
1477 def testUpdateFdtBad(self):
1478 """Test that we detect when ProcessFdt never completes"""
1479 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001480 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001481 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glass16287932020-04-17 18:09:03 -06001482 '[<binman.etype._testing.Entry__testing',
1483 str(e.exception))
Simon Glass5c890232018-07-06 10:27:19 -06001484
Simon Glass53af22a2018-07-17 13:25:32 -06001485 def testEntryArgs(self):
1486 """Test passing arguments to entries from the command line"""
1487 entry_args = {
1488 'test-str-arg': 'test1',
1489 'test-int-arg': '456',
1490 }
Simon Glass741f2d62018-10-01 12:22:30 -06001491 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001492 self.assertIn('image', control.images)
1493 entry = control.images['image'].GetEntries()['_testing']
1494 self.assertEqual('test0', entry.test_str_fdt)
1495 self.assertEqual('test1', entry.test_str_arg)
1496 self.assertEqual(123, entry.test_int_fdt)
1497 self.assertEqual(456, entry.test_int_arg)
1498
1499 def testEntryArgsMissing(self):
1500 """Test missing arguments and properties"""
1501 entry_args = {
1502 'test-int-arg': '456',
1503 }
Simon Glass741f2d62018-10-01 12:22:30 -06001504 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001505 entry = control.images['image'].GetEntries()['_testing']
1506 self.assertEqual('test0', entry.test_str_fdt)
1507 self.assertEqual(None, entry.test_str_arg)
1508 self.assertEqual(None, entry.test_int_fdt)
1509 self.assertEqual(456, entry.test_int_arg)
1510
1511 def testEntryArgsRequired(self):
1512 """Test missing arguments and properties"""
1513 entry_args = {
1514 'test-int-arg': '456',
1515 }
1516 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001517 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass3decfa32020-09-01 05:13:54 -06001518 self.assertIn("Node '/binman/_testing': "
1519 'Missing required properties/entry args: test-str-arg, '
1520 'test-int-fdt, test-int-arg',
Simon Glass53af22a2018-07-17 13:25:32 -06001521 str(e.exception))
1522
1523 def testEntryArgsInvalidFormat(self):
1524 """Test that an invalid entry-argument format is detected"""
Simon Glass53cd5d92019-07-08 14:25:29 -06001525 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1526 '-ano-value']
Simon Glass53af22a2018-07-17 13:25:32 -06001527 with self.assertRaises(ValueError) as e:
1528 self._DoBinman(*args)
1529 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1530
1531 def testEntryArgsInvalidInteger(self):
1532 """Test that an invalid entry-argument integer is detected"""
1533 entry_args = {
1534 'test-int-arg': 'abc',
1535 }
1536 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001537 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001538 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1539 "'test-int-arg' (value 'abc') to integer",
1540 str(e.exception))
1541
1542 def testEntryArgsInvalidDatatype(self):
1543 """Test that an invalid entry-argument datatype is detected
1544
1545 This test could be written in entry_test.py except that it needs
1546 access to control.entry_args, which seems more than that module should
1547 be able to see.
1548 """
1549 entry_args = {
1550 'test-bad-datatype-arg': '12',
1551 }
1552 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001553 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass53af22a2018-07-17 13:25:32 -06001554 entry_args=entry_args)
1555 self.assertIn('GetArg() internal error: Unknown data type ',
1556 str(e.exception))
1557
Simon Glassbb748372018-07-17 13:25:33 -06001558 def testText(self):
1559 """Test for a text entry type"""
1560 entry_args = {
1561 'test-id': TEXT_DATA,
1562 'test-id2': TEXT_DATA2,
1563 'test-id3': TEXT_DATA3,
1564 }
Simon Glass741f2d62018-10-01 12:22:30 -06001565 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glassbb748372018-07-17 13:25:33 -06001566 entry_args=entry_args)
Simon Glassc6c10e72019-05-17 22:00:46 -06001567 expected = (tools.ToBytes(TEXT_DATA) +
1568 tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1569 tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
Simon Glassaa88b502019-07-08 13:18:40 -06001570 b'some text' + b'more text')
Simon Glassbb748372018-07-17 13:25:33 -06001571 self.assertEqual(expected, data)
1572
Simon Glassfd8d1f72018-07-17 13:25:36 -06001573 def testEntryDocs(self):
1574 """Test for creation of entry documentation"""
1575 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass87d43322020-08-05 13:27:46 -06001576 control.WriteEntryDocs(control.GetEntryModules())
Simon Glassfd8d1f72018-07-17 13:25:36 -06001577 self.assertTrue(len(stdout.getvalue()) > 0)
1578
1579 def testEntryDocsMissing(self):
1580 """Test handling of missing entry documentation"""
1581 with self.assertRaises(ValueError) as e:
1582 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass87d43322020-08-05 13:27:46 -06001583 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glassfd8d1f72018-07-17 13:25:36 -06001584 self.assertIn('Documentation is missing for modules: u_boot',
1585 str(e.exception))
1586
Simon Glass11e36cc2018-07-17 13:25:38 -06001587 def testFmap(self):
1588 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001589 data = self._DoReadFile('067_fmap.dts')
Simon Glass11e36cc2018-07-17 13:25:38 -06001590 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc6c10e72019-05-17 22:00:46 -06001591 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1592 U_BOOT_DATA + tools.GetBytes(ord('a'), 12))
Simon Glass11e36cc2018-07-17 13:25:38 -06001593 self.assertEqual(expected, data[:32])
Simon Glassc6c10e72019-05-17 22:00:46 -06001594 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass11e36cc2018-07-17 13:25:38 -06001595 self.assertEqual(1, fhdr.ver_major)
1596 self.assertEqual(0, fhdr.ver_minor)
1597 self.assertEqual(0, fhdr.base)
1598 self.assertEqual(16 + 16 +
1599 fmap_util.FMAP_HEADER_LEN +
1600 fmap_util.FMAP_AREA_LEN * 3, fhdr.image_size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001601 self.assertEqual(b'FMAP', fhdr.name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001602 self.assertEqual(3, fhdr.nareas)
1603 for fentry in fentries:
1604 self.assertEqual(0, fentry.flags)
1605
1606 self.assertEqual(0, fentries[0].offset)
1607 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001608 self.assertEqual(b'RO_U_BOOT', fentries[0].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001609
1610 self.assertEqual(16, fentries[1].offset)
1611 self.assertEqual(4, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001612 self.assertEqual(b'RW_U_BOOT', fentries[1].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001613
1614 self.assertEqual(32, fentries[2].offset)
1615 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1616 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001617 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001618
Simon Glassec127af2018-07-17 13:25:39 -06001619 def testBlobNamedByArg(self):
1620 """Test we can add a blob with the filename coming from an entry arg"""
1621 entry_args = {
1622 'cros-ec-rw-path': 'ecrw.bin',
1623 }
Simon Glass3decfa32020-09-01 05:13:54 -06001624 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassec127af2018-07-17 13:25:39 -06001625
Simon Glass3af8e492018-07-17 13:25:40 -06001626 def testFill(self):
1627 """Test for an fill entry type"""
Simon Glass741f2d62018-10-01 12:22:30 -06001628 data = self._DoReadFile('069_fill.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001629 expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
Simon Glass3af8e492018-07-17 13:25:40 -06001630 self.assertEqual(expected, data)
1631
1632 def testFillNoSize(self):
1633 """Test for an fill entry type with no size"""
1634 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001635 self._DoReadFile('070_fill_no_size.dts')
Simon Glass3af8e492018-07-17 13:25:40 -06001636 self.assertIn("'fill' entry must have a size property",
1637 str(e.exception))
1638
Simon Glass0ef87aa2018-07-17 13:25:44 -06001639 def _HandleGbbCommand(self, pipe_list):
1640 """Fake calls to the futility utility"""
1641 if pipe_list[0][0] == 'futility':
1642 fname = pipe_list[0][-1]
1643 # Append our GBB data to the file, which will happen every time the
1644 # futility command is called.
Simon Glass1d0ebf72019-05-14 15:53:42 -06001645 with open(fname, 'ab') as fd:
Simon Glass0ef87aa2018-07-17 13:25:44 -06001646 fd.write(GBB_DATA)
1647 return command.CommandResult()
1648
1649 def testGbb(self):
1650 """Test for the Chromium OS Google Binary Block"""
1651 command.test_result = self._HandleGbbCommand
1652 entry_args = {
1653 'keydir': 'devkeys',
1654 'bmpblk': 'bmpblk.bin',
1655 }
Simon Glass741f2d62018-10-01 12:22:30 -06001656 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glass0ef87aa2018-07-17 13:25:44 -06001657
1658 # Since futility
Simon Glasse6d85ff2019-05-14 15:53:47 -06001659 expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1660 tools.GetBytes(0, 0x2180 - 16))
Simon Glass0ef87aa2018-07-17 13:25:44 -06001661 self.assertEqual(expected, data)
1662
1663 def testGbbTooSmall(self):
1664 """Test for the Chromium OS Google Binary Block being large enough"""
1665 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001666 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001667 self.assertIn("Node '/binman/gbb': GBB is too small",
1668 str(e.exception))
1669
1670 def testGbbNoSize(self):
1671 """Test for the Chromium OS Google Binary Block having a size"""
1672 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001673 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001674 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1675 str(e.exception))
1676
Simon Glass24d0d3c2018-07-17 13:25:47 -06001677 def _HandleVblockCommand(self, pipe_list):
Simon Glass5af9ebc2021-01-06 21:35:17 -07001678 """Fake calls to the futility utility
1679
1680 The expected pipe is:
1681
1682 [('futility', 'vbutil_firmware', '--vblock',
1683 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1684 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1685 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1686 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1687
1688 This writes to the output file (here, 'vblock.vblock'). If
1689 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1690 of the input data (here, 'input.vblock').
1691 """
Simon Glass24d0d3c2018-07-17 13:25:47 -06001692 if pipe_list[0][0] == 'futility':
1693 fname = pipe_list[0][3]
Simon Glassa326b492018-09-14 04:57:11 -06001694 with open(fname, 'wb') as fd:
Simon Glass5af9ebc2021-01-06 21:35:17 -07001695 if self._hash_data:
1696 infile = pipe_list[0][11]
1697 m = hashlib.sha256()
1698 data = tools.ReadFile(infile)
1699 m.update(data)
1700 fd.write(m.digest())
1701 else:
1702 fd.write(VBLOCK_DATA)
1703
Simon Glass24d0d3c2018-07-17 13:25:47 -06001704 return command.CommandResult()
1705
1706 def testVblock(self):
1707 """Test for the Chromium OS Verified Boot Block"""
Simon Glass5af9ebc2021-01-06 21:35:17 -07001708 self._hash_data = False
Simon Glass24d0d3c2018-07-17 13:25:47 -06001709 command.test_result = self._HandleVblockCommand
1710 entry_args = {
1711 'keydir': 'devkeys',
1712 }
Simon Glass741f2d62018-10-01 12:22:30 -06001713 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass24d0d3c2018-07-17 13:25:47 -06001714 entry_args=entry_args)
1715 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1716 self.assertEqual(expected, data)
1717
1718 def testVblockNoContent(self):
1719 """Test we detect a vblock which has no content to sign"""
1720 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001721 self._DoReadFile('075_vblock_no_content.dts')
Simon Glass189f2912021-03-21 18:24:31 +13001722 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
Simon Glass24d0d3c2018-07-17 13:25:47 -06001723 'property', str(e.exception))
1724
1725 def testVblockBadPhandle(self):
1726 """Test that we detect a vblock with an invalid phandle in contents"""
1727 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001728 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001729 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1730 '1000', str(e.exception))
1731
1732 def testVblockBadEntry(self):
1733 """Test that we detect an entry that points to a non-entry"""
1734 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001735 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001736 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1737 "'other'", str(e.exception))
1738
Simon Glass5af9ebc2021-01-06 21:35:17 -07001739 def testVblockContent(self):
1740 """Test that the vblock signs the right data"""
1741 self._hash_data = True
1742 command.test_result = self._HandleVblockCommand
1743 entry_args = {
1744 'keydir': 'devkeys',
1745 }
1746 data = self._DoReadFileDtb(
1747 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1748 entry_args=entry_args)[0]
1749 hashlen = 32 # SHA256 hash is 32 bytes
1750 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1751 hashval = data[-hashlen:]
1752 dtb = data[len(U_BOOT_DATA):-hashlen]
1753
1754 expected_data = U_BOOT_DATA + dtb
1755
1756 # The hashval should be a hash of the dtb
1757 m = hashlib.sha256()
1758 m.update(expected_data)
1759 expected_hashval = m.digest()
1760 self.assertEqual(expected_hashval, hashval)
1761
Simon Glassb8ef5b62018-07-17 13:25:48 -06001762 def testTpl(self):
Simon Glass2090f1e2019-08-24 07:23:00 -06001763 """Test that an image with TPL and its device tree can be created"""
Simon Glassb8ef5b62018-07-17 13:25:48 -06001764 # ELF file with a '__bss_size' symbol
Simon Glass2090f1e2019-08-24 07:23:00 -06001765 self._SetupTplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001766 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glassb8ef5b62018-07-17 13:25:48 -06001767 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1768
Simon Glass15a587c2018-07-17 13:25:51 -06001769 def testUsesPos(self):
1770 """Test that the 'pos' property cannot be used anymore"""
1771 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001772 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass15a587c2018-07-17 13:25:51 -06001773 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1774 "'pos'", str(e.exception))
1775
Simon Glassd178eab2018-09-14 04:57:08 -06001776 def testFillZero(self):
1777 """Test for an fill entry type with a size of 0"""
Simon Glass741f2d62018-10-01 12:22:30 -06001778 data = self._DoReadFile('080_fill_empty.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001779 self.assertEqual(tools.GetBytes(0, 16), data)
Simon Glassd178eab2018-09-14 04:57:08 -06001780
Simon Glass0b489362018-09-14 04:57:09 -06001781 def testTextMissing(self):
1782 """Test for a text entry type where there is no text"""
1783 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001784 self._DoReadFileDtb('066_text.dts',)
Simon Glass0b489362018-09-14 04:57:09 -06001785 self.assertIn("Node '/binman/text': No value provided for text label "
1786 "'test-id'", str(e.exception))
1787
Simon Glass35b384c2018-09-14 04:57:10 -06001788 def testPackStart16Tpl(self):
1789 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001790 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glass35b384c2018-09-14 04:57:10 -06001791 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1792
Simon Glass0bfa7b02018-09-14 04:57:12 -06001793 def testSelectImage(self):
1794 """Test that we can select which images to build"""
Simon Glasseb833d82019-04-25 21:58:34 -06001795 expected = 'Skipping images: image1'
Simon Glass0bfa7b02018-09-14 04:57:12 -06001796
Simon Glasseb833d82019-04-25 21:58:34 -06001797 # We should only get the expected message in verbose mode
Simon Glassee0c9a72019-07-08 13:18:48 -06001798 for verbosity in (0, 2):
Simon Glasseb833d82019-04-25 21:58:34 -06001799 with test_util.capture_sys_output() as (stdout, stderr):
1800 retcode = self._DoTestFile('006_dual_image.dts',
1801 verbosity=verbosity,
1802 images=['image2'])
1803 self.assertEqual(0, retcode)
1804 if verbosity:
1805 self.assertIn(expected, stdout.getvalue())
1806 else:
1807 self.assertNotIn(expected, stdout.getvalue())
1808
1809 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1810 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
Simon Glassf86a7362019-07-20 12:24:10 -06001811 self._CleanupOutputDir()
Simon Glass0bfa7b02018-09-14 04:57:12 -06001812
Simon Glass6ed45ba2018-09-14 04:57:24 -06001813 def testUpdateFdtAll(self):
1814 """Test that all device trees are updated with offset/size info"""
Simon Glass3c081312019-07-08 14:25:26 -06001815 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glass6ed45ba2018-09-14 04:57:24 -06001816
1817 base_expected = {
1818 'section:image-pos': 0,
1819 'u-boot-tpl-dtb:size': 513,
1820 'u-boot-spl-dtb:size': 513,
1821 'u-boot-spl-dtb:offset': 493,
1822 'image-pos': 0,
1823 'section/u-boot-dtb:image-pos': 0,
1824 'u-boot-spl-dtb:image-pos': 493,
1825 'section/u-boot-dtb:size': 493,
1826 'u-boot-tpl-dtb:image-pos': 1006,
1827 'section/u-boot-dtb:offset': 0,
1828 'section:size': 493,
1829 'offset': 0,
1830 'section:offset': 0,
1831 'u-boot-tpl-dtb:offset': 1006,
1832 'size': 1519
1833 }
1834
1835 # We expect three device-tree files in the output, one after the other.
1836 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1837 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1838 # main U-Boot tree. All three should have the same postions and offset.
1839 start = 0
1840 for item in ['', 'spl', 'tpl']:
1841 dtb = fdt.Fdt.FromData(data[start:])
1842 dtb.Scan()
Simon Glass12bb1a92019-07-20 12:23:51 -06001843 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
1844 ['spl', 'tpl'])
Simon Glass6ed45ba2018-09-14 04:57:24 -06001845 expected = dict(base_expected)
1846 if item:
1847 expected[item] = 0
1848 self.assertEqual(expected, props)
1849 start += dtb._fdt_obj.totalsize()
1850
1851 def testUpdateFdtOutput(self):
1852 """Test that output DTB files are updated"""
1853 try:
Simon Glass741f2d62018-10-01 12:22:30 -06001854 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glass6ed45ba2018-09-14 04:57:24 -06001855 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1856
1857 # Unfortunately, compiling a source file always results in a file
1858 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass741f2d62018-10-01 12:22:30 -06001859 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glass6ed45ba2018-09-14 04:57:24 -06001860 # binman as a file called u-boot.dtb. To fix this, copy the file
1861 # over to the expected place.
Simon Glass6ed45ba2018-09-14 04:57:24 -06001862 start = 0
1863 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1864 'tpl/u-boot-tpl.dtb.out']:
1865 dtb = fdt.Fdt.FromData(data[start:])
1866 size = dtb._fdt_obj.totalsize()
1867 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1868 outdata = tools.ReadFile(pathname)
1869 name = os.path.split(fname)[0]
1870
1871 if name:
1872 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1873 else:
1874 orig_indata = dtb_data
1875 self.assertNotEqual(outdata, orig_indata,
1876 "Expected output file '%s' be updated" % pathname)
1877 self.assertEqual(outdata, data[start:start + size],
1878 "Expected output file '%s' to match output image" %
1879 pathname)
1880 start += size
1881 finally:
1882 self._ResetDtbs()
1883
Simon Glass83d73c22018-09-14 04:57:26 -06001884 def _decompress(self, data):
Simon Glassff5c7e32019-07-08 13:18:42 -06001885 return tools.Decompress(data, 'lz4')
Simon Glass83d73c22018-09-14 04:57:26 -06001886
1887 def testCompress(self):
1888 """Test compression of blobs"""
Simon Glassac62fba2019-07-08 13:18:53 -06001889 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06001890 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass83d73c22018-09-14 04:57:26 -06001891 use_real_dtb=True, update_dtb=True)
1892 dtb = fdt.Fdt(out_dtb_fname)
1893 dtb.Scan()
1894 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1895 orig = self._decompress(data)
1896 self.assertEquals(COMPRESS_DATA, orig)
Simon Glass97c3e9a2020-10-26 17:40:15 -06001897
1898 # Do a sanity check on various fields
1899 image = control.images['image']
1900 entries = image.GetEntries()
1901 self.assertEqual(1, len(entries))
1902
1903 entry = entries['blob']
1904 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
1905 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
1906 orig = self._decompress(entry.data)
1907 self.assertEqual(orig, entry.uncomp_data)
1908
Simon Glass63e7ba62020-10-26 17:40:16 -06001909 self.assertEqual(image.data, entry.data)
1910
Simon Glass83d73c22018-09-14 04:57:26 -06001911 expected = {
1912 'blob:uncomp-size': len(COMPRESS_DATA),
1913 'blob:size': len(data),
1914 'size': len(data),
1915 }
1916 self.assertEqual(expected, props)
1917
Simon Glass0a98b282018-09-14 04:57:28 -06001918 def testFiles(self):
1919 """Test bringing in multiple files"""
Simon Glass741f2d62018-10-01 12:22:30 -06001920 data = self._DoReadFile('084_files.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001921 self.assertEqual(FILES_DATA, data)
1922
1923 def testFilesCompress(self):
1924 """Test bringing in multiple files and compressing them"""
Simon Glassac62fba2019-07-08 13:18:53 -06001925 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06001926 data = self._DoReadFile('085_files_compress.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001927
1928 image = control.images['image']
1929 entries = image.GetEntries()
1930 files = entries['files']
Simon Glass8beb11e2019-07-08 14:25:47 -06001931 entries = files._entries
Simon Glass0a98b282018-09-14 04:57:28 -06001932
Simon Glassc6c10e72019-05-17 22:00:46 -06001933 orig = b''
Simon Glass0a98b282018-09-14 04:57:28 -06001934 for i in range(1, 3):
1935 key = '%d.dat' % i
1936 start = entries[key].image_pos
1937 len = entries[key].size
1938 chunk = data[start:start + len]
1939 orig += self._decompress(chunk)
1940
1941 self.assertEqual(FILES_DATA, orig)
1942
1943 def testFilesMissing(self):
1944 """Test missing files"""
1945 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001946 data = self._DoReadFile('086_files_none.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001947 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1948 'no files', str(e.exception))
1949
1950 def testFilesNoPattern(self):
1951 """Test missing files"""
1952 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001953 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001954 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1955 str(e.exception))
1956
Simon Glassba64a0b2018-09-14 04:57:29 -06001957 def testExpandSize(self):
1958 """Test an expanding entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001959 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
Simon Glassba64a0b2018-09-14 04:57:29 -06001960 map=True)
Simon Glassc6c10e72019-05-17 22:00:46 -06001961 expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA +
1962 MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA +
1963 tools.GetBytes(ord('c'), 8) + U_BOOT_DATA +
1964 tools.GetBytes(ord('d'), 8))
Simon Glassba64a0b2018-09-14 04:57:29 -06001965 self.assertEqual(expect, data)
1966 self.assertEqual('''ImagePos Offset Size Name
196700000000 00000000 00000028 main-section
196800000000 00000000 00000008 fill
196900000008 00000008 00000004 u-boot
19700000000c 0000000c 00000004 section
19710000000c 00000000 00000003 intel-mrc
197200000010 00000010 00000004 u-boot2
197300000014 00000014 0000000c section2
197400000014 00000000 00000008 fill
19750000001c 00000008 00000004 u-boot
197600000020 00000020 00000008 fill2
1977''', map_data)
1978
1979 def testExpandSizeBad(self):
1980 """Test an expanding entry which fails to provide contents"""
Simon Glass163ed6c2018-09-14 04:57:36 -06001981 with test_util.capture_sys_output() as (stdout, stderr):
1982 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001983 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
Simon Glassba64a0b2018-09-14 04:57:29 -06001984 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
1985 'expanding entry', str(e.exception))
1986
Simon Glasse0e5df92018-09-14 04:57:31 -06001987 def testHash(self):
1988 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001989 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06001990 use_real_dtb=True, update_dtb=True)
1991 dtb = fdt.Fdt(out_dtb_fname)
1992 dtb.Scan()
1993 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
1994 m = hashlib.sha256()
1995 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001996 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06001997
1998 def testHashNoAlgo(self):
1999 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002000 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06002001 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2002 'hash node', str(e.exception))
2003
2004 def testHashBadAlgo(self):
2005 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002006 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06002007 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
2008 str(e.exception))
2009
2010 def testHashSection(self):
2011 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06002012 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06002013 use_real_dtb=True, update_dtb=True)
2014 dtb = fdt.Fdt(out_dtb_fname)
2015 dtb.Scan()
2016 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2017 m = hashlib.sha256()
2018 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06002019 m.update(tools.GetBytes(ord('a'), 16))
2020 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06002021
Simon Glassf0253632018-09-14 04:57:32 -06002022 def testPackUBootTplMicrocode(self):
2023 """Test that x86 microcode can be handled correctly in TPL
2024
2025 We expect to see the following in the image, in order:
2026 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2027 place
2028 u-boot-tpl.dtb with the microcode removed
2029 the microcode
2030 """
Simon Glass2090f1e2019-08-24 07:23:00 -06002031 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass741f2d62018-10-01 12:22:30 -06002032 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glassf0253632018-09-14 04:57:32 -06002033 U_BOOT_TPL_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06002034 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2035 b'ter somewhere in here', first)
Simon Glassf0253632018-09-14 04:57:32 -06002036
Simon Glassf8f8df62018-09-14 04:57:34 -06002037 def testFmapX86(self):
2038 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06002039 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassf8f8df62018-09-14 04:57:34 -06002040 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc6c10e72019-05-17 22:00:46 -06002041 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06002042 self.assertEqual(expected, data[:32])
2043 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2044
2045 self.assertEqual(0x100, fhdr.image_size)
2046
2047 self.assertEqual(0, fentries[0].offset)
2048 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06002049 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06002050
2051 self.assertEqual(4, fentries[1].offset)
2052 self.assertEqual(3, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06002053 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06002054
2055 self.assertEqual(32, fentries[2].offset)
2056 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2057 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06002058 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06002059
2060 def testFmapX86Section(self):
2061 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06002062 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glassc6c10e72019-05-17 22:00:46 -06002063 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06002064 self.assertEqual(expected, data[:32])
2065 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2066
2067 self.assertEqual(0x100, fhdr.image_size)
2068
2069 self.assertEqual(0, fentries[0].offset)
2070 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06002071 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06002072
2073 self.assertEqual(4, fentries[1].offset)
2074 self.assertEqual(3, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06002075 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06002076
2077 self.assertEqual(36, fentries[2].offset)
2078 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2079 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06002080 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06002081
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002082 def testElf(self):
2083 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06002084 self._SetupSplElf()
Simon Glass2090f1e2019-08-24 07:23:00 -06002085 self._SetupTplElf()
Simon Glass53e22bf2019-08-24 07:22:53 -06002086 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002087 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06002088 data = self._DoReadFile('096_elf.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002089
Simon Glass093d1682019-07-08 13:18:25 -06002090 def testElfStrip(self):
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002091 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06002092 self._SetupSplElf()
Simon Glass53e22bf2019-08-24 07:22:53 -06002093 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002094 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06002095 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002096
Simon Glass163ed6c2018-09-14 04:57:36 -06002097 def testPackOverlapMap(self):
2098 """Test that overlapping regions are detected"""
2099 with test_util.capture_sys_output() as (stdout, stderr):
2100 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002101 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glass163ed6c2018-09-14 04:57:36 -06002102 map_fname = tools.GetOutputFilename('image.map')
2103 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2104 stdout.getvalue())
2105
2106 # We should not get an inmage, but there should be a map file
2107 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
2108 self.assertTrue(os.path.exists(map_fname))
Simon Glasseb546ac2019-05-17 22:00:51 -06002109 map_data = tools.ReadFile(map_fname, binary=False)
Simon Glass163ed6c2018-09-14 04:57:36 -06002110 self.assertEqual('''ImagePos Offset Size Name
Simon Glass0ff83da2020-10-26 17:40:24 -06002111<none> 00000000 00000008 main-section
Simon Glass163ed6c2018-09-14 04:57:36 -06002112<none> 00000000 00000004 u-boot
2113<none> 00000003 00000004 u-boot-align
2114''', map_data)
2115
Simon Glass093d1682019-07-08 13:18:25 -06002116 def testPackRefCode(self):
Simon Glass3ae192c2018-10-01 12:22:31 -06002117 """Test that an image with an Intel Reference code binary works"""
2118 data = self._DoReadFile('100_intel_refcode.dts')
2119 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2120
Simon Glass9481c802019-04-25 21:58:39 -06002121 def testSectionOffset(self):
2122 """Tests use of a section with an offset"""
2123 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2124 map=True)
2125 self.assertEqual('''ImagePos Offset Size Name
212600000000 00000000 00000038 main-section
212700000004 00000004 00000010 section@0
212800000004 00000000 00000004 u-boot
212900000018 00000018 00000010 section@1
213000000018 00000000 00000004 u-boot
21310000002c 0000002c 00000004 section@2
21320000002c 00000000 00000004 u-boot
2133''', map_data)
2134 self.assertEqual(data,
Simon Glasse6d85ff2019-05-14 15:53:47 -06002135 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2136 tools.GetBytes(0x21, 12) +
2137 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2138 tools.GetBytes(0x61, 12) +
2139 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2140 tools.GetBytes(0x26, 8))
Simon Glass9481c802019-04-25 21:58:39 -06002141
Simon Glassac62fba2019-07-08 13:18:53 -06002142 def testCbfsRaw(self):
2143 """Test base handling of a Coreboot Filesystem (CBFS)
2144
2145 The exact contents of the CBFS is verified by similar tests in
2146 cbfs_util_test.py. The tests here merely check that the files added to
2147 the CBFS can be found in the final image.
2148 """
2149 data = self._DoReadFile('102_cbfs_raw.dts')
2150 size = 0xb0
2151
2152 cbfs = cbfs_util.CbfsReader(data)
2153 self.assertEqual(size, cbfs.rom_size)
2154
2155 self.assertIn('u-boot-dtb', cbfs.files)
2156 cfile = cbfs.files['u-boot-dtb']
2157 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2158
2159 def testCbfsArch(self):
2160 """Test on non-x86 architecture"""
2161 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2162 size = 0x100
2163
2164 cbfs = cbfs_util.CbfsReader(data)
2165 self.assertEqual(size, cbfs.rom_size)
2166
2167 self.assertIn('u-boot-dtb', cbfs.files)
2168 cfile = cbfs.files['u-boot-dtb']
2169 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2170
2171 def testCbfsStage(self):
2172 """Tests handling of a Coreboot Filesystem (CBFS)"""
2173 if not elf.ELF_TOOLS:
2174 self.skipTest('Python elftools not available')
2175 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2176 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2177 size = 0xb0
2178
2179 data = self._DoReadFile('104_cbfs_stage.dts')
2180 cbfs = cbfs_util.CbfsReader(data)
2181 self.assertEqual(size, cbfs.rom_size)
2182
2183 self.assertIn('u-boot', cbfs.files)
2184 cfile = cbfs.files['u-boot']
2185 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2186
2187 def testCbfsRawCompress(self):
2188 """Test handling of compressing raw files"""
2189 self._CheckLz4()
2190 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2191 size = 0x140
2192
2193 cbfs = cbfs_util.CbfsReader(data)
2194 self.assertIn('u-boot', cbfs.files)
2195 cfile = cbfs.files['u-boot']
2196 self.assertEqual(COMPRESS_DATA, cfile.data)
2197
2198 def testCbfsBadArch(self):
2199 """Test handling of a bad architecture"""
2200 with self.assertRaises(ValueError) as e:
2201 self._DoReadFile('106_cbfs_bad_arch.dts')
2202 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2203
2204 def testCbfsNoSize(self):
2205 """Test handling of a missing size property"""
2206 with self.assertRaises(ValueError) as e:
2207 self._DoReadFile('107_cbfs_no_size.dts')
2208 self.assertIn('entry must have a size property', str(e.exception))
2209
2210 def testCbfsNoCOntents(self):
2211 """Test handling of a CBFS entry which does not provide contentsy"""
2212 with self.assertRaises(ValueError) as e:
2213 self._DoReadFile('108_cbfs_no_contents.dts')
2214 self.assertIn('Could not complete processing of contents',
2215 str(e.exception))
2216
2217 def testCbfsBadCompress(self):
2218 """Test handling of a bad architecture"""
2219 with self.assertRaises(ValueError) as e:
2220 self._DoReadFile('109_cbfs_bad_compress.dts')
2221 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2222 str(e.exception))
2223
2224 def testCbfsNamedEntries(self):
2225 """Test handling of named entries"""
2226 data = self._DoReadFile('110_cbfs_name.dts')
2227
2228 cbfs = cbfs_util.CbfsReader(data)
2229 self.assertIn('FRED', cbfs.files)
2230 cfile1 = cbfs.files['FRED']
2231 self.assertEqual(U_BOOT_DATA, cfile1.data)
2232
2233 self.assertIn('hello', cbfs.files)
2234 cfile2 = cbfs.files['hello']
2235 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2236
Simon Glassc5ac1382019-07-08 13:18:54 -06002237 def _SetupIfwi(self, fname):
2238 """Set up to run an IFWI test
2239
2240 Args:
2241 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2242 """
2243 self._SetupSplElf()
Simon Glass2090f1e2019-08-24 07:23:00 -06002244 self._SetupTplElf()
Simon Glassc5ac1382019-07-08 13:18:54 -06002245
2246 # Intel Integrated Firmware Image (IFWI) file
2247 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2248 data = fd.read()
2249 TestFunctional._MakeInputFile(fname,data)
2250
2251 def _CheckIfwi(self, data):
2252 """Check that an image with an IFWI contains the correct output
2253
2254 Args:
2255 data: Conents of output file
2256 """
2257 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
2258 if data[:0x1000] != expected_desc:
2259 self.fail('Expected descriptor binary at start of image')
2260
2261 # We expect to find the TPL wil in subpart IBBP entry IBBL
2262 image_fname = tools.GetOutputFilename('image.bin')
2263 tpl_fname = tools.GetOutputFilename('tpl.out')
2264 tools.RunIfwiTool(image_fname, tools.CMD_EXTRACT, fname=tpl_fname,
2265 subpart='IBBP', entry_name='IBBL')
2266
2267 tpl_data = tools.ReadFile(tpl_fname)
Simon Glasse95be632019-08-24 07:22:51 -06002268 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glassc5ac1382019-07-08 13:18:54 -06002269
2270 def testPackX86RomIfwi(self):
2271 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2272 self._SetupIfwi('fitimage.bin')
Simon Glass9255f3c2019-08-24 07:23:01 -06002273 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002274 self._CheckIfwi(data)
2275
2276 def testPackX86RomIfwiNoDesc(self):
2277 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2278 self._SetupIfwi('ifwi.bin')
Simon Glass9255f3c2019-08-24 07:23:01 -06002279 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002280 self._CheckIfwi(data)
2281
2282 def testPackX86RomIfwiNoData(self):
2283 """Test that an x86 ROM with IFWI handles missing data"""
2284 self._SetupIfwi('ifwi.bin')
2285 with self.assertRaises(ValueError) as e:
Simon Glass9255f3c2019-08-24 07:23:01 -06002286 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002287 self.assertIn('Could not complete processing of contents',
2288 str(e.exception))
Simon Glass53af22a2018-07-17 13:25:32 -06002289
Simon Glasse073d4e2019-07-08 13:18:56 -06002290 def testCbfsOffset(self):
2291 """Test a CBFS with files at particular offsets
2292
2293 Like all CFBS tests, this is just checking the logic that calls
2294 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2295 """
2296 data = self._DoReadFile('114_cbfs_offset.dts')
2297 size = 0x200
2298
2299 cbfs = cbfs_util.CbfsReader(data)
2300 self.assertEqual(size, cbfs.rom_size)
2301
2302 self.assertIn('u-boot', cbfs.files)
2303 cfile = cbfs.files['u-boot']
2304 self.assertEqual(U_BOOT_DATA, cfile.data)
2305 self.assertEqual(0x40, cfile.cbfs_offset)
2306
2307 self.assertIn('u-boot-dtb', cbfs.files)
2308 cfile2 = cbfs.files['u-boot-dtb']
2309 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2310 self.assertEqual(0x140, cfile2.cbfs_offset)
2311
Simon Glass086cec92019-07-08 14:25:27 -06002312 def testFdtmap(self):
2313 """Test an FDT map can be inserted in the image"""
2314 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2315 fdtmap_data = data[len(U_BOOT_DATA):]
2316 magic = fdtmap_data[:8]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002317 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass086cec92019-07-08 14:25:27 -06002318 self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
2319
2320 fdt_data = fdtmap_data[16:]
2321 dtb = fdt.Fdt.FromData(fdt_data)
2322 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002323 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass086cec92019-07-08 14:25:27 -06002324 self.assertEqual({
2325 'image-pos': 0,
2326 'offset': 0,
2327 'u-boot:offset': 0,
2328 'u-boot:size': len(U_BOOT_DATA),
2329 'u-boot:image-pos': 0,
2330 'fdtmap:image-pos': 4,
2331 'fdtmap:offset': 4,
2332 'fdtmap:size': len(fdtmap_data),
2333 'size': len(data),
2334 }, props)
2335
2336 def testFdtmapNoMatch(self):
2337 """Check handling of an FDT map when the section cannot be found"""
2338 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2339
2340 # Mangle the section name, which should cause a mismatch between the
2341 # correct FDT path and the one expected by the section
2342 image = control.images['image']
Simon Glasscf228942019-07-08 14:25:28 -06002343 image._node.path += '-suffix'
Simon Glass086cec92019-07-08 14:25:27 -06002344 entries = image.GetEntries()
2345 fdtmap = entries['fdtmap']
2346 with self.assertRaises(ValueError) as e:
2347 fdtmap._GetFdtmap()
2348 self.assertIn("Cannot locate node for path '/binman-suffix'",
2349 str(e.exception))
2350
Simon Glasscf228942019-07-08 14:25:28 -06002351 def testFdtmapHeader(self):
2352 """Test an FDT map and image header can be inserted in the image"""
2353 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2354 fdtmap_pos = len(U_BOOT_DATA)
2355 fdtmap_data = data[fdtmap_pos:]
2356 fdt_data = fdtmap_data[16:]
2357 dtb = fdt.Fdt.FromData(fdt_data)
2358 fdt_size = dtb.GetFdtObj().totalsize()
2359 hdr_data = data[-8:]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002360 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002361 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2362 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2363
2364 def testFdtmapHeaderStart(self):
2365 """Test an image header can be inserted at the image start"""
2366 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2367 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2368 hdr_data = data[:8]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002369 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002370 offset = struct.unpack('<I', hdr_data[4:])[0]
2371 self.assertEqual(fdtmap_pos, offset)
2372
2373 def testFdtmapHeaderPos(self):
2374 """Test an image header can be inserted at a chosen position"""
2375 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2376 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2377 hdr_data = data[0x80:0x88]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002378 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002379 offset = struct.unpack('<I', hdr_data[4:])[0]
2380 self.assertEqual(fdtmap_pos, offset)
2381
2382 def testHeaderMissingFdtmap(self):
2383 """Test an image header requires an fdtmap"""
2384 with self.assertRaises(ValueError) as e:
2385 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2386 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2387 str(e.exception))
2388
2389 def testHeaderNoLocation(self):
2390 """Test an image header with a no specified location is detected"""
2391 with self.assertRaises(ValueError) as e:
2392 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2393 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2394 str(e.exception))
2395
Simon Glassc52c9e72019-07-08 14:25:37 -06002396 def testEntryExpand(self):
2397 """Test expanding an entry after it is packed"""
2398 data = self._DoReadFile('121_entry_expand.dts')
Simon Glass79d3c582019-07-20 12:23:57 -06002399 self.assertEqual(b'aaa', data[:3])
2400 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2401 self.assertEqual(b'aaa', data[-3:])
Simon Glassc52c9e72019-07-08 14:25:37 -06002402
2403 def testEntryExpandBad(self):
2404 """Test expanding an entry after it is packed, twice"""
2405 with self.assertRaises(ValueError) as e:
2406 self._DoReadFile('122_entry_expand_twice.dts')
Simon Glass61ec04f2019-07-20 12:23:58 -06002407 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glassc52c9e72019-07-08 14:25:37 -06002408 str(e.exception))
2409
2410 def testEntryExpandSection(self):
2411 """Test expanding an entry within a section after it is packed"""
2412 data = self._DoReadFile('123_entry_expand_section.dts')
Simon Glass79d3c582019-07-20 12:23:57 -06002413 self.assertEqual(b'aaa', data[:3])
2414 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2415 self.assertEqual(b'aaa', data[-3:])
Simon Glassc52c9e72019-07-08 14:25:37 -06002416
Simon Glass6c223fd2019-07-08 14:25:38 -06002417 def testCompressDtb(self):
2418 """Test that compress of device-tree files is supported"""
2419 self._CheckLz4()
2420 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2421 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2422 comp_data = data[len(U_BOOT_DATA):]
2423 orig = self._decompress(comp_data)
2424 dtb = fdt.Fdt.FromData(orig)
2425 dtb.Scan()
2426 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2427 expected = {
2428 'u-boot:size': len(U_BOOT_DATA),
2429 'u-boot-dtb:uncomp-size': len(orig),
2430 'u-boot-dtb:size': len(comp_data),
2431 'size': len(data),
2432 }
2433 self.assertEqual(expected, props)
2434
Simon Glass69f7cb32019-07-08 14:25:41 -06002435 def testCbfsUpdateFdt(self):
2436 """Test that we can update the device tree with CBFS offset/size info"""
2437 self._CheckLz4()
2438 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2439 update_dtb=True)
2440 dtb = fdt.Fdt(out_dtb_fname)
2441 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002442 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass69f7cb32019-07-08 14:25:41 -06002443 del props['cbfs/u-boot:size']
2444 self.assertEqual({
2445 'offset': 0,
2446 'size': len(data),
2447 'image-pos': 0,
2448 'cbfs:offset': 0,
2449 'cbfs:size': len(data),
2450 'cbfs:image-pos': 0,
2451 'cbfs/u-boot:offset': 0x38,
2452 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2453 'cbfs/u-boot:image-pos': 0x38,
2454 'cbfs/u-boot-dtb:offset': 0xb8,
2455 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2456 'cbfs/u-boot-dtb:image-pos': 0xb8,
2457 }, props)
2458
Simon Glass8a1ad062019-07-08 14:25:42 -06002459 def testCbfsBadType(self):
2460 """Test an image header with a no specified location is detected"""
2461 with self.assertRaises(ValueError) as e:
2462 self._DoReadFile('126_cbfs_bad_type.dts')
2463 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2464
Simon Glass41b8ba02019-07-08 14:25:43 -06002465 def testList(self):
2466 """Test listing the files in an image"""
2467 self._CheckLz4()
2468 data = self._DoReadFile('127_list.dts')
2469 image = control.images['image']
2470 entries = image.BuildEntryList()
2471 self.assertEqual(7, len(entries))
2472
2473 ent = entries[0]
2474 self.assertEqual(0, ent.indent)
2475 self.assertEqual('main-section', ent.name)
2476 self.assertEqual('section', ent.etype)
2477 self.assertEqual(len(data), ent.size)
2478 self.assertEqual(0, ent.image_pos)
2479 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002480 self.assertEqual(0, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002481
2482 ent = entries[1]
2483 self.assertEqual(1, ent.indent)
2484 self.assertEqual('u-boot', ent.name)
2485 self.assertEqual('u-boot', ent.etype)
2486 self.assertEqual(len(U_BOOT_DATA), ent.size)
2487 self.assertEqual(0, ent.image_pos)
2488 self.assertEqual(None, ent.uncomp_size)
2489 self.assertEqual(0, ent.offset)
2490
2491 ent = entries[2]
2492 self.assertEqual(1, ent.indent)
2493 self.assertEqual('section', ent.name)
2494 self.assertEqual('section', ent.etype)
2495 section_size = ent.size
2496 self.assertEqual(0x100, ent.image_pos)
2497 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002498 self.assertEqual(0x100, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002499
2500 ent = entries[3]
2501 self.assertEqual(2, ent.indent)
2502 self.assertEqual('cbfs', ent.name)
2503 self.assertEqual('cbfs', ent.etype)
2504 self.assertEqual(0x400, ent.size)
2505 self.assertEqual(0x100, ent.image_pos)
2506 self.assertEqual(None, ent.uncomp_size)
2507 self.assertEqual(0, ent.offset)
2508
2509 ent = entries[4]
2510 self.assertEqual(3, ent.indent)
2511 self.assertEqual('u-boot', ent.name)
2512 self.assertEqual('u-boot', ent.etype)
2513 self.assertEqual(len(U_BOOT_DATA), ent.size)
2514 self.assertEqual(0x138, ent.image_pos)
2515 self.assertEqual(None, ent.uncomp_size)
2516 self.assertEqual(0x38, ent.offset)
2517
2518 ent = entries[5]
2519 self.assertEqual(3, ent.indent)
2520 self.assertEqual('u-boot-dtb', ent.name)
2521 self.assertEqual('text', ent.etype)
2522 self.assertGreater(len(COMPRESS_DATA), ent.size)
2523 self.assertEqual(0x178, ent.image_pos)
2524 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2525 self.assertEqual(0x78, ent.offset)
2526
2527 ent = entries[6]
2528 self.assertEqual(2, ent.indent)
2529 self.assertEqual('u-boot-dtb', ent.name)
2530 self.assertEqual('u-boot-dtb', ent.etype)
2531 self.assertEqual(0x500, ent.image_pos)
2532 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2533 dtb_size = ent.size
2534 # Compressing this data expands it since headers are added
2535 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2536 self.assertEqual(0x400, ent.offset)
2537
2538 self.assertEqual(len(data), 0x100 + section_size)
2539 self.assertEqual(section_size, 0x400 + dtb_size)
2540
Simon Glasse1925fa2019-07-08 14:25:44 -06002541 def testFindFdtmap(self):
2542 """Test locating an FDT map in an image"""
2543 self._CheckLz4()
2544 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2545 image = control.images['image']
2546 entries = image.GetEntries()
2547 entry = entries['fdtmap']
2548 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2549
2550 def testFindFdtmapMissing(self):
2551 """Test failing to locate an FDP map"""
2552 data = self._DoReadFile('005_simple.dts')
2553 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2554
Simon Glass2d260032019-07-08 14:25:45 -06002555 def testFindImageHeader(self):
2556 """Test locating a image header"""
2557 self._CheckLz4()
Simon Glassffded752019-07-08 14:25:46 -06002558 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002559 image = control.images['image']
2560 entries = image.GetEntries()
2561 entry = entries['fdtmap']
2562 # The header should point to the FDT map
2563 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2564
2565 def testFindImageHeaderStart(self):
2566 """Test locating a image header located at the start of an image"""
Simon Glassffded752019-07-08 14:25:46 -06002567 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002568 image = control.images['image']
2569 entries = image.GetEntries()
2570 entry = entries['fdtmap']
2571 # The header should point to the FDT map
2572 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2573
2574 def testFindImageHeaderMissing(self):
2575 """Test failing to locate an image header"""
2576 data = self._DoReadFile('005_simple.dts')
2577 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2578
Simon Glassffded752019-07-08 14:25:46 -06002579 def testReadImage(self):
2580 """Test reading an image and accessing its FDT map"""
2581 self._CheckLz4()
2582 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2583 image_fname = tools.GetOutputFilename('image.bin')
2584 orig_image = control.images['image']
2585 image = Image.FromFile(image_fname)
2586 self.assertEqual(orig_image.GetEntries().keys(),
2587 image.GetEntries().keys())
2588
2589 orig_entry = orig_image.GetEntries()['fdtmap']
2590 entry = image.GetEntries()['fdtmap']
2591 self.assertEquals(orig_entry.offset, entry.offset)
2592 self.assertEquals(orig_entry.size, entry.size)
2593 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2594
2595 def testReadImageNoHeader(self):
2596 """Test accessing an image's FDT map without an image header"""
2597 self._CheckLz4()
2598 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
2599 image_fname = tools.GetOutputFilename('image.bin')
2600 image = Image.FromFile(image_fname)
2601 self.assertTrue(isinstance(image, Image))
Simon Glass10f9d002019-07-20 12:23:50 -06002602 self.assertEqual('image', image.image_name[-5:])
Simon Glassffded752019-07-08 14:25:46 -06002603
2604 def testReadImageFail(self):
2605 """Test failing to read an image image's FDT map"""
2606 self._DoReadFile('005_simple.dts')
2607 image_fname = tools.GetOutputFilename('image.bin')
2608 with self.assertRaises(ValueError) as e:
2609 image = Image.FromFile(image_fname)
2610 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glasse073d4e2019-07-08 13:18:56 -06002611
Simon Glass61f564d2019-07-08 14:25:48 -06002612 def testListCmd(self):
2613 """Test listing the files in an image using an Fdtmap"""
2614 self._CheckLz4()
2615 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2616
2617 # lz4 compression size differs depending on the version
2618 image = control.images['image']
2619 entries = image.GetEntries()
2620 section_size = entries['section'].size
2621 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2622 fdtmap_offset = entries['fdtmap'].offset
2623
Simon Glassf86a7362019-07-20 12:24:10 -06002624 try:
2625 tmpdir, updated_fname = self._SetupImageInTmpdir()
2626 with test_util.capture_sys_output() as (stdout, stderr):
2627 self._DoBinman('ls', '-i', updated_fname)
2628 finally:
2629 shutil.rmtree(tmpdir)
Simon Glass61f564d2019-07-08 14:25:48 -06002630 lines = stdout.getvalue().splitlines()
2631 expected = [
2632'Name Image-pos Size Entry-type Offset Uncomp-size',
2633'----------------------------------------------------------------------',
2634'main-section 0 c00 section 0',
2635' u-boot 0 4 u-boot 0',
2636' section 100 %x section 100' % section_size,
2637' cbfs 100 400 cbfs 0',
2638' u-boot 138 4 u-boot 38',
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002639' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glass61f564d2019-07-08 14:25:48 -06002640' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002641' fdtmap %x 3bd fdtmap %x' %
Simon Glass61f564d2019-07-08 14:25:48 -06002642 (fdtmap_offset, fdtmap_offset),
2643' image-header bf8 8 image-header bf8',
2644 ]
2645 self.assertEqual(expected, lines)
2646
2647 def testListCmdFail(self):
2648 """Test failing to list an image"""
2649 self._DoReadFile('005_simple.dts')
Simon Glassf86a7362019-07-20 12:24:10 -06002650 try:
2651 tmpdir, updated_fname = self._SetupImageInTmpdir()
2652 with self.assertRaises(ValueError) as e:
2653 self._DoBinman('ls', '-i', updated_fname)
2654 finally:
2655 shutil.rmtree(tmpdir)
Simon Glass61f564d2019-07-08 14:25:48 -06002656 self.assertIn("Cannot find FDT map in image", str(e.exception))
2657
2658 def _RunListCmd(self, paths, expected):
2659 """List out entries and check the result
2660
2661 Args:
2662 paths: List of paths to pass to the list command
2663 expected: Expected list of filenames to be returned, in order
2664 """
2665 self._CheckLz4()
2666 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2667 image_fname = tools.GetOutputFilename('image.bin')
2668 image = Image.FromFile(image_fname)
2669 lines = image.GetListEntries(paths)[1]
2670 files = [line[0].strip() for line in lines[1:]]
2671 self.assertEqual(expected, files)
2672
2673 def testListCmdSection(self):
2674 """Test listing the files in a section"""
2675 self._RunListCmd(['section'],
2676 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2677
2678 def testListCmdFile(self):
2679 """Test listing a particular file"""
2680 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2681
2682 def testListCmdWildcard(self):
2683 """Test listing a wildcarded file"""
2684 self._RunListCmd(['*boot*'],
2685 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2686
2687 def testListCmdWildcardMulti(self):
2688 """Test listing a wildcarded file"""
2689 self._RunListCmd(['*cb*', '*head*'],
2690 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2691
2692 def testListCmdEmpty(self):
2693 """Test listing a wildcarded file"""
2694 self._RunListCmd(['nothing'], [])
2695
2696 def testListCmdPath(self):
2697 """Test listing the files in a sub-entry of a section"""
2698 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2699
Simon Glassf667e452019-07-08 14:25:50 -06002700 def _RunExtractCmd(self, entry_name, decomp=True):
2701 """Extract an entry from an image
2702
2703 Args:
2704 entry_name: Entry name to extract
2705 decomp: True to decompress the data if compressed, False to leave
2706 it in its raw uncompressed format
2707
2708 Returns:
2709 data from entry
2710 """
2711 self._CheckLz4()
2712 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2713 image_fname = tools.GetOutputFilename('image.bin')
2714 return control.ReadEntry(image_fname, entry_name, decomp)
2715
2716 def testExtractSimple(self):
2717 """Test extracting a single file"""
2718 data = self._RunExtractCmd('u-boot')
2719 self.assertEqual(U_BOOT_DATA, data)
2720
Simon Glass71ce0ba2019-07-08 14:25:52 -06002721 def testExtractSection(self):
2722 """Test extracting the files in a section"""
2723 data = self._RunExtractCmd('section')
2724 cbfs_data = data[:0x400]
2725 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002726 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass71ce0ba2019-07-08 14:25:52 -06002727 dtb_data = data[0x400:]
2728 dtb = self._decompress(dtb_data)
2729 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2730
2731 def testExtractCompressed(self):
2732 """Test extracting compressed data"""
2733 data = self._RunExtractCmd('section/u-boot-dtb')
2734 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2735
2736 def testExtractRaw(self):
2737 """Test extracting compressed data without decompressing it"""
2738 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2739 dtb = self._decompress(data)
2740 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2741
2742 def testExtractCbfs(self):
2743 """Test extracting CBFS data"""
2744 data = self._RunExtractCmd('section/cbfs/u-boot')
2745 self.assertEqual(U_BOOT_DATA, data)
2746
2747 def testExtractCbfsCompressed(self):
2748 """Test extracting CBFS compressed data"""
2749 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2750 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2751
2752 def testExtractCbfsRaw(self):
2753 """Test extracting CBFS compressed data without decompressing it"""
2754 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Simon Glasseb0f4a42019-07-20 12:24:06 -06002755 dtb = tools.Decompress(data, 'lzma', with_header=False)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002756 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2757
Simon Glassf667e452019-07-08 14:25:50 -06002758 def testExtractBadEntry(self):
2759 """Test extracting a bad section path"""
2760 with self.assertRaises(ValueError) as e:
2761 self._RunExtractCmd('section/does-not-exist')
2762 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2763 str(e.exception))
2764
2765 def testExtractMissingFile(self):
2766 """Test extracting file that does not exist"""
2767 with self.assertRaises(IOError) as e:
2768 control.ReadEntry('missing-file', 'name')
2769
2770 def testExtractBadFile(self):
2771 """Test extracting an invalid file"""
2772 fname = os.path.join(self._indir, 'badfile')
2773 tools.WriteFile(fname, b'')
2774 with self.assertRaises(ValueError) as e:
2775 control.ReadEntry(fname, 'name')
2776
Simon Glass71ce0ba2019-07-08 14:25:52 -06002777 def testExtractCmd(self):
2778 """Test extracting a file fron an image on the command line"""
2779 self._CheckLz4()
2780 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass71ce0ba2019-07-08 14:25:52 -06002781 fname = os.path.join(self._indir, 'output.extact')
Simon Glassf86a7362019-07-20 12:24:10 -06002782 try:
2783 tmpdir, updated_fname = self._SetupImageInTmpdir()
2784 with test_util.capture_sys_output() as (stdout, stderr):
2785 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2786 '-f', fname)
2787 finally:
2788 shutil.rmtree(tmpdir)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002789 data = tools.ReadFile(fname)
2790 self.assertEqual(U_BOOT_DATA, data)
2791
2792 def testExtractOneEntry(self):
2793 """Test extracting a single entry fron an image """
2794 self._CheckLz4()
2795 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2796 image_fname = tools.GetOutputFilename('image.bin')
2797 fname = os.path.join(self._indir, 'output.extact')
2798 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
2799 data = tools.ReadFile(fname)
2800 self.assertEqual(U_BOOT_DATA, data)
2801
2802 def _CheckExtractOutput(self, decomp):
2803 """Helper to test file output with and without decompression
2804
2805 Args:
2806 decomp: True to decompress entry data, False to output it raw
2807 """
2808 def _CheckPresent(entry_path, expect_data, expect_size=None):
2809 """Check and remove expected file
2810
2811 This checks the data/size of a file and removes the file both from
2812 the outfiles set and from the output directory. Once all files are
2813 processed, both the set and directory should be empty.
2814
2815 Args:
2816 entry_path: Entry path
2817 expect_data: Data to expect in file, or None to skip check
2818 expect_size: Size of data to expect in file, or None to skip
2819 """
2820 path = os.path.join(outdir, entry_path)
2821 data = tools.ReadFile(path)
2822 os.remove(path)
2823 if expect_data:
2824 self.assertEqual(expect_data, data)
2825 elif expect_size:
2826 self.assertEqual(expect_size, len(data))
2827 outfiles.remove(path)
2828
2829 def _CheckDirPresent(name):
2830 """Remove expected directory
2831
2832 This gives an error if the directory does not exist as expected
2833
2834 Args:
2835 name: Name of directory to remove
2836 """
2837 path = os.path.join(outdir, name)
2838 os.rmdir(path)
2839
2840 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2841 image_fname = tools.GetOutputFilename('image.bin')
2842 outdir = os.path.join(self._indir, 'extract')
2843 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2844
2845 # Create a set of all file that were output (should be 9)
2846 outfiles = set()
2847 for root, dirs, files in os.walk(outdir):
2848 outfiles |= set([os.path.join(root, fname) for fname in files])
2849 self.assertEqual(9, len(outfiles))
2850 self.assertEqual(9, len(einfos))
2851
2852 image = control.images['image']
2853 entries = image.GetEntries()
2854
2855 # Check the 9 files in various ways
2856 section = entries['section']
2857 section_entries = section.GetEntries()
2858 cbfs_entries = section_entries['cbfs'].GetEntries()
2859 _CheckPresent('u-boot', U_BOOT_DATA)
2860 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
2861 dtb_len = EXTRACT_DTB_SIZE
2862 if not decomp:
2863 dtb_len = cbfs_entries['u-boot-dtb'].size
2864 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
2865 if not decomp:
2866 dtb_len = section_entries['u-boot-dtb'].size
2867 _CheckPresent('section/u-boot-dtb', None, dtb_len)
2868
2869 fdtmap = entries['fdtmap']
2870 _CheckPresent('fdtmap', fdtmap.data)
2871 hdr = entries['image-header']
2872 _CheckPresent('image-header', hdr.data)
2873
2874 _CheckPresent('section/root', section.data)
2875 cbfs = section_entries['cbfs']
2876 _CheckPresent('section/cbfs/root', cbfs.data)
2877 data = tools.ReadFile(image_fname)
2878 _CheckPresent('root', data)
2879
2880 # There should be no files left. Remove all the directories to check.
2881 # If there are any files/dirs remaining, one of these checks will fail.
2882 self.assertEqual(0, len(outfiles))
2883 _CheckDirPresent('section/cbfs')
2884 _CheckDirPresent('section')
2885 _CheckDirPresent('')
2886 self.assertFalse(os.path.exists(outdir))
2887
2888 def testExtractAllEntries(self):
2889 """Test extracting all entries"""
2890 self._CheckLz4()
2891 self._CheckExtractOutput(decomp=True)
2892
2893 def testExtractAllEntriesRaw(self):
2894 """Test extracting all entries without decompressing them"""
2895 self._CheckLz4()
2896 self._CheckExtractOutput(decomp=False)
2897
2898 def testExtractSelectedEntries(self):
2899 """Test extracting some entries"""
2900 self._CheckLz4()
2901 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2902 image_fname = tools.GetOutputFilename('image.bin')
2903 outdir = os.path.join(self._indir, 'extract')
2904 einfos = control.ExtractEntries(image_fname, None, outdir,
2905 ['*cb*', '*head*'])
2906
2907 # File output is tested by testExtractAllEntries(), so just check that
2908 # the expected entries are selected
2909 names = [einfo.name for einfo in einfos]
2910 self.assertEqual(names,
2911 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2912
2913 def testExtractNoEntryPaths(self):
2914 """Test extracting some entries"""
2915 self._CheckLz4()
2916 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2917 image_fname = tools.GetOutputFilename('image.bin')
2918 with self.assertRaises(ValueError) as e:
2919 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassbb5edc12019-07-20 12:24:14 -06002920 self.assertIn('Must specify an entry path to write with -f',
Simon Glass71ce0ba2019-07-08 14:25:52 -06002921 str(e.exception))
2922
2923 def testExtractTooManyEntryPaths(self):
2924 """Test extracting some entries"""
2925 self._CheckLz4()
2926 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2927 image_fname = tools.GetOutputFilename('image.bin')
2928 with self.assertRaises(ValueError) as e:
2929 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassbb5edc12019-07-20 12:24:14 -06002930 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass71ce0ba2019-07-08 14:25:52 -06002931 str(e.exception))
2932
Simon Glasse2705fa2019-07-08 14:25:53 -06002933 def testPackAlignSection(self):
2934 """Test that sections can have alignment"""
2935 self._DoReadFile('131_pack_align_section.dts')
2936
2937 self.assertIn('image', control.images)
2938 image = control.images['image']
2939 entries = image.GetEntries()
2940 self.assertEqual(3, len(entries))
2941
2942 # First u-boot
2943 self.assertIn('u-boot', entries)
2944 entry = entries['u-boot']
2945 self.assertEqual(0, entry.offset)
2946 self.assertEqual(0, entry.image_pos)
2947 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2948 self.assertEqual(len(U_BOOT_DATA), entry.size)
2949
2950 # Section0
2951 self.assertIn('section0', entries)
2952 section0 = entries['section0']
2953 self.assertEqual(0x10, section0.offset)
2954 self.assertEqual(0x10, section0.image_pos)
2955 self.assertEqual(len(U_BOOT_DATA), section0.size)
2956
2957 # Second u-boot
2958 section_entries = section0.GetEntries()
2959 self.assertIn('u-boot', section_entries)
2960 entry = section_entries['u-boot']
2961 self.assertEqual(0, entry.offset)
2962 self.assertEqual(0x10, entry.image_pos)
2963 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2964 self.assertEqual(len(U_BOOT_DATA), entry.size)
2965
2966 # Section1
2967 self.assertIn('section1', entries)
2968 section1 = entries['section1']
2969 self.assertEqual(0x14, section1.offset)
2970 self.assertEqual(0x14, section1.image_pos)
2971 self.assertEqual(0x20, section1.size)
2972
2973 # Second u-boot
2974 section_entries = section1.GetEntries()
2975 self.assertIn('u-boot', section_entries)
2976 entry = section_entries['u-boot']
2977 self.assertEqual(0, entry.offset)
2978 self.assertEqual(0x14, entry.image_pos)
2979 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2980 self.assertEqual(len(U_BOOT_DATA), entry.size)
2981
2982 # Section2
2983 self.assertIn('section2', section_entries)
2984 section2 = section_entries['section2']
2985 self.assertEqual(0x4, section2.offset)
2986 self.assertEqual(0x18, section2.image_pos)
2987 self.assertEqual(4, section2.size)
2988
2989 # Third u-boot
2990 section_entries = section2.GetEntries()
2991 self.assertIn('u-boot', section_entries)
2992 entry = section_entries['u-boot']
2993 self.assertEqual(0, entry.offset)
2994 self.assertEqual(0x18, entry.image_pos)
2995 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2996 self.assertEqual(len(U_BOOT_DATA), entry.size)
2997
Simon Glass51014aa2019-07-20 12:23:56 -06002998 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
2999 dts='132_replace.dts'):
Simon Glass10f9d002019-07-20 12:23:50 -06003000 """Replace an entry in an image
3001
3002 This writes the entry data to update it, then opens the updated file and
3003 returns the value that it now finds there.
3004
3005 Args:
3006 entry_name: Entry name to replace
3007 data: Data to replace it with
3008 decomp: True to compress the data if needed, False if data is
3009 already compressed so should be used as is
Simon Glass51014aa2019-07-20 12:23:56 -06003010 allow_resize: True to allow entries to change size, False to raise
3011 an exception
Simon Glass10f9d002019-07-20 12:23:50 -06003012
3013 Returns:
3014 Tuple:
3015 data from entry
3016 data from fdtmap (excluding header)
Simon Glass51014aa2019-07-20 12:23:56 -06003017 Image object that was modified
Simon Glass10f9d002019-07-20 12:23:50 -06003018 """
Simon Glass51014aa2019-07-20 12:23:56 -06003019 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass10f9d002019-07-20 12:23:50 -06003020 update_dtb=True)[1]
3021
3022 self.assertIn('image', control.images)
3023 image = control.images['image']
3024 entries = image.GetEntries()
3025 orig_dtb_data = entries['u-boot-dtb'].data
3026 orig_fdtmap_data = entries['fdtmap'].data
3027
3028 image_fname = tools.GetOutputFilename('image.bin')
3029 updated_fname = tools.GetOutputFilename('image-updated.bin')
3030 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
Simon Glass51014aa2019-07-20 12:23:56 -06003031 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3032 allow_resize)
Simon Glass10f9d002019-07-20 12:23:50 -06003033 data = control.ReadEntry(updated_fname, entry_name, decomp)
3034
Simon Glass51014aa2019-07-20 12:23:56 -06003035 # The DT data should not change unless resized:
3036 if not allow_resize:
3037 new_dtb_data = entries['u-boot-dtb'].data
3038 self.assertEqual(new_dtb_data, orig_dtb_data)
3039 new_fdtmap_data = entries['fdtmap'].data
3040 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass10f9d002019-07-20 12:23:50 -06003041
Simon Glass51014aa2019-07-20 12:23:56 -06003042 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass10f9d002019-07-20 12:23:50 -06003043
3044 def testReplaceSimple(self):
3045 """Test replacing a single file"""
3046 expected = b'x' * len(U_BOOT_DATA)
Simon Glass51014aa2019-07-20 12:23:56 -06003047 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3048 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06003049 self.assertEqual(expected, data)
3050
3051 # Test that the state looks right. There should be an FDT for the fdtmap
3052 # that we jsut read back in, and it should match what we find in the
3053 # 'control' tables. Checking for an FDT that does not exist should
3054 # return None.
3055 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glass51014aa2019-07-20 12:23:56 -06003056 self.assertIsNotNone(path)
Simon Glass10f9d002019-07-20 12:23:50 -06003057 self.assertEqual(expected_fdtmap, fdtmap)
3058
3059 dtb = state.GetFdtForEtype('fdtmap')
3060 self.assertEqual(dtb.GetContents(), fdtmap)
3061
3062 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3063 self.assertIsNone(missing_path)
3064 self.assertIsNone(missing_fdtmap)
3065
3066 missing_dtb = state.GetFdtForEtype('missing')
3067 self.assertIsNone(missing_dtb)
3068
3069 self.assertEqual('/binman', state.fdt_path_prefix)
3070
3071 def testReplaceResizeFail(self):
3072 """Test replacing a file by something larger"""
3073 expected = U_BOOT_DATA + b'x'
3074 with self.assertRaises(ValueError) as e:
Simon Glass51014aa2019-07-20 12:23:56 -06003075 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3076 dts='139_replace_repack.dts')
Simon Glass10f9d002019-07-20 12:23:50 -06003077 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3078 str(e.exception))
3079
3080 def testReplaceMulti(self):
3081 """Test replacing entry data where multiple images are generated"""
3082 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3083 update_dtb=True)[0]
3084 expected = b'x' * len(U_BOOT_DATA)
3085 updated_fname = tools.GetOutputFilename('image-updated.bin')
3086 tools.WriteFile(updated_fname, data)
3087 entry_name = 'u-boot'
Simon Glass51014aa2019-07-20 12:23:56 -06003088 control.WriteEntry(updated_fname, entry_name, expected,
3089 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06003090 data = control.ReadEntry(updated_fname, entry_name)
3091 self.assertEqual(expected, data)
3092
3093 # Check the state looks right.
3094 self.assertEqual('/binman/image', state.fdt_path_prefix)
3095
3096 # Now check we can write the first image
3097 image_fname = tools.GetOutputFilename('first-image.bin')
3098 updated_fname = tools.GetOutputFilename('first-updated.bin')
3099 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
3100 entry_name = 'u-boot'
Simon Glass51014aa2019-07-20 12:23:56 -06003101 control.WriteEntry(updated_fname, entry_name, expected,
3102 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06003103 data = control.ReadEntry(updated_fname, entry_name)
3104 self.assertEqual(expected, data)
3105
3106 # Check the state looks right.
3107 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass8beb11e2019-07-08 14:25:47 -06003108
Simon Glass12bb1a92019-07-20 12:23:51 -06003109 def testUpdateFdtAllRepack(self):
3110 """Test that all device trees are updated with offset/size info"""
3111 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3112 SECTION_SIZE = 0x300
3113 DTB_SIZE = 602
3114 FDTMAP_SIZE = 608
3115 base_expected = {
3116 'offset': 0,
3117 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3118 'image-pos': 0,
3119 'section:offset': 0,
3120 'section:size': SECTION_SIZE,
3121 'section:image-pos': 0,
3122 'section/u-boot-dtb:offset': 4,
3123 'section/u-boot-dtb:size': 636,
3124 'section/u-boot-dtb:image-pos': 4,
3125 'u-boot-spl-dtb:offset': SECTION_SIZE,
3126 'u-boot-spl-dtb:size': DTB_SIZE,
3127 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3128 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3129 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3130 'u-boot-tpl-dtb:size': DTB_SIZE,
3131 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3132 'fdtmap:size': FDTMAP_SIZE,
3133 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3134 }
3135 main_expected = {
3136 'section:orig-size': SECTION_SIZE,
3137 'section/u-boot-dtb:orig-offset': 4,
3138 }
3139
3140 # We expect three device-tree files in the output, with the first one
3141 # within a fixed-size section.
3142 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3143 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3144 # main U-Boot tree. All three should have the same positions and offset
3145 # except that the main tree should include the main_expected properties
3146 start = 4
3147 for item in ['', 'spl', 'tpl', None]:
3148 if item is None:
3149 start += 16 # Move past fdtmap header
3150 dtb = fdt.Fdt.FromData(data[start:])
3151 dtb.Scan()
3152 props = self._GetPropTree(dtb,
3153 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3154 prefix='/' if item is None else '/binman/')
3155 expected = dict(base_expected)
3156 if item:
3157 expected[item] = 0
3158 else:
3159 # Main DTB and fdtdec should include the 'orig-' properties
3160 expected.update(main_expected)
3161 # Helpful for debugging:
3162 #for prop in sorted(props):
3163 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3164 self.assertEqual(expected, props)
3165 if item == '':
3166 start = SECTION_SIZE
3167 else:
3168 start += dtb._fdt_obj.totalsize()
3169
Simon Glasseba1f0c2019-07-20 12:23:55 -06003170 def testFdtmapHeaderMiddle(self):
3171 """Test an FDT map in the middle of an image when it should be at end"""
3172 with self.assertRaises(ValueError) as e:
3173 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3174 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3175 str(e.exception))
3176
3177 def testFdtmapHeaderStartBad(self):
3178 """Test an FDT map in middle of an image when it should be at start"""
3179 with self.assertRaises(ValueError) as e:
3180 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3181 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3182 str(e.exception))
3183
3184 def testFdtmapHeaderEndBad(self):
3185 """Test an FDT map at the start of an image when it should be at end"""
3186 with self.assertRaises(ValueError) as e:
3187 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3188 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3189 str(e.exception))
3190
3191 def testFdtmapHeaderNoSize(self):
3192 """Test an image header at the end of an image with undefined size"""
3193 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3194
Simon Glass51014aa2019-07-20 12:23:56 -06003195 def testReplaceResize(self):
3196 """Test replacing a single file in an entry with a larger file"""
3197 expected = U_BOOT_DATA + b'x'
3198 data, _, image = self._RunReplaceCmd('u-boot', expected,
3199 dts='139_replace_repack.dts')
3200 self.assertEqual(expected, data)
3201
3202 entries = image.GetEntries()
3203 dtb_data = entries['u-boot-dtb'].data
3204 dtb = fdt.Fdt.FromData(dtb_data)
3205 dtb.Scan()
3206
3207 # The u-boot section should now be larger in the dtb
3208 node = dtb.GetNode('/binman/u-boot')
3209 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3210
3211 # Same for the fdtmap
3212 fdata = entries['fdtmap'].data
3213 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3214 fdtb.Scan()
3215 fnode = fdtb.GetNode('/u-boot')
3216 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3217
3218 def testReplaceResizeNoRepack(self):
3219 """Test replacing an entry with a larger file when not allowed"""
3220 expected = U_BOOT_DATA + b'x'
3221 with self.assertRaises(ValueError) as e:
3222 self._RunReplaceCmd('u-boot', expected)
3223 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3224 str(e.exception))
3225
Simon Glass61ec04f2019-07-20 12:23:58 -06003226 def testEntryShrink(self):
3227 """Test contracting an entry after it is packed"""
3228 try:
3229 state.SetAllowEntryContraction(True)
3230 data = self._DoReadFileDtb('140_entry_shrink.dts',
3231 update_dtb=True)[0]
3232 finally:
3233 state.SetAllowEntryContraction(False)
3234 self.assertEqual(b'a', data[:1])
3235 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3236 self.assertEqual(b'a', data[-1:])
3237
3238 def testEntryShrinkFail(self):
3239 """Test not being allowed to contract an entry after it is packed"""
3240 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3241
3242 # In this case there is a spare byte at the end of the data. The size of
3243 # the contents is only 1 byte but we still have the size before it
3244 # shrunk.
3245 self.assertEqual(b'a\0', data[:2])
3246 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3247 self.assertEqual(b'a\0', data[-2:])
3248
Simon Glass27145fd2019-07-20 12:24:01 -06003249 def testDescriptorOffset(self):
3250 """Test that the Intel descriptor is always placed at at the start"""
3251 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3252 image = control.images['image']
3253 entries = image.GetEntries()
3254 desc = entries['intel-descriptor']
3255 self.assertEqual(0xff800000, desc.offset);
3256 self.assertEqual(0xff800000, desc.image_pos);
3257
Simon Glasseb0f4a42019-07-20 12:24:06 -06003258 def testReplaceCbfs(self):
3259 """Test replacing a single file in CBFS without changing the size"""
3260 self._CheckLz4()
3261 expected = b'x' * len(U_BOOT_DATA)
3262 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3263 updated_fname = tools.GetOutputFilename('image-updated.bin')
3264 tools.WriteFile(updated_fname, data)
3265 entry_name = 'section/cbfs/u-boot'
3266 control.WriteEntry(updated_fname, entry_name, expected,
3267 allow_resize=True)
3268 data = control.ReadEntry(updated_fname, entry_name)
3269 self.assertEqual(expected, data)
3270
3271 def testReplaceResizeCbfs(self):
3272 """Test replacing a single file in CBFS with one of a different size"""
3273 self._CheckLz4()
3274 expected = U_BOOT_DATA + b'x'
3275 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3276 updated_fname = tools.GetOutputFilename('image-updated.bin')
3277 tools.WriteFile(updated_fname, data)
3278 entry_name = 'section/cbfs/u-boot'
3279 control.WriteEntry(updated_fname, entry_name, expected,
3280 allow_resize=True)
3281 data = control.ReadEntry(updated_fname, entry_name)
3282 self.assertEqual(expected, data)
3283
Simon Glassa6cb9952019-07-20 12:24:15 -06003284 def _SetupForReplace(self):
3285 """Set up some files to use to replace entries
3286
3287 This generates an image, copies it to a new file, extracts all the files
3288 in it and updates some of them
3289
3290 Returns:
3291 List
3292 Image filename
3293 Output directory
3294 Expected values for updated entries, each a string
3295 """
3296 data = self._DoReadFileRealDtb('143_replace_all.dts')
3297
3298 updated_fname = tools.GetOutputFilename('image-updated.bin')
3299 tools.WriteFile(updated_fname, data)
3300
3301 outdir = os.path.join(self._indir, 'extract')
3302 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3303
3304 expected1 = b'x' + U_BOOT_DATA + b'y'
3305 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3306 tools.WriteFile(u_boot_fname1, expected1)
3307
3308 expected2 = b'a' + U_BOOT_DATA + b'b'
3309 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
3310 tools.WriteFile(u_boot_fname2, expected2)
3311
3312 expected_text = b'not the same text'
3313 text_fname = os.path.join(outdir, 'text')
3314 tools.WriteFile(text_fname, expected_text)
3315
3316 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3317 dtb = fdt.FdtScan(dtb_fname)
3318 node = dtb.GetNode('/binman/text')
3319 node.AddString('my-property', 'the value')
3320 dtb.Sync(auto_resize=True)
3321 dtb.Flush()
3322
3323 return updated_fname, outdir, expected1, expected2, expected_text
3324
3325 def _CheckReplaceMultiple(self, entry_paths):
3326 """Handle replacing the contents of multiple entries
3327
3328 Args:
3329 entry_paths: List of entry paths to replace
3330
3331 Returns:
3332 List
3333 Dict of entries in the image:
3334 key: Entry name
3335 Value: Entry object
3336 Expected values for updated entries, each a string
3337 """
3338 updated_fname, outdir, expected1, expected2, expected_text = (
3339 self._SetupForReplace())
3340 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3341
3342 image = Image.FromFile(updated_fname)
3343 image.LoadData()
3344 return image.GetEntries(), expected1, expected2, expected_text
3345
3346 def testReplaceAll(self):
3347 """Test replacing the contents of all entries"""
3348 entries, expected1, expected2, expected_text = (
3349 self._CheckReplaceMultiple([]))
3350 data = entries['u-boot'].data
3351 self.assertEqual(expected1, data)
3352
3353 data = entries['u-boot2'].data
3354 self.assertEqual(expected2, data)
3355
3356 data = entries['text'].data
3357 self.assertEqual(expected_text, data)
3358
3359 # Check that the device tree is updated
3360 data = entries['u-boot-dtb'].data
3361 dtb = fdt.Fdt.FromData(data)
3362 dtb.Scan()
3363 node = dtb.GetNode('/binman/text')
3364 self.assertEqual('the value', node.props['my-property'].value)
3365
3366 def testReplaceSome(self):
3367 """Test replacing the contents of a few entries"""
3368 entries, expected1, expected2, expected_text = (
3369 self._CheckReplaceMultiple(['u-boot2', 'text']))
3370
3371 # This one should not change
3372 data = entries['u-boot'].data
3373 self.assertEqual(U_BOOT_DATA, data)
3374
3375 data = entries['u-boot2'].data
3376 self.assertEqual(expected2, data)
3377
3378 data = entries['text'].data
3379 self.assertEqual(expected_text, data)
3380
3381 def testReplaceCmd(self):
3382 """Test replacing a file fron an image on the command line"""
3383 self._DoReadFileRealDtb('143_replace_all.dts')
3384
3385 try:
3386 tmpdir, updated_fname = self._SetupImageInTmpdir()
3387
3388 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3389 expected = b'x' * len(U_BOOT_DATA)
3390 tools.WriteFile(fname, expected)
3391
3392 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
3393 data = tools.ReadFile(updated_fname)
3394 self.assertEqual(expected, data[:len(expected)])
3395 map_fname = os.path.join(tmpdir, 'image-updated.map')
3396 self.assertFalse(os.path.exists(map_fname))
3397 finally:
3398 shutil.rmtree(tmpdir)
3399
3400 def testReplaceCmdSome(self):
3401 """Test replacing some files fron an image on the command line"""
3402 updated_fname, outdir, expected1, expected2, expected_text = (
3403 self._SetupForReplace())
3404
3405 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3406 'u-boot2', 'text')
3407
3408 tools.PrepareOutputDir(None)
3409 image = Image.FromFile(updated_fname)
3410 image.LoadData()
3411 entries = image.GetEntries()
3412
3413 # This one should not change
3414 data = entries['u-boot'].data
3415 self.assertEqual(U_BOOT_DATA, data)
3416
3417 data = entries['u-boot2'].data
3418 self.assertEqual(expected2, data)
3419
3420 data = entries['text'].data
3421 self.assertEqual(expected_text, data)
3422
3423 def testReplaceMissing(self):
3424 """Test replacing entries where the file is missing"""
3425 updated_fname, outdir, expected1, expected2, expected_text = (
3426 self._SetupForReplace())
3427
3428 # Remove one of the files, to generate a warning
3429 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3430 os.remove(u_boot_fname1)
3431
3432 with test_util.capture_sys_output() as (stdout, stderr):
3433 control.ReplaceEntries(updated_fname, None, outdir, [])
3434 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass38fdb4c2020-07-09 18:39:39 -06003435 stderr.getvalue())
Simon Glassa6cb9952019-07-20 12:24:15 -06003436
3437 def testReplaceCmdMap(self):
3438 """Test replacing a file fron an image on the command line"""
3439 self._DoReadFileRealDtb('143_replace_all.dts')
3440
3441 try:
3442 tmpdir, updated_fname = self._SetupImageInTmpdir()
3443
3444 fname = os.path.join(self._indir, 'update-u-boot.bin')
3445 expected = b'x' * len(U_BOOT_DATA)
3446 tools.WriteFile(fname, expected)
3447
3448 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3449 '-f', fname, '-m')
3450 map_fname = os.path.join(tmpdir, 'image-updated.map')
3451 self.assertTrue(os.path.exists(map_fname))
3452 finally:
3453 shutil.rmtree(tmpdir)
3454
3455 def testReplaceNoEntryPaths(self):
3456 """Test replacing an entry without an entry path"""
3457 self._DoReadFileRealDtb('143_replace_all.dts')
3458 image_fname = tools.GetOutputFilename('image.bin')
3459 with self.assertRaises(ValueError) as e:
3460 control.ReplaceEntries(image_fname, 'fname', None, [])
3461 self.assertIn('Must specify an entry path to read with -f',
3462 str(e.exception))
3463
3464 def testReplaceTooManyEntryPaths(self):
3465 """Test extracting some entries"""
3466 self._DoReadFileRealDtb('143_replace_all.dts')
3467 image_fname = tools.GetOutputFilename('image.bin')
3468 with self.assertRaises(ValueError) as e:
3469 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3470 self.assertIn('Must specify exactly one entry path to write with -f',
3471 str(e.exception))
3472
Simon Glass2250ee62019-08-24 07:22:48 -06003473 def testPackReset16(self):
3474 """Test that an image with an x86 reset16 region can be created"""
3475 data = self._DoReadFile('144_x86_reset16.dts')
3476 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3477
3478 def testPackReset16Spl(self):
3479 """Test that an image with an x86 reset16-spl region can be created"""
3480 data = self._DoReadFile('145_x86_reset16_spl.dts')
3481 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3482
3483 def testPackReset16Tpl(self):
3484 """Test that an image with an x86 reset16-tpl region can be created"""
3485 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3486 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3487
Simon Glass5af12072019-08-24 07:22:50 -06003488 def testPackIntelFit(self):
3489 """Test that an image with an Intel FIT and pointer can be created"""
3490 data = self._DoReadFile('147_intel_fit.dts')
3491 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3492 fit = data[16:32];
3493 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3494 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3495
3496 image = control.images['image']
3497 entries = image.GetEntries()
3498 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3499 self.assertEqual(expected_ptr, ptr)
3500
3501 def testPackIntelFitMissing(self):
3502 """Test detection of a FIT pointer with not FIT region"""
3503 with self.assertRaises(ValueError) as e:
3504 self._DoReadFile('148_intel_fit_missing.dts')
3505 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3506 str(e.exception))
3507
Simon Glass7c150132019-11-06 17:22:44 -07003508 def _CheckSymbolsTplSection(self, dts, expected_vals):
3509 data = self._DoReadFile(dts)
3510 sym_values = struct.pack('<LQLL', *expected_vals)
Simon Glass2090f1e2019-08-24 07:23:00 -06003511 upto1 = 4 + len(U_BOOT_SPL_DATA)
Simon Glassb87064c2019-08-24 07:23:05 -06003512 expected1 = tools.GetBytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[20:]
Simon Glass2090f1e2019-08-24 07:23:00 -06003513 self.assertEqual(expected1, data[:upto1])
3514
3515 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Simon Glassb87064c2019-08-24 07:23:05 -06003516 expected2 = tools.GetBytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[20:]
Simon Glass2090f1e2019-08-24 07:23:00 -06003517 self.assertEqual(expected2, data[upto1:upto2])
3518
Simon Glasseb0086f2019-08-24 07:23:04 -06003519 upto3 = 0x34 + len(U_BOOT_DATA)
3520 expected3 = tools.GetBytes(0xff, 1) + U_BOOT_DATA
Simon Glass2090f1e2019-08-24 07:23:00 -06003521 self.assertEqual(expected3, data[upto2:upto3])
3522
Simon Glassb87064c2019-08-24 07:23:05 -06003523 expected4 = sym_values + U_BOOT_TPL_DATA[20:]
Simon Glass7c150132019-11-06 17:22:44 -07003524 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3525
3526 def testSymbolsTplSection(self):
3527 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3528 self._SetupSplElf('u_boot_binman_syms')
3529 self._SetupTplElf('u_boot_binman_syms')
3530 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
3531 [0x04, 0x1c, 0x10 + 0x34, 0x04])
3532
3533 def testSymbolsTplSectionX86(self):
3534 """Test binman can assign symbols in a section with end-at-4gb"""
3535 self._SetupSplElf('u_boot_binman_syms_x86')
3536 self._SetupTplElf('u_boot_binman_syms_x86')
3537 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
3538 [0xffffff04, 0xffffff1c, 0xffffff34,
3539 0x04])
Simon Glass2090f1e2019-08-24 07:23:00 -06003540
Simon Glassbf4d0e22019-08-24 07:23:03 -06003541 def testPackX86RomIfwiSectiom(self):
3542 """Test that a section can be placed in an IFWI region"""
3543 self._SetupIfwi('fitimage.bin')
3544 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3545 self._CheckIfwi(data)
3546
Simon Glassea0fff92019-08-24 07:23:07 -06003547 def testPackFspM(self):
3548 """Test that an image with a FSP memory-init binary can be created"""
3549 data = self._DoReadFile('152_intel_fsp_m.dts')
3550 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3551
Simon Glassbc6a88f2019-10-20 21:31:35 -06003552 def testPackFspS(self):
3553 """Test that an image with a FSP silicon-init binary can be created"""
3554 data = self._DoReadFile('153_intel_fsp_s.dts')
3555 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassea0fff92019-08-24 07:23:07 -06003556
Simon Glass998d1482019-10-20 21:31:36 -06003557 def testPackFspT(self):
3558 """Test that an image with a FSP temp-ram-init binary can be created"""
3559 data = self._DoReadFile('154_intel_fsp_t.dts')
3560 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3561
Simon Glass0dc706f2020-07-09 18:39:31 -06003562 def testMkimage(self):
3563 """Test using mkimage to build an image"""
3564 data = self._DoReadFile('156_mkimage.dts')
3565
3566 # Just check that the data appears in the file somewhere
3567 self.assertIn(U_BOOT_SPL_DATA, data)
3568
Simon Glassce867ad2020-07-09 18:39:36 -06003569 def testExtblob(self):
3570 """Test an image with an external blob"""
3571 data = self._DoReadFile('157_blob_ext.dts')
3572 self.assertEqual(REFCODE_DATA, data)
3573
3574 def testExtblobMissing(self):
3575 """Test an image with a missing external blob"""
3576 with self.assertRaises(ValueError) as e:
3577 self._DoReadFile('158_blob_ext_missing.dts')
3578 self.assertIn("Filename 'missing-file' not found in input path",
3579 str(e.exception))
3580
Simon Glass4f9f1052020-07-09 18:39:38 -06003581 def testExtblobMissingOk(self):
3582 """Test an image with an missing external blob that is allowed"""
Simon Glassb1cca952020-07-09 18:39:40 -06003583 with test_util.capture_sys_output() as (stdout, stderr):
3584 self._DoTestFile('158_blob_ext_missing.dts', allow_missing=True)
3585 err = stderr.getvalue()
3586 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
3587
3588 def testExtblobMissingOkSect(self):
3589 """Test an image with an missing external blob that is allowed"""
3590 with test_util.capture_sys_output() as (stdout, stderr):
3591 self._DoTestFile('159_blob_ext_missing_sect.dts',
3592 allow_missing=True)
3593 err = stderr.getvalue()
3594 self.assertRegex(err, "Image 'main-section'.*missing.*: "
3595 "blob-ext blob-ext2")
Simon Glass4f9f1052020-07-09 18:39:38 -06003596
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003597 def testPackX86RomMeMissingDesc(self):
3598 """Test that an missing Intel descriptor entry is allowed"""
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003599 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass52b10dd2020-07-25 15:11:19 -06003600 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003601 err = stderr.getvalue()
3602 self.assertRegex(err,
3603 "Image 'main-section'.*missing.*: intel-descriptor")
3604
3605 def testPackX86RomMissingIfwi(self):
3606 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3607 self._SetupIfwi('fitimage.bin')
3608 pathname = os.path.join(self._indir, 'fitimage.bin')
3609 os.remove(pathname)
3610 with test_util.capture_sys_output() as (stdout, stderr):
3611 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3612 err = stderr.getvalue()
3613 self.assertRegex(err, "Image 'main-section'.*missing.*: intel-ifwi")
3614
Simon Glassb3295fd2020-07-09 18:39:42 -06003615 def testPackOverlap(self):
3616 """Test that zero-size overlapping regions are ignored"""
3617 self._DoTestFile('160_pack_overlap_zero.dts')
3618
Simon Glassfdc34362020-07-09 18:39:45 -06003619 def testSimpleFit(self):
3620 """Test an image with a FIT inside"""
3621 data = self._DoReadFile('161_fit.dts')
3622 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3623 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3624 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3625
3626 # The data should be inside the FIT
3627 dtb = fdt.Fdt.FromData(fit_data)
3628 dtb.Scan()
3629 fnode = dtb.GetNode('/images/kernel')
3630 self.assertIn('data', fnode.props)
3631
3632 fname = os.path.join(self._indir, 'fit_data.fit')
3633 tools.WriteFile(fname, fit_data)
3634 out = tools.Run('dumpimage', '-l', fname)
3635
3636 # Check a few features to make sure the plumbing works. We don't need
3637 # to test the operation of mkimage or dumpimage here. First convert the
3638 # output into a dict where the keys are the fields printed by dumpimage
3639 # and the values are a list of values for each field
3640 lines = out.splitlines()
3641
3642 # Converts "Compression: gzip compressed" into two groups:
3643 # 'Compression' and 'gzip compressed'
3644 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3645 vals = collections.defaultdict(list)
3646 for line in lines:
3647 mat = re_line.match(line)
3648 vals[mat.group(1)].append(mat.group(2))
3649
3650 self.assertEquals('FIT description: test-desc', lines[0])
3651 self.assertIn('Created:', lines[1])
3652 self.assertIn('Image 0 (kernel)', vals)
3653 self.assertIn('Hash value', vals)
3654 data_sizes = vals.get('Data Size')
3655 self.assertIsNotNone(data_sizes)
3656 self.assertEqual(2, len(data_sizes))
3657 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
3658 self.assertEqual(len(U_BOOT_DATA), int(data_sizes[0].split()[0]))
3659 self.assertEqual(len(U_BOOT_SPL_DTB_DATA), int(data_sizes[1].split()[0]))
3660
3661 def testFitExternal(self):
Simon Glasse9d336d2020-09-01 05:13:55 -06003662 """Test an image with an FIT with external images"""
Simon Glassfdc34362020-07-09 18:39:45 -06003663 data = self._DoReadFile('162_fit_external.dts')
3664 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3665
3666 # The data should be outside the FIT
3667 dtb = fdt.Fdt.FromData(fit_data)
3668 dtb.Scan()
3669 fnode = dtb.GetNode('/images/kernel')
3670 self.assertNotIn('data', fnode.props)
Simon Glass12bb1a92019-07-20 12:23:51 -06003671
Alper Nebi Yasak8001d0b2020-08-31 12:58:18 +03003672 def testSectionIgnoreHashSignature(self):
3673 """Test that sections ignore hash, signature nodes for its data"""
3674 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
3675 expected = (U_BOOT_DATA + U_BOOT_DATA)
3676 self.assertEqual(expected, data)
3677
Alper Nebi Yasak3fdeb142020-08-31 12:58:19 +03003678 def testPadInSections(self):
3679 """Test pad-before, pad-after for entries in sections"""
Simon Glassf90d9062020-10-26 17:40:09 -06003680 data, _, _, out_dtb_fname = self._DoReadFileDtb(
3681 '166_pad_in_sections.dts', update_dtb=True)
Alper Nebi Yasak3fdeb142020-08-31 12:58:19 +03003682 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
3683 U_BOOT_DATA + tools.GetBytes(ord('!'), 6) +
3684 U_BOOT_DATA)
3685 self.assertEqual(expected, data)
3686
Simon Glassf90d9062020-10-26 17:40:09 -06003687 dtb = fdt.Fdt(out_dtb_fname)
3688 dtb.Scan()
3689 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
3690 expected = {
3691 'image-pos': 0,
3692 'offset': 0,
3693 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
3694
3695 'section:image-pos': 0,
3696 'section:offset': 0,
3697 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
3698
3699 'section/before:image-pos': 0,
3700 'section/before:offset': 0,
3701 'section/before:size': len(U_BOOT_DATA),
3702
3703 'section/u-boot:image-pos': 4,
3704 'section/u-boot:offset': 4,
3705 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
3706
3707 'section/after:image-pos': 26,
3708 'section/after:offset': 26,
3709 'section/after:size': len(U_BOOT_DATA),
3710 }
3711 self.assertEqual(expected, props)
3712
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03003713 def testFitImageSubentryAlignment(self):
3714 """Test relative alignability of FIT image subentries"""
3715 entry_args = {
3716 'test-id': TEXT_DATA,
3717 }
3718 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
3719 entry_args=entry_args)
3720 dtb = fdt.Fdt.FromData(data)
3721 dtb.Scan()
3722
3723 node = dtb.GetNode('/images/kernel')
3724 data = dtb.GetProps(node)["data"].bytes
3725 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
3726 expected = (tools.GetBytes(0, 0x20) + U_BOOT_SPL_DATA +
3727 tools.GetBytes(0, align_pad) + U_BOOT_DATA)
3728 self.assertEqual(expected, data)
3729
3730 node = dtb.GetNode('/images/fdt-1')
3731 data = dtb.GetProps(node)["data"].bytes
3732 expected = (U_BOOT_SPL_DTB_DATA + tools.GetBytes(0, 20) +
3733 tools.ToBytes(TEXT_DATA) + tools.GetBytes(0, 30) +
3734 U_BOOT_DTB_DATA)
3735 self.assertEqual(expected, data)
3736
3737 def testFitExtblobMissingOk(self):
3738 """Test a FIT with a missing external blob that is allowed"""
3739 with test_util.capture_sys_output() as (stdout, stderr):
3740 self._DoTestFile('168_fit_missing_blob.dts',
3741 allow_missing=True)
3742 err = stderr.getvalue()
Simon Glassb2381432020-09-06 10:39:09 -06003743 self.assertRegex(err, "Image 'main-section'.*missing.*: atf-bl31")
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03003744
Simon Glass3decfa32020-09-01 05:13:54 -06003745 def testBlobNamedByArgMissing(self):
3746 """Test handling of a missing entry arg"""
3747 with self.assertRaises(ValueError) as e:
3748 self._DoReadFile('068_blob_named_by_arg.dts')
3749 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
3750 str(e.exception))
3751
Simon Glassdc2f81a2020-09-01 05:13:58 -06003752 def testPackBl31(self):
3753 """Test that an image with an ATF BL31 binary can be created"""
3754 data = self._DoReadFile('169_atf_bl31.dts')
3755 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
3756
Samuel Holland18bd4552020-10-21 21:12:15 -05003757 def testPackScp(self):
3758 """Test that an image with an SCP binary can be created"""
3759 data = self._DoReadFile('172_scp.dts')
3760 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
3761
Simon Glass6cf99532020-09-01 05:13:59 -06003762 def testFitFdt(self):
3763 """Test an image with an FIT with multiple FDT images"""
3764 def _CheckFdt(seq, expected_data):
3765 """Check the FDT nodes
3766
3767 Args:
3768 seq: Sequence number to check (0 or 1)
3769 expected_data: Expected contents of 'data' property
3770 """
3771 name = 'fdt-%d' % seq
3772 fnode = dtb.GetNode('/images/%s' % name)
3773 self.assertIsNotNone(fnode)
3774 self.assertEqual({'description','type', 'compression', 'data'},
3775 set(fnode.props.keys()))
3776 self.assertEqual(expected_data, fnode.props['data'].bytes)
3777 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
3778 fnode.props['description'].value)
3779
3780 def _CheckConfig(seq, expected_data):
3781 """Check the configuration nodes
3782
3783 Args:
3784 seq: Sequence number to check (0 or 1)
3785 expected_data: Expected contents of 'data' property
3786 """
3787 cnode = dtb.GetNode('/configurations')
3788 self.assertIn('default', cnode.props)
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003789 self.assertEqual('config-2', cnode.props['default'].value)
Simon Glass6cf99532020-09-01 05:13:59 -06003790
3791 name = 'config-%d' % seq
3792 fnode = dtb.GetNode('/configurations/%s' % name)
3793 self.assertIsNotNone(fnode)
3794 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
3795 set(fnode.props.keys()))
3796 self.assertEqual('conf-test-fdt%d.dtb' % seq,
3797 fnode.props['description'].value)
3798 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
3799
3800 entry_args = {
3801 'of-list': 'test-fdt1 test-fdt2',
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003802 'default-dt': 'test-fdt2',
Simon Glass6cf99532020-09-01 05:13:59 -06003803 }
3804 data = self._DoReadFileDtb(
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003805 '172_fit_fdt.dts',
Simon Glass6cf99532020-09-01 05:13:59 -06003806 entry_args=entry_args,
3807 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3808 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3809 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3810
3811 dtb = fdt.Fdt.FromData(fit_data)
3812 dtb.Scan()
3813 fnode = dtb.GetNode('/images/kernel')
3814 self.assertIn('data', fnode.props)
3815
3816 # Check all the properties in fdt-1 and fdt-2
3817 _CheckFdt(1, TEST_FDT1_DATA)
3818 _CheckFdt(2, TEST_FDT2_DATA)
3819
3820 # Check configurations
3821 _CheckConfig(1, TEST_FDT1_DATA)
3822 _CheckConfig(2, TEST_FDT2_DATA)
3823
3824 def testFitFdtMissingList(self):
3825 """Test handling of a missing 'of-list' entry arg"""
3826 with self.assertRaises(ValueError) as e:
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003827 self._DoReadFile('172_fit_fdt.dts')
Simon Glass6cf99532020-09-01 05:13:59 -06003828 self.assertIn("Generator node requires 'of-list' entry argument",
3829 str(e.exception))
3830
3831 def testFitFdtEmptyList(self):
3832 """Test handling of an empty 'of-list' entry arg"""
3833 entry_args = {
3834 'of-list': '',
3835 }
3836 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
3837
3838 def testFitFdtMissingProp(self):
3839 """Test handling of a missing 'fit,fdt-list' property"""
3840 with self.assertRaises(ValueError) as e:
3841 self._DoReadFile('171_fit_fdt_missing_prop.dts')
3842 self.assertIn("Generator node requires 'fit,fdt-list' property",
3843 str(e.exception))
Simon Glassdc2f81a2020-09-01 05:13:58 -06003844
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003845 def testFitFdtEmptyList(self):
3846 """Test handling of an empty 'of-list' entry arg"""
3847 entry_args = {
3848 'of-list': '',
3849 }
3850 data = self._DoReadFileDtb('172_fit_fdt.dts', entry_args=entry_args)[0]
3851
3852 def testFitFdtMissing(self):
3853 """Test handling of a missing 'default-dt' entry arg"""
3854 entry_args = {
3855 'of-list': 'test-fdt1 test-fdt2',
3856 }
3857 with self.assertRaises(ValueError) as e:
3858 self._DoReadFileDtb(
3859 '172_fit_fdt.dts',
3860 entry_args=entry_args,
3861 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3862 self.assertIn("Generated 'default' node requires default-dt entry argument",
3863 str(e.exception))
3864
3865 def testFitFdtNotInList(self):
3866 """Test handling of a default-dt that is not in the of-list"""
3867 entry_args = {
3868 'of-list': 'test-fdt1 test-fdt2',
3869 'default-dt': 'test-fdt3',
3870 }
3871 with self.assertRaises(ValueError) as e:
3872 self._DoReadFileDtb(
3873 '172_fit_fdt.dts',
3874 entry_args=entry_args,
3875 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3876 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
3877 str(e.exception))
3878
Simon Glassb2381432020-09-06 10:39:09 -06003879 def testFitExtblobMissingHelp(self):
3880 """Test display of help messages when an external blob is missing"""
3881 control.missing_blob_help = control._ReadMissingBlobHelp()
3882 control.missing_blob_help['wibble'] = 'Wibble test'
3883 control.missing_blob_help['another'] = 'Another test'
3884 with test_util.capture_sys_output() as (stdout, stderr):
3885 self._DoTestFile('168_fit_missing_blob.dts',
3886 allow_missing=True)
3887 err = stderr.getvalue()
3888
3889 # We can get the tag from the name, the type or the missing-msg
3890 # property. Check all three.
3891 self.assertIn('You may need to build ARM Trusted', err)
3892 self.assertIn('Wibble test', err)
3893 self.assertIn('Another test', err)
3894
Simon Glass204aa782020-09-06 10:35:32 -06003895 def testMissingBlob(self):
3896 """Test handling of a blob containing a missing file"""
3897 with self.assertRaises(ValueError) as e:
3898 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
3899 self.assertIn("Filename 'missing' not found in input path",
3900 str(e.exception))
3901
Simon Glassfb91d562020-09-06 10:35:33 -06003902 def testEnvironment(self):
3903 """Test adding a U-Boot environment"""
3904 data = self._DoReadFile('174_env.dts')
3905 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3906 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3907 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3908 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
3909 env)
3910
3911 def testEnvironmentNoSize(self):
3912 """Test that a missing 'size' property is detected"""
3913 with self.assertRaises(ValueError) as e:
Simon Glassa4dfe3e2020-10-26 17:40:00 -06003914 self._DoTestFile('175_env_no_size.dts')
Simon Glassfb91d562020-09-06 10:35:33 -06003915 self.assertIn("'u-boot-env' entry must have a size property",
3916 str(e.exception))
3917
3918 def testEnvironmentTooSmall(self):
3919 """Test handling of an environment that does not fit"""
3920 with self.assertRaises(ValueError) as e:
Simon Glassa4dfe3e2020-10-26 17:40:00 -06003921 self._DoTestFile('176_env_too_small.dts')
Simon Glassfb91d562020-09-06 10:35:33 -06003922
3923 # checksum, start byte, environment with \0 terminator, final \0
3924 need = 4 + 1 + len(ENV_DATA) + 1 + 1
3925 short = need - 0x8
3926 self.assertIn("too small to hold data (need %#x more bytes)" % short,
3927 str(e.exception))
3928
Simon Glassf2c0dd82020-10-26 17:40:01 -06003929 def testSkipAtStart(self):
3930 """Test handling of skip-at-start section"""
3931 data = self._DoReadFile('177_skip_at_start.dts')
3932 self.assertEqual(U_BOOT_DATA, data)
3933
3934 image = control.images['image']
3935 entries = image.GetEntries()
3936 section = entries['section']
3937 self.assertEqual(0, section.offset)
3938 self.assertEqual(len(U_BOOT_DATA), section.size)
3939 self.assertEqual(U_BOOT_DATA, section.GetData())
3940
3941 entry = section.GetEntries()['u-boot']
3942 self.assertEqual(16, entry.offset)
3943 self.assertEqual(len(U_BOOT_DATA), entry.size)
3944 self.assertEqual(U_BOOT_DATA, entry.data)
3945
3946 def testSkipAtStartPad(self):
3947 """Test handling of skip-at-start section with padded entry"""
3948 data = self._DoReadFile('178_skip_at_start_pad.dts')
3949 before = tools.GetBytes(0, 8)
3950 after = tools.GetBytes(0, 4)
3951 all = before + U_BOOT_DATA + after
3952 self.assertEqual(all, data)
3953
3954 image = control.images['image']
3955 entries = image.GetEntries()
3956 section = entries['section']
3957 self.assertEqual(0, section.offset)
3958 self.assertEqual(len(all), section.size)
3959 self.assertEqual(all, section.GetData())
3960
3961 entry = section.GetEntries()['u-boot']
3962 self.assertEqual(16, entry.offset)
3963 self.assertEqual(len(all), entry.size)
3964 self.assertEqual(U_BOOT_DATA, entry.data)
3965
3966 def testSkipAtStartSectionPad(self):
3967 """Test handling of skip-at-start section with padding"""
3968 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
3969 before = tools.GetBytes(0, 8)
3970 after = tools.GetBytes(0, 4)
3971 all = before + U_BOOT_DATA + after
Simon Glassd1d3ad72020-10-26 17:40:13 -06003972 self.assertEqual(all, data)
Simon Glassf2c0dd82020-10-26 17:40:01 -06003973
3974 image = control.images['image']
3975 entries = image.GetEntries()
3976 section = entries['section']
3977 self.assertEqual(0, section.offset)
3978 self.assertEqual(len(all), section.size)
Simon Glass63e7ba62020-10-26 17:40:16 -06003979 self.assertEqual(U_BOOT_DATA, section.data)
Simon Glassd1d3ad72020-10-26 17:40:13 -06003980 self.assertEqual(all, section.GetPaddedData())
Simon Glassf2c0dd82020-10-26 17:40:01 -06003981
3982 entry = section.GetEntries()['u-boot']
3983 self.assertEqual(16, entry.offset)
3984 self.assertEqual(len(U_BOOT_DATA), entry.size)
3985 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassfb91d562020-09-06 10:35:33 -06003986
Simon Glass7d398bb2020-10-26 17:40:14 -06003987 def testSectionPad(self):
3988 """Testing padding with sections"""
3989 data = self._DoReadFile('180_section_pad.dts')
3990 expected = (tools.GetBytes(ord('&'), 3) +
3991 tools.GetBytes(ord('!'), 5) +
3992 U_BOOT_DATA +
3993 tools.GetBytes(ord('!'), 1) +
3994 tools.GetBytes(ord('&'), 2))
3995 self.assertEqual(expected, data)
3996
3997 def testSectionAlign(self):
3998 """Testing alignment with sections"""
3999 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4000 expected = (b'\0' + # fill section
4001 tools.GetBytes(ord('&'), 1) + # padding to section align
4002 b'\0' + # fill section
4003 tools.GetBytes(ord('!'), 3) + # padding to u-boot align
4004 U_BOOT_DATA +
4005 tools.GetBytes(ord('!'), 4) + # padding to u-boot size
4006 tools.GetBytes(ord('!'), 4)) # padding to section size
4007 self.assertEqual(expected, data)
4008
Simon Glass8f5ef892020-10-26 17:40:25 -06004009 def testCompressImage(self):
4010 """Test compression of the entire image"""
4011 self._CheckLz4()
4012 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4013 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4014 dtb = fdt.Fdt(out_dtb_fname)
4015 dtb.Scan()
4016 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4017 'uncomp-size'])
4018 orig = self._decompress(data)
4019 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4020
4021 # Do a sanity check on various fields
4022 image = control.images['image']
4023 entries = image.GetEntries()
4024 self.assertEqual(2, len(entries))
4025
4026 entry = entries['blob']
4027 self.assertEqual(COMPRESS_DATA, entry.data)
4028 self.assertEqual(len(COMPRESS_DATA), entry.size)
4029
4030 entry = entries['u-boot']
4031 self.assertEqual(U_BOOT_DATA, entry.data)
4032 self.assertEqual(len(U_BOOT_DATA), entry.size)
4033
4034 self.assertEqual(len(data), image.size)
4035 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4036 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4037 orig = self._decompress(image.data)
4038 self.assertEqual(orig, image.uncomp_data)
4039
4040 expected = {
4041 'blob:offset': 0,
4042 'blob:size': len(COMPRESS_DATA),
4043 'u-boot:offset': len(COMPRESS_DATA),
4044 'u-boot:size': len(U_BOOT_DATA),
4045 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4046 'offset': 0,
4047 'image-pos': 0,
4048 'size': len(data),
4049 }
4050 self.assertEqual(expected, props)
4051
4052 def testCompressImageLess(self):
4053 """Test compression where compression reduces the image size"""
4054 self._CheckLz4()
4055 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4056 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4057 dtb = fdt.Fdt(out_dtb_fname)
4058 dtb.Scan()
4059 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4060 'uncomp-size'])
4061 orig = self._decompress(data)
4062
4063 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
4064
4065 # Do a sanity check on various fields
4066 image = control.images['image']
4067 entries = image.GetEntries()
4068 self.assertEqual(2, len(entries))
4069
4070 entry = entries['blob']
4071 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4072 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4073
4074 entry = entries['u-boot']
4075 self.assertEqual(U_BOOT_DATA, entry.data)
4076 self.assertEqual(len(U_BOOT_DATA), entry.size)
4077
4078 self.assertEqual(len(data), image.size)
4079 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4080 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4081 image.uncomp_size)
4082 orig = self._decompress(image.data)
4083 self.assertEqual(orig, image.uncomp_data)
4084
4085 expected = {
4086 'blob:offset': 0,
4087 'blob:size': len(COMPRESS_DATA_BIG),
4088 'u-boot:offset': len(COMPRESS_DATA_BIG),
4089 'u-boot:size': len(U_BOOT_DATA),
4090 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4091 'offset': 0,
4092 'image-pos': 0,
4093 'size': len(data),
4094 }
4095 self.assertEqual(expected, props)
4096
4097 def testCompressSectionSize(self):
4098 """Test compression of a section with a fixed size"""
4099 self._CheckLz4()
4100 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4101 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4102 dtb = fdt.Fdt(out_dtb_fname)
4103 dtb.Scan()
4104 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4105 'uncomp-size'])
4106 orig = self._decompress(data)
4107 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4108 expected = {
4109 'section/blob:offset': 0,
4110 'section/blob:size': len(COMPRESS_DATA),
4111 'section/u-boot:offset': len(COMPRESS_DATA),
4112 'section/u-boot:size': len(U_BOOT_DATA),
4113 'section:offset': 0,
4114 'section:image-pos': 0,
4115 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4116 'section:size': 0x30,
4117 'offset': 0,
4118 'image-pos': 0,
4119 'size': 0x30,
4120 }
4121 self.assertEqual(expected, props)
4122
4123 def testCompressSection(self):
4124 """Test compression of a section with no fixed size"""
4125 self._CheckLz4()
4126 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4127 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4128 dtb = fdt.Fdt(out_dtb_fname)
4129 dtb.Scan()
4130 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4131 'uncomp-size'])
4132 orig = self._decompress(data)
4133 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4134 expected = {
4135 'section/blob:offset': 0,
4136 'section/blob:size': len(COMPRESS_DATA),
4137 'section/u-boot:offset': len(COMPRESS_DATA),
4138 'section/u-boot:size': len(U_BOOT_DATA),
4139 'section:offset': 0,
4140 'section:image-pos': 0,
4141 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4142 'section:size': len(data),
4143 'offset': 0,
4144 'image-pos': 0,
4145 'size': len(data),
4146 }
4147 self.assertEqual(expected, props)
4148
4149 def testCompressExtra(self):
4150 """Test compression of a section with no fixed size"""
4151 self._CheckLz4()
4152 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4153 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4154 dtb = fdt.Fdt(out_dtb_fname)
4155 dtb.Scan()
4156 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4157 'uncomp-size'])
4158
4159 base = data[len(U_BOOT_DATA):]
4160 self.assertEquals(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
4161 rest = base[len(U_BOOT_DATA):]
4162
4163 # Check compressed data
4164 section1 = self._decompress(rest)
4165 expect1 = tools.Compress(COMPRESS_DATA + U_BOOT_DATA, 'lz4')
4166 self.assertEquals(expect1, rest[:len(expect1)])
4167 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, section1)
4168 rest1 = rest[len(expect1):]
4169
4170 section2 = self._decompress(rest1)
4171 expect2 = tools.Compress(COMPRESS_DATA + COMPRESS_DATA, 'lz4')
4172 self.assertEquals(expect2, rest1[:len(expect2)])
4173 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA, section2)
4174 rest2 = rest1[len(expect2):]
4175
4176 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4177 len(expect2) + len(U_BOOT_DATA))
4178 #self.assertEquals(expect_size, len(data))
4179
4180 #self.assertEquals(U_BOOT_DATA, rest2)
4181
4182 self.maxDiff = None
4183 expected = {
4184 'u-boot:offset': 0,
4185 'u-boot:image-pos': 0,
4186 'u-boot:size': len(U_BOOT_DATA),
4187
4188 'base:offset': len(U_BOOT_DATA),
4189 'base:image-pos': len(U_BOOT_DATA),
4190 'base:size': len(data) - len(U_BOOT_DATA),
4191 'base/u-boot:offset': 0,
4192 'base/u-boot:image-pos': len(U_BOOT_DATA),
4193 'base/u-boot:size': len(U_BOOT_DATA),
4194 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4195 len(expect2),
4196 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4197 len(expect2),
4198 'base/u-boot2:size': len(U_BOOT_DATA),
4199
4200 'base/section:offset': len(U_BOOT_DATA),
4201 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4202 'base/section:size': len(expect1),
4203 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4204 'base/section/blob:offset': 0,
4205 'base/section/blob:size': len(COMPRESS_DATA),
4206 'base/section/u-boot:offset': len(COMPRESS_DATA),
4207 'base/section/u-boot:size': len(U_BOOT_DATA),
4208
4209 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4210 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4211 'base/section2:size': len(expect2),
4212 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4213 'base/section2/blob:offset': 0,
4214 'base/section2/blob:size': len(COMPRESS_DATA),
4215 'base/section2/blob2:offset': len(COMPRESS_DATA),
4216 'base/section2/blob2:size': len(COMPRESS_DATA),
4217
4218 'offset': 0,
4219 'image-pos': 0,
4220 'size': len(data),
4221 }
4222 self.assertEqual(expected, props)
4223
Simon Glass870a9ea2021-01-06 21:35:15 -07004224 def testSymbolsSubsection(self):
4225 """Test binman can assign symbols from a subsection"""
Simon Glassf5898822021-03-18 20:24:56 +13004226 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x18)
Simon Glass870a9ea2021-01-06 21:35:15 -07004227
Simon Glass939d1062021-01-06 21:35:16 -07004228 def testReadImageEntryArg(self):
4229 """Test reading an image that would need an entry arg to generate"""
4230 entry_args = {
4231 'cros-ec-rw-path': 'ecrw.bin',
4232 }
4233 data = self.data = self._DoReadFileDtb(
4234 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4235 entry_args=entry_args)
4236
4237 image_fname = tools.GetOutputFilename('image.bin')
4238 orig_image = control.images['image']
4239
4240 # This should not generate an error about the missing 'cros-ec-rw-path'
4241 # since we are reading the image from a file. Compare with
4242 # testEntryArgsRequired()
4243 image = Image.FromFile(image_fname)
4244 self.assertEqual(orig_image.GetEntries().keys(),
4245 image.GetEntries().keys())
4246
Simon Glass6eb99322021-01-06 21:35:18 -07004247 def testFilesAlign(self):
4248 """Test alignment with files"""
4249 data = self._DoReadFile('190_files_align.dts')
4250
4251 # The first string is 15 bytes so will align to 16
4252 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4253 self.assertEqual(expect, data)
4254
Simon Glass5c6ba712021-01-06 21:35:19 -07004255 def testReadImageSkip(self):
4256 """Test reading an image and accessing its FDT map"""
4257 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
4258 image_fname = tools.GetOutputFilename('image.bin')
4259 orig_image = control.images['image']
4260 image = Image.FromFile(image_fname)
4261 self.assertEqual(orig_image.GetEntries().keys(),
4262 image.GetEntries().keys())
4263
4264 orig_entry = orig_image.GetEntries()['fdtmap']
4265 entry = image.GetEntries()['fdtmap']
4266 self.assertEqual(orig_entry.offset, entry.offset)
4267 self.assertEqual(orig_entry.size, entry.size)
4268 self.assertEqual(16, entry.image_pos)
4269
4270 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4271
4272 self.assertEquals(U_BOOT_DATA, u_boot.ReadData())
4273
Simon Glass77a64e02021-03-18 20:24:57 +13004274 def testTplNoDtb(self):
4275 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
Simon Glass0fe44dc2021-04-25 08:39:32 +12004276 self._SetupTplElf()
Simon Glass77a64e02021-03-18 20:24:57 +13004277 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4278 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4279 data[:len(U_BOOT_TPL_NODTB_DATA)])
4280
Simon Glassd26efc82021-03-18 20:24:58 +13004281 def testTplBssPad(self):
4282 """Test that we can pad TPL's BSS with zeros"""
4283 # ELF file with a '__bss_size' symbol
4284 self._SetupTplElf()
4285 data = self._DoReadFile('193_tpl_bss_pad.dts')
4286 self.assertEqual(U_BOOT_TPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
4287 data)
4288
4289 def testTplBssPadMissing(self):
4290 """Test that a missing symbol is detected"""
4291 self._SetupTplElf('u_boot_ucode_ptr')
4292 with self.assertRaises(ValueError) as e:
4293 self._DoReadFile('193_tpl_bss_pad.dts')
4294 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4295 str(e.exception))
4296
Simon Glass06684922021-03-18 20:25:07 +13004297 def checkDtbSizes(self, data, pad_len, start):
4298 """Check the size arguments in a dtb embedded in an image
4299
4300 Args:
4301 data: The image data
4302 pad_len: Length of the pad section in the image, in bytes
4303 start: Start offset of the devicetree to examine, within the image
4304
4305 Returns:
4306 Size of the devicetree in bytes
4307 """
4308 dtb_data = data[start:]
4309 dtb = fdt.Fdt.FromData(dtb_data)
4310 fdt_size = dtb.GetFdtObj().totalsize()
4311 dtb.Scan()
4312 props = self._GetPropTree(dtb, 'size')
4313 self.assertEqual({
4314 'size': len(data),
4315 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4316 'u-boot-spl/u-boot-spl-dtb:size': 801,
4317 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4318 'u-boot-spl:size': 860,
4319 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4320 'u-boot/u-boot-dtb:size': 781,
4321 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4322 'u-boot:size': 827,
4323 }, props)
4324 return fdt_size
4325
4326 def testExpanded(self):
4327 """Test that an expanded entry type is selected when needed"""
4328 self._SetupSplElf()
4329 self._SetupTplElf()
4330
4331 # SPL has a devicetree, TPL does not
4332 entry_args = {
4333 'spl-dtb': '1',
4334 'spl-bss-pad': 'y',
4335 'tpl-dtb': '',
4336 }
4337 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4338 entry_args=entry_args)
4339 image = control.images['image']
4340 entries = image.GetEntries()
4341 self.assertEqual(3, len(entries))
4342
4343 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4344 self.assertIn('u-boot', entries)
4345 entry = entries['u-boot']
4346 self.assertEqual('u-boot-expanded', entry.etype)
4347 subent = entry.GetEntries()
4348 self.assertEqual(2, len(subent))
4349 self.assertIn('u-boot-nodtb', subent)
4350 self.assertIn('u-boot-dtb', subent)
4351
4352 # Second, u-boot-spl, which should be expanded into three parts
4353 self.assertIn('u-boot-spl', entries)
4354 entry = entries['u-boot-spl']
4355 self.assertEqual('u-boot-spl-expanded', entry.etype)
4356 subent = entry.GetEntries()
4357 self.assertEqual(3, len(subent))
4358 self.assertIn('u-boot-spl-nodtb', subent)
4359 self.assertIn('u-boot-spl-bss-pad', subent)
4360 self.assertIn('u-boot-spl-dtb', subent)
4361
4362 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4363 # devicetree
4364 self.assertIn('u-boot-tpl', entries)
4365 entry = entries['u-boot-tpl']
4366 self.assertEqual('u-boot-tpl', entry.etype)
4367 self.assertEqual(None, entry.GetEntries())
4368
4369 def testExpandedTpl(self):
4370 """Test that an expanded entry type is selected for TPL when needed"""
4371 self._SetupTplElf()
4372
4373 entry_args = {
4374 'tpl-bss-pad': 'y',
4375 'tpl-dtb': 'y',
4376 }
4377 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4378 entry_args=entry_args)
4379 image = control.images['image']
4380 entries = image.GetEntries()
4381 self.assertEqual(1, len(entries))
4382
4383 # We only have u-boot-tpl, which be expanded
4384 self.assertIn('u-boot-tpl', entries)
4385 entry = entries['u-boot-tpl']
4386 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4387 subent = entry.GetEntries()
4388 self.assertEqual(3, len(subent))
4389 self.assertIn('u-boot-tpl-nodtb', subent)
4390 self.assertIn('u-boot-tpl-bss-pad', subent)
4391 self.assertIn('u-boot-tpl-dtb', subent)
4392
4393 def testExpandedNoPad(self):
4394 """Test an expanded entry without BSS pad enabled"""
4395 self._SetupSplElf()
4396 self._SetupTplElf()
4397
4398 # SPL has a devicetree, TPL does not
4399 entry_args = {
4400 'spl-dtb': 'something',
4401 'spl-bss-pad': 'n',
4402 'tpl-dtb': '',
4403 }
4404 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4405 entry_args=entry_args)
4406 image = control.images['image']
4407 entries = image.GetEntries()
4408
4409 # Just check u-boot-spl, which should be expanded into two parts
4410 self.assertIn('u-boot-spl', entries)
4411 entry = entries['u-boot-spl']
4412 self.assertEqual('u-boot-spl-expanded', entry.etype)
4413 subent = entry.GetEntries()
4414 self.assertEqual(2, len(subent))
4415 self.assertIn('u-boot-spl-nodtb', subent)
4416 self.assertIn('u-boot-spl-dtb', subent)
4417
4418 def testExpandedTplNoPad(self):
4419 """Test that an expanded entry type with padding disabled in TPL"""
4420 self._SetupTplElf()
4421
4422 entry_args = {
4423 'tpl-bss-pad': '',
4424 'tpl-dtb': 'y',
4425 }
4426 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4427 entry_args=entry_args)
4428 image = control.images['image']
4429 entries = image.GetEntries()
4430 self.assertEqual(1, len(entries))
4431
4432 # We only have u-boot-tpl, which be expanded
4433 self.assertIn('u-boot-tpl', entries)
4434 entry = entries['u-boot-tpl']
4435 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4436 subent = entry.GetEntries()
4437 self.assertEqual(2, len(subent))
4438 self.assertIn('u-boot-tpl-nodtb', subent)
4439 self.assertIn('u-boot-tpl-dtb', subent)
4440
4441 def testFdtInclude(self):
4442 """Test that an Fdt is update within all binaries"""
4443 self._SetupSplElf()
4444 self._SetupTplElf()
4445
4446 # SPL has a devicetree, TPL does not
4447 self.maxDiff = None
4448 entry_args = {
4449 'spl-dtb': '1',
4450 'spl-bss-pad': 'y',
4451 'tpl-dtb': '',
4452 }
4453 # Build the image. It includes two separate devicetree binaries, each
4454 # with their own contents, but all contain the binman definition.
4455 data = self._DoReadFileDtb(
4456 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4457 update_dtb=True, entry_args=entry_args)[0]
4458 pad_len = 10
4459
4460 # Check the U-Boot dtb
4461 start = len(U_BOOT_NODTB_DATA)
4462 fdt_size = self.checkDtbSizes(data, pad_len, start)
4463
4464 # Now check SPL
4465 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4466 fdt_size = self.checkDtbSizes(data, pad_len, start)
4467
4468 # TPL has no devicetree
4469 start += fdt_size + len(U_BOOT_TPL_DATA)
4470 self.assertEqual(len(data), start)
Simon Glass7d398bb2020-10-26 17:40:14 -06004471
Simon Glass3d433382021-03-21 18:24:30 +13004472 def testSymbolsExpanded(self):
4473 """Test binman can assign symbols in expanded entries"""
4474 entry_args = {
4475 'spl-dtb': '1',
4476 }
4477 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4478 U_BOOT_SPL_DTB_DATA, 0x38,
4479 entry_args=entry_args, use_expanded=True)
4480
Simon Glass189f2912021-03-21 18:24:31 +13004481 def testCollection(self):
4482 """Test a collection"""
4483 data = self._DoReadFile('198_collection.dts')
4484 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
4485 tools.GetBytes(0xff, 2) + U_BOOT_NODTB_DATA +
4486 tools.GetBytes(0xfe, 3) + U_BOOT_DTB_DATA,
4487 data)
4488
Simon Glass631f7522021-03-21 18:24:32 +13004489 def testCollectionSection(self):
4490 """Test a collection where a section must be built first"""
4491 # Sections never have their contents when GetData() is called, but when
4492 # _BuildSectionData() is called with required=True, a section will force
4493 # building the contents, producing an error is anything is still
4494 # missing.
4495 data = self._DoReadFile('199_collection_section.dts')
4496 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
4497 self.assertEqual(section + U_BOOT_DATA + tools.GetBytes(0xff, 2) +
4498 section + tools.GetBytes(0xfe, 3) + U_BOOT_DATA,
4499 data)
4500
Simon Glass5ff9fed2021-03-21 18:24:33 +13004501 def testAlignDefault(self):
4502 """Test that default alignment works on sections"""
4503 data = self._DoReadFile('200_align_default.dts')
4504 expected = (U_BOOT_DATA + tools.GetBytes(0, 8 - len(U_BOOT_DATA)) +
4505 U_BOOT_DATA)
4506 # Special alignment for section
4507 expected += tools.GetBytes(0, 32 - len(expected))
4508 # No alignment within the nested section
4509 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
4510 # Now the final piece, which should be default-aligned
4511 expected += tools.GetBytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
4512 self.assertEqual(expected, data)
Simon Glass631f7522021-03-21 18:24:32 +13004513
Simon Glass9fc60b42017-11-12 21:52:22 -07004514if __name__ == "__main__":
4515 unittest.main()