blob: 481b8fd03c11a77626e52129f49737f67e70f395 [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 Glassc6c10e72019-05-17 22:00:46 -060073REFCODE_DATA = b'refcode'
Simon Glassea0fff92019-08-24 07:23:07 -060074FSP_M_DATA = b'fsp_m'
Simon Glassbc6a88f2019-10-20 21:31:35 -060075FSP_S_DATA = b'fsp_s'
Simon Glass998d1482019-10-20 21:31:36 -060076FSP_T_DATA = b'fsp_t'
Simon Glassdc2f81a2020-09-01 05:13:58 -060077ATF_BL31_DATA = b'bl31'
Samuel Holland18bd4552020-10-21 21:12:15 -050078SCP_DATA = b'scp'
Simon Glass6cf99532020-09-01 05:13:59 -060079TEST_FDT1_DATA = b'fdt1'
80TEST_FDT2_DATA = b'test-fdt2'
Simon Glassfb91d562020-09-06 10:35:33 -060081ENV_DATA = b'var1=1\nvar2="2"'
Simon Glass6cf99532020-09-01 05:13:59 -060082
83# Subdirectory of the input dir to use to put test FDTs
84TEST_FDT_SUBDIR = 'fdts'
Simon Glassec127af2018-07-17 13:25:39 -060085
Simon Glass6ccbfcd2019-07-20 12:23:47 -060086# The expected size for the device tree in some tests
Simon Glassf667e452019-07-08 14:25:50 -060087EXTRACT_DTB_SIZE = 0x3c9
88
Simon Glass6ccbfcd2019-07-20 12:23:47 -060089# Properties expected to be in the device tree when update_dtb is used
90BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
91
Simon Glass12bb1a92019-07-20 12:23:51 -060092# Extra properties expected to be in the device tree when allow-repack is used
93REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
94
Simon Glass4f443042016-11-25 20:15:52 -070095
96class TestFunctional(unittest.TestCase):
97 """Functional tests for binman
98
99 Most of these use a sample .dts file to build an image and then check
100 that it looks correct. The sample files are in the test/ subdirectory
101 and are numbered.
102
103 For each entry type a very small test file is created using fixed
104 string contents. This makes it easy to test that things look right, and
105 debug problems.
106
107 In some cases a 'real' file must be used - these are also supplied in
108 the test/ diurectory.
109 """
110 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600111 def setUpClass(cls):
Simon Glass4d5994f2017-11-12 21:52:20 -0700112 global entry
Simon Glass16287932020-04-17 18:09:03 -0600113 from binman import entry
Simon Glass4d5994f2017-11-12 21:52:20 -0700114
Simon Glass4f443042016-11-25 20:15:52 -0700115 # Handle the case where argv[0] is 'python'
Simon Glassb986b3b2019-08-24 07:22:43 -0600116 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
117 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
Simon Glass4f443042016-11-25 20:15:52 -0700118
119 # Create a temporary directory for input files
Simon Glassb986b3b2019-08-24 07:22:43 -0600120 cls._indir = tempfile.mkdtemp(prefix='binmant.')
Simon Glass4f443042016-11-25 20:15:52 -0700121
122 # Create some test files
123 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
124 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
125 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glassb8ef5b62018-07-17 13:25:48 -0600126 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700127 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -0700128 TestFunctional._MakeInputFile('me.bin', ME_DATA)
129 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glassb986b3b2019-08-24 07:22:43 -0600130 cls._ResetDtbs()
Simon Glass2250ee62019-08-24 07:22:48 -0600131
Jagdish Gediya9d368f32018-09-03 21:35:08 +0530132 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glass2250ee62019-08-24 07:22:48 -0600133
Simon Glass5e239182019-08-24 07:22:49 -0600134 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
135 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
Simon Glass87722132017-11-12 21:52:26 -0700136 X86_START16_SPL_DATA)
Simon Glass5e239182019-08-24 07:22:49 -0600137 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
Simon Glass35b384c2018-09-14 04:57:10 -0600138 X86_START16_TPL_DATA)
Simon Glass2250ee62019-08-24 07:22:48 -0600139
140 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
141 X86_RESET16_DATA)
142 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
143 X86_RESET16_SPL_DATA)
144 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
145 X86_RESET16_TPL_DATA)
146
Simon Glass4f443042016-11-25 20:15:52 -0700147 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass6b187df2017-11-12 21:52:27 -0700148 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
149 U_BOOT_SPL_NODTB_DATA)
Simon Glassf0253632018-09-14 04:57:32 -0600150 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
151 U_BOOT_TPL_NODTB_DATA)
Simon Glassda229092016-11-25 20:15:56 -0700152 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
153 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Meng59ea8c22017-08-15 22:41:54 -0700154 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassca4f4ff2017-11-12 21:52:28 -0700155 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassec127af2018-07-17 13:25:39 -0600156 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glass0ef87aa2018-07-17 13:25:44 -0600157 TestFunctional._MakeInputDir('devkeys')
158 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass3ae192c2018-10-01 12:22:31 -0600159 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glassea0fff92019-08-24 07:23:07 -0600160 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
Simon Glassbc6a88f2019-10-20 21:31:35 -0600161 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
Simon Glass998d1482019-10-20 21:31:36 -0600162 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700163
Simon Glass53e22bf2019-08-24 07:22:53 -0600164 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
165 elf_test.BuildElfTestFiles(cls._elf_testdir)
166
Simon Glasse0ff8552016-11-25 20:15:53 -0700167 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glassf514d8f2019-08-24 07:22:54 -0600168 TestFunctional._MakeInputFile('u-boot',
169 tools.ReadFile(cls.ElfTestFile('u_boot_ucode_ptr')))
Simon Glasse0ff8552016-11-25 20:15:53 -0700170
171 # Intel flash descriptor file
Simon Glass0ba4b3d2020-07-09 18:39:41 -0600172 cls._SetupDescriptor()
Simon Glasse0ff8552016-11-25 20:15:53 -0700173
Simon Glassb986b3b2019-08-24 07:22:43 -0600174 shutil.copytree(cls.TestFile('files'),
175 os.path.join(cls._indir, 'files'))
Simon Glass0a98b282018-09-14 04:57:28 -0600176
Simon Glass83d73c22018-09-14 04:57:26 -0600177 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
Simon Glassdc2f81a2020-09-01 05:13:58 -0600178 TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
Samuel Holland18bd4552020-10-21 21:12:15 -0500179 TestFunctional._MakeInputFile('scp.bin', SCP_DATA)
Simon Glass83d73c22018-09-14 04:57:26 -0600180
Simon Glass6cf99532020-09-01 05:13:59 -0600181 # Add a few .dtb files for testing
182 TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR,
183 TEST_FDT1_DATA)
184 TestFunctional._MakeInputFile('%s/test-fdt2.dtb' % TEST_FDT_SUBDIR,
185 TEST_FDT2_DATA)
186
Simon Glassfb91d562020-09-06 10:35:33 -0600187 TestFunctional._MakeInputFile('env.txt', ENV_DATA)
188
Simon Glassac62fba2019-07-08 13:18:53 -0600189 # Travis-CI may have an old lz4
Simon Glassb986b3b2019-08-24 07:22:43 -0600190 cls.have_lz4 = True
Simon Glassac62fba2019-07-08 13:18:53 -0600191 try:
192 tools.Run('lz4', '--no-frame-crc', '-c',
Simon Glass3b3e3c02019-10-31 07:42:50 -0600193 os.path.join(cls._indir, 'u-boot.bin'), binary=True)
Simon Glassac62fba2019-07-08 13:18:53 -0600194 except:
Simon Glassb986b3b2019-08-24 07:22:43 -0600195 cls.have_lz4 = False
Simon Glassac62fba2019-07-08 13:18:53 -0600196
Simon Glass4f443042016-11-25 20:15:52 -0700197 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600198 def tearDownClass(cls):
Simon Glass4f443042016-11-25 20:15:52 -0700199 """Remove the temporary input directory and its contents"""
Simon Glassb986b3b2019-08-24 07:22:43 -0600200 if cls.preserve_indir:
201 print('Preserving input dir: %s' % cls._indir)
Simon Glassd5164a72019-07-08 13:18:49 -0600202 else:
Simon Glassb986b3b2019-08-24 07:22:43 -0600203 if cls._indir:
204 shutil.rmtree(cls._indir)
205 cls._indir = None
Simon Glass4f443042016-11-25 20:15:52 -0700206
Simon Glassd5164a72019-07-08 13:18:49 -0600207 @classmethod
Simon Glass8acce602019-07-08 13:18:50 -0600208 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
Simon Glass53cd5d92019-07-08 14:25:29 -0600209 toolpath=None, verbosity=None):
Simon Glassd5164a72019-07-08 13:18:49 -0600210 """Accept arguments controlling test execution
211
212 Args:
213 preserve_indir: Preserve the shared input directory used by all
214 tests in this class.
215 preserve_outdir: Preserve the output directories used by tests. Each
216 test has its own, so this is normally only useful when running a
217 single test.
Simon Glass8acce602019-07-08 13:18:50 -0600218 toolpath: ist of paths to use for tools
Simon Glassd5164a72019-07-08 13:18:49 -0600219 """
220 cls.preserve_indir = preserve_indir
221 cls.preserve_outdirs = preserve_outdirs
Simon Glass8acce602019-07-08 13:18:50 -0600222 cls.toolpath = toolpath
Simon Glass53cd5d92019-07-08 14:25:29 -0600223 cls.verbosity = verbosity
Simon Glassd5164a72019-07-08 13:18:49 -0600224
Simon Glassac62fba2019-07-08 13:18:53 -0600225 def _CheckLz4(self):
226 if not self.have_lz4:
227 self.skipTest('lz4 --no-frame-crc not available')
228
Simon Glassbf574f12019-07-20 12:24:09 -0600229 def _CleanupOutputDir(self):
230 """Remove the temporary output directory"""
231 if self.preserve_outdirs:
232 print('Preserving output dir: %s' % tools.outdir)
233 else:
234 tools._FinaliseForTest()
235
Simon Glass4f443042016-11-25 20:15:52 -0700236 def setUp(self):
237 # Enable this to turn on debugging output
238 # tout.Init(tout.DEBUG)
239 command.test_result = None
240
241 def tearDown(self):
242 """Remove the temporary output directory"""
Simon Glassbf574f12019-07-20 12:24:09 -0600243 self._CleanupOutputDir()
Simon Glass4f443042016-11-25 20:15:52 -0700244
Simon Glassf86a7362019-07-20 12:24:10 -0600245 def _SetupImageInTmpdir(self):
246 """Set up the output image in a new temporary directory
247
248 This is used when an image has been generated in the output directory,
249 but we want to run binman again. This will create a new output
250 directory and fail to delete the original one.
251
252 This creates a new temporary directory, copies the image to it (with a
253 new name) and removes the old output directory.
254
255 Returns:
256 Tuple:
257 Temporary directory to use
258 New image filename
259 """
260 image_fname = tools.GetOutputFilename('image.bin')
261 tmpdir = tempfile.mkdtemp(prefix='binman.')
262 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
263 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
264 self._CleanupOutputDir()
265 return tmpdir, updated_fname
266
Simon Glassb8ef5b62018-07-17 13:25:48 -0600267 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600268 def _ResetDtbs(cls):
Simon Glassb8ef5b62018-07-17 13:25:48 -0600269 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
270 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
271 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
272
Simon Glass4f443042016-11-25 20:15:52 -0700273 def _RunBinman(self, *args, **kwargs):
274 """Run binman using the command line
275
276 Args:
277 Arguments to pass, as a list of strings
278 kwargs: Arguments to pass to Command.RunPipe()
279 """
280 result = command.RunPipe([[self._binman_pathname] + list(args)],
281 capture=True, capture_stderr=True, raise_on_error=False)
282 if result.return_code and kwargs.get('raise_on_error', True):
283 raise Exception("Error running '%s': %s" % (' '.join(args),
284 result.stdout + result.stderr))
285 return result
286
Simon Glass53cd5d92019-07-08 14:25:29 -0600287 def _DoBinman(self, *argv):
Simon Glass4f443042016-11-25 20:15:52 -0700288 """Run binman using directly (in the same process)
289
290 Args:
291 Arguments to pass, as a list of strings
292 Returns:
293 Return value (0 for success)
294 """
Simon Glass53cd5d92019-07-08 14:25:29 -0600295 argv = list(argv)
296 args = cmdline.ParseArgs(argv)
297 args.pager = 'binman-invalid-pager'
298 args.build_dir = self._indir
Simon Glass4f443042016-11-25 20:15:52 -0700299
300 # For testing, you can force an increase in verbosity here
Simon Glass53cd5d92019-07-08 14:25:29 -0600301 # args.verbosity = tout.DEBUG
302 return control.Binman(args)
Simon Glass4f443042016-11-25 20:15:52 -0700303
Simon Glass53af22a2018-07-17 13:25:32 -0600304 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glasseb833d82019-04-25 21:58:34 -0600305 entry_args=None, images=None, use_real_dtb=False,
Simon Glass6cf99532020-09-01 05:13:59 -0600306 verbosity=None, allow_missing=False, extra_indirs=None):
Simon Glass4f443042016-11-25 20:15:52 -0700307 """Run binman with a given test file
308
309 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600310 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600311 debug: True to enable debugging output
Simon Glass3b0c3822018-06-01 09:38:20 -0600312 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600313 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600314 tree before packing it into the image
Simon Glass0bfa7b02018-09-14 04:57:12 -0600315 entry_args: Dict of entry args to supply to binman
316 key: arg name
317 value: value of that arg
318 images: List of image names to build
Simon Glasse9d336d2020-09-01 05:13:55 -0600319 use_real_dtb: True to use the test file as the contents of
320 the u-boot-dtb entry. Normally this is not needed and the
321 test contents (the U_BOOT_DTB_DATA string) can be used.
322 But in some test we need the real contents.
323 verbosity: Verbosity level to use (0-3, None=don't set it)
324 allow_missing: Set the '--allow-missing' flag so that missing
325 external binaries just produce a warning instead of an error
Simon Glass6cf99532020-09-01 05:13:59 -0600326 extra_indirs: Extra input directories to add using -I
Simon Glass4f443042016-11-25 20:15:52 -0700327 """
Simon Glass53cd5d92019-07-08 14:25:29 -0600328 args = []
Simon Glass7fe91732017-11-13 18:55:00 -0700329 if debug:
330 args.append('-D')
Simon Glass53cd5d92019-07-08 14:25:29 -0600331 if verbosity is not None:
332 args.append('-v%d' % verbosity)
333 elif self.verbosity:
334 args.append('-v%d' % self.verbosity)
335 if self.toolpath:
336 for path in self.toolpath:
337 args += ['--toolpath', path]
338 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass3b0c3822018-06-01 09:38:20 -0600339 if map:
340 args.append('-m')
Simon Glass16b8d6b2018-07-06 10:27:42 -0600341 if update_dtb:
Simon Glass2569e102019-07-08 13:18:47 -0600342 args.append('-u')
Simon Glass93d17412018-09-14 04:57:23 -0600343 if not use_real_dtb:
344 args.append('--fake-dtb')
Simon Glass53af22a2018-07-17 13:25:32 -0600345 if entry_args:
Simon Glass50979152019-05-14 15:53:41 -0600346 for arg, value in entry_args.items():
Simon Glass53af22a2018-07-17 13:25:32 -0600347 args.append('-a%s=%s' % (arg, value))
Simon Glass4f9f1052020-07-09 18:39:38 -0600348 if allow_missing:
349 args.append('-M')
Simon Glass0bfa7b02018-09-14 04:57:12 -0600350 if images:
351 for image in images:
352 args += ['-i', image]
Simon Glass6cf99532020-09-01 05:13:59 -0600353 if extra_indirs:
354 for indir in extra_indirs:
355 args += ['-I', indir]
Simon Glass7fe91732017-11-13 18:55:00 -0700356 return self._DoBinman(*args)
Simon Glass4f443042016-11-25 20:15:52 -0700357
358 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glasse0ff8552016-11-25 20:15:53 -0700359 """Set up a new test device-tree file
360
361 The given file is compiled and set up as the device tree to be used
362 for ths test.
363
364 Args:
365 fname: Filename of .dts file to read
Simon Glass7ae5f312018-06-01 09:38:19 -0600366 outfile: Output filename for compiled device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700367
368 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600369 Contents of device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700370 """
Simon Glassa004f292019-07-20 12:23:49 -0600371 tmpdir = tempfile.mkdtemp(prefix='binmant.')
372 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
Simon Glass1d0ebf72019-05-14 15:53:42 -0600373 with open(dtb, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700374 data = fd.read()
375 TestFunctional._MakeInputFile(outfile, data)
Simon Glassa004f292019-07-20 12:23:49 -0600376 shutil.rmtree(tmpdir)
Simon Glasse0e62752018-10-01 21:12:41 -0600377 return data
Simon Glass4f443042016-11-25 20:15:52 -0700378
Simon Glass6ed45ba2018-09-14 04:57:24 -0600379 def _GetDtbContentsForSplTpl(self, dtb_data, name):
380 """Create a version of the main DTB for SPL or SPL
381
382 For testing we don't actually have different versions of the DTB. With
383 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
384 we don't normally have any unwanted nodes.
385
386 We still want the DTBs for SPL and TPL to be different though, since
387 otherwise it is confusing to know which one we are looking at. So add
388 an 'spl' or 'tpl' property to the top-level node.
Simon Glasse9d336d2020-09-01 05:13:55 -0600389
390 Args:
391 dtb_data: dtb data to modify (this should be a value devicetree)
392 name: Name of a new property to add
393
394 Returns:
395 New dtb data with the property added
Simon Glass6ed45ba2018-09-14 04:57:24 -0600396 """
397 dtb = fdt.Fdt.FromData(dtb_data)
398 dtb.Scan()
399 dtb.GetNode('/binman').AddZeroProp(name)
400 dtb.Sync(auto_resize=True)
401 dtb.Pack()
402 return dtb.GetContents()
403
Simon Glass16b8d6b2018-07-06 10:27:42 -0600404 def _DoReadFileDtb(self, fname, use_real_dtb=False, map=False,
Simon Glass6cf99532020-09-01 05:13:59 -0600405 update_dtb=False, entry_args=None, reset_dtbs=True,
406 extra_indirs=None):
Simon Glass4f443042016-11-25 20:15:52 -0700407 """Run binman and return the resulting image
408
409 This runs binman with a given test file and then reads the resulting
410 output file. It is a shortcut function since most tests need to do
411 these steps.
412
413 Raises an assertion failure if binman returns a non-zero exit code.
414
415 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600416 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass4f443042016-11-25 20:15:52 -0700417 use_real_dtb: True to use the test file as the contents of
418 the u-boot-dtb entry. Normally this is not needed and the
419 test contents (the U_BOOT_DTB_DATA string) can be used.
420 But in some test we need the real contents.
Simon Glass3b0c3822018-06-01 09:38:20 -0600421 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600422 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600423 tree before packing it into the image
Simon Glasse9d336d2020-09-01 05:13:55 -0600424 entry_args: Dict of entry args to supply to binman
425 key: arg name
426 value: value of that arg
427 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
428 function. If reset_dtbs is True, then the original test dtb
429 is written back before this function finishes
Simon Glass6cf99532020-09-01 05:13:59 -0600430 extra_indirs: Extra input directories to add using -I
Simon Glasse0ff8552016-11-25 20:15:53 -0700431
432 Returns:
433 Tuple:
434 Resulting image contents
435 Device tree contents
Simon Glass3b0c3822018-06-01 09:38:20 -0600436 Map data showing contents of image (or None if none)
Simon Glassea6922e2018-07-17 13:25:27 -0600437 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass4f443042016-11-25 20:15:52 -0700438 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700439 dtb_data = None
Simon Glass4f443042016-11-25 20:15:52 -0700440 # Use the compiled test file as the u-boot-dtb input
441 if use_real_dtb:
Simon Glasse0ff8552016-11-25 20:15:53 -0700442 dtb_data = self._SetupDtb(fname)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600443
444 # For testing purposes, make a copy of the DT for SPL and TPL. Add
445 # a node indicating which it is, so aid verification.
446 for name in ['spl', 'tpl']:
447 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
448 outfile = os.path.join(self._indir, dtb_fname)
449 TestFunctional._MakeInputFile(dtb_fname,
450 self._GetDtbContentsForSplTpl(dtb_data, name))
Simon Glass4f443042016-11-25 20:15:52 -0700451
452 try:
Simon Glass53af22a2018-07-17 13:25:32 -0600453 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glass6cf99532020-09-01 05:13:59 -0600454 entry_args=entry_args, use_real_dtb=use_real_dtb,
455 extra_indirs=extra_indirs)
Simon Glass4f443042016-11-25 20:15:52 -0700456 self.assertEqual(0, retcode)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600457 out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
Simon Glass4f443042016-11-25 20:15:52 -0700458
459 # Find the (only) image, read it and return its contents
460 image = control.images['image']
Simon Glass16b8d6b2018-07-06 10:27:42 -0600461 image_fname = tools.GetOutputFilename('image.bin')
462 self.assertTrue(os.path.exists(image_fname))
Simon Glass3b0c3822018-06-01 09:38:20 -0600463 if map:
464 map_fname = tools.GetOutputFilename('image.map')
465 with open(map_fname) as fd:
466 map_data = fd.read()
467 else:
468 map_data = None
Simon Glass1d0ebf72019-05-14 15:53:42 -0600469 with open(image_fname, 'rb') as fd:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600470 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass4f443042016-11-25 20:15:52 -0700471 finally:
472 # Put the test file back
Simon Glass6ed45ba2018-09-14 04:57:24 -0600473 if reset_dtbs and use_real_dtb:
Simon Glassb8ef5b62018-07-17 13:25:48 -0600474 self._ResetDtbs()
Simon Glass4f443042016-11-25 20:15:52 -0700475
Simon Glass3c081312019-07-08 14:25:26 -0600476 def _DoReadFileRealDtb(self, fname):
477 """Run binman with a real .dtb file and return the resulting data
478
479 Args:
480 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
481
482 Returns:
483 Resulting image contents
484 """
485 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
486
Simon Glasse0ff8552016-11-25 20:15:53 -0700487 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass7ae5f312018-06-01 09:38:19 -0600488 """Helper function which discards the device-tree binary
489
490 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600491 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600492 use_real_dtb: True to use the test file as the contents of
493 the u-boot-dtb entry. Normally this is not needed and the
494 test contents (the U_BOOT_DTB_DATA string) can be used.
495 But in some test we need the real contents.
Simon Glassea6922e2018-07-17 13:25:27 -0600496
497 Returns:
498 Resulting image contents
Simon Glass7ae5f312018-06-01 09:38:19 -0600499 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700500 return self._DoReadFileDtb(fname, use_real_dtb)[0]
501
Simon Glass4f443042016-11-25 20:15:52 -0700502 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600503 def _MakeInputFile(cls, fname, contents):
Simon Glass4f443042016-11-25 20:15:52 -0700504 """Create a new test input file, creating directories as needed
505
506 Args:
Simon Glass3ab95982018-08-01 15:22:37 -0600507 fname: Filename to create
Simon Glass4f443042016-11-25 20:15:52 -0700508 contents: File contents to write in to the file
509 Returns:
510 Full pathname of file created
511 """
Simon Glassb986b3b2019-08-24 07:22:43 -0600512 pathname = os.path.join(cls._indir, fname)
Simon Glass4f443042016-11-25 20:15:52 -0700513 dirname = os.path.dirname(pathname)
514 if dirname and not os.path.exists(dirname):
515 os.makedirs(dirname)
516 with open(pathname, 'wb') as fd:
517 fd.write(contents)
518 return pathname
519
520 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600521 def _MakeInputDir(cls, dirname):
Simon Glass0ef87aa2018-07-17 13:25:44 -0600522 """Create a new test input directory, creating directories as needed
523
524 Args:
525 dirname: Directory name to create
526
527 Returns:
528 Full pathname of directory created
529 """
Simon Glassb986b3b2019-08-24 07:22:43 -0600530 pathname = os.path.join(cls._indir, dirname)
Simon Glass0ef87aa2018-07-17 13:25:44 -0600531 if not os.path.exists(pathname):
532 os.makedirs(pathname)
533 return pathname
534
535 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600536 def _SetupSplElf(cls, src_fname='bss_data'):
Simon Glass11ae93e2018-10-01 21:12:47 -0600537 """Set up an ELF file with a '_dt_ucode_base_size' symbol
538
539 Args:
540 Filename of ELF file to use as SPL
541 """
Simon Glassc9a0b272019-08-24 07:22:59 -0600542 TestFunctional._MakeInputFile('spl/u-boot-spl',
543 tools.ReadFile(cls.ElfTestFile(src_fname)))
Simon Glass11ae93e2018-10-01 21:12:47 -0600544
545 @classmethod
Simon Glass2090f1e2019-08-24 07:23:00 -0600546 def _SetupTplElf(cls, src_fname='bss_data'):
547 """Set up an ELF file with a '_dt_ucode_base_size' symbol
548
549 Args:
550 Filename of ELF file to use as TPL
551 """
552 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
553 tools.ReadFile(cls.ElfTestFile(src_fname)))
554
555 @classmethod
Simon Glass0ba4b3d2020-07-09 18:39:41 -0600556 def _SetupDescriptor(cls):
557 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
558 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
559
560 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600561 def TestFile(cls, fname):
562 return os.path.join(cls._binman_dir, 'test', fname)
Simon Glass4f443042016-11-25 20:15:52 -0700563
Simon Glass53e22bf2019-08-24 07:22:53 -0600564 @classmethod
565 def ElfTestFile(cls, fname):
566 return os.path.join(cls._elf_testdir, fname)
567
Simon Glass4f443042016-11-25 20:15:52 -0700568 def AssertInList(self, grep_list, target):
569 """Assert that at least one of a list of things is in a target
570
571 Args:
572 grep_list: List of strings to check
573 target: Target string
574 """
575 for grep in grep_list:
576 if grep in target:
577 return
Simon Glass1fc62de2019-05-17 22:00:50 -0600578 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass4f443042016-11-25 20:15:52 -0700579
580 def CheckNoGaps(self, entries):
581 """Check that all entries fit together without gaps
582
583 Args:
584 entries: List of entries to check
585 """
Simon Glass3ab95982018-08-01 15:22:37 -0600586 offset = 0
Simon Glass4f443042016-11-25 20:15:52 -0700587 for entry in entries.values():
Simon Glass3ab95982018-08-01 15:22:37 -0600588 self.assertEqual(offset, entry.offset)
589 offset += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700590
Simon Glasse0ff8552016-11-25 20:15:53 -0700591 def GetFdtLen(self, dtb):
Simon Glass7ae5f312018-06-01 09:38:19 -0600592 """Get the totalsize field from a device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700593
594 Args:
Simon Glass7ae5f312018-06-01 09:38:19 -0600595 dtb: Device-tree binary contents
Simon Glasse0ff8552016-11-25 20:15:53 -0700596
597 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600598 Total size of device-tree binary, from the header
Simon Glasse0ff8552016-11-25 20:15:53 -0700599 """
600 return struct.unpack('>L', dtb[4:8])[0]
601
Simon Glass086cec92019-07-08 14:25:27 -0600602 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glass16b8d6b2018-07-06 10:27:42 -0600603 def AddNode(node, path):
604 if node.name != '/':
605 path += '/' + node.name
Simon Glass086cec92019-07-08 14:25:27 -0600606 for prop in node.props.values():
607 if prop.name in prop_names:
608 prop_path = path + ':' + prop.name
609 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
610 prop.value)
Simon Glass16b8d6b2018-07-06 10:27:42 -0600611 for subnode in node.subnodes:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600612 AddNode(subnode, path)
613
614 tree = {}
Simon Glass16b8d6b2018-07-06 10:27:42 -0600615 AddNode(dtb.GetRoot(), '')
616 return tree
617
Simon Glass4f443042016-11-25 20:15:52 -0700618 def testRun(self):
619 """Test a basic run with valid args"""
620 result = self._RunBinman('-h')
621
622 def testFullHelp(self):
623 """Test that the full help is displayed with -H"""
624 result = self._RunBinman('-H')
625 help_file = os.path.join(self._binman_dir, 'README')
Tom Rini3759df02018-01-16 15:29:50 -0500626 # Remove possible extraneous strings
627 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
628 gothelp = result.stdout.replace(extra, '')
629 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass4f443042016-11-25 20:15:52 -0700630 self.assertEqual(0, len(result.stderr))
631 self.assertEqual(0, result.return_code)
632
633 def testFullHelpInternal(self):
634 """Test that the full help is displayed with -H"""
635 try:
636 command.test_result = command.CommandResult()
637 result = self._DoBinman('-H')
638 help_file = os.path.join(self._binman_dir, 'README')
639 finally:
640 command.test_result = None
641
642 def testHelp(self):
643 """Test that the basic help is displayed with -h"""
644 result = self._RunBinman('-h')
645 self.assertTrue(len(result.stdout) > 200)
646 self.assertEqual(0, len(result.stderr))
647 self.assertEqual(0, result.return_code)
648
Simon Glass4f443042016-11-25 20:15:52 -0700649 def testBoard(self):
650 """Test that we can run it with a specific board"""
Simon Glass741f2d62018-10-01 12:22:30 -0600651 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass4f443042016-11-25 20:15:52 -0700652 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glass53cd5d92019-07-08 14:25:29 -0600653 result = self._DoBinman('build', '-b', 'sandbox')
Simon Glass4f443042016-11-25 20:15:52 -0700654 self.assertEqual(0, result)
655
656 def testNeedBoard(self):
657 """Test that we get an error when no board ius supplied"""
658 with self.assertRaises(ValueError) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600659 result = self._DoBinman('build')
Simon Glass4f443042016-11-25 20:15:52 -0700660 self.assertIn("Must provide a board to process (use -b <board>)",
661 str(e.exception))
662
663 def testMissingDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600664 """Test that an invalid device-tree file generates an error"""
Simon Glass4f443042016-11-25 20:15:52 -0700665 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600666 self._RunBinman('build', '-d', 'missing_file')
Simon Glass4f443042016-11-25 20:15:52 -0700667 # We get one error from libfdt, and a different one from fdtget.
668 self.AssertInList(["Couldn't open blob from 'missing_file'",
669 'No such file or directory'], str(e.exception))
670
671 def testBrokenDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600672 """Test that an invalid device-tree source file generates an error
Simon Glass4f443042016-11-25 20:15:52 -0700673
674 Since this is a source file it should be compiled and the error
675 will come from the device-tree compiler (dtc).
676 """
677 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600678 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700679 self.assertIn("FATAL ERROR: Unable to parse input tree",
680 str(e.exception))
681
682 def testMissingNode(self):
683 """Test that a device tree without a 'binman' node generates an error"""
684 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600685 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700686 self.assertIn("does not have a 'binman' node", str(e.exception))
687
688 def testEmpty(self):
689 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glass53cd5d92019-07-08 14:25:29 -0600690 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700691 self.assertEqual(0, len(result.stderr))
692 self.assertEqual(0, result.return_code)
693
694 def testInvalidEntry(self):
695 """Test that an invalid entry is flagged"""
696 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600697 result = self._RunBinman('build', '-d',
Simon Glass741f2d62018-10-01 12:22:30 -0600698 self.TestFile('004_invalid_entry.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700699 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
700 "'/binman/not-a-valid-type'", str(e.exception))
701
702 def testSimple(self):
703 """Test a simple binman with a single file"""
Simon Glass741f2d62018-10-01 12:22:30 -0600704 data = self._DoReadFile('005_simple.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700705 self.assertEqual(U_BOOT_DATA, data)
706
Simon Glass7fe91732017-11-13 18:55:00 -0700707 def testSimpleDebug(self):
708 """Test a simple binman run with debugging enabled"""
Simon Glasse2705fa2019-07-08 14:25:53 -0600709 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass7fe91732017-11-13 18:55:00 -0700710
Simon Glass4f443042016-11-25 20:15:52 -0700711 def testDual(self):
712 """Test that we can handle creating two images
713
714 This also tests image padding.
715 """
Simon Glass741f2d62018-10-01 12:22:30 -0600716 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700717 self.assertEqual(0, retcode)
718
719 image = control.images['image1']
Simon Glass8beb11e2019-07-08 14:25:47 -0600720 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700721 fname = tools.GetOutputFilename('image1.bin')
722 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600723 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700724 data = fd.read()
725 self.assertEqual(U_BOOT_DATA, data)
726
727 image = control.images['image2']
Simon Glass8beb11e2019-07-08 14:25:47 -0600728 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700729 fname = tools.GetOutputFilename('image2.bin')
730 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600731 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700732 data = fd.read()
733 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glasse6d85ff2019-05-14 15:53:47 -0600734 self.assertEqual(tools.GetBytes(0, 3), data[:3])
735 self.assertEqual(tools.GetBytes(0, 5), data[7:])
Simon Glass4f443042016-11-25 20:15:52 -0700736
737 def testBadAlign(self):
738 """Test that an invalid alignment value is detected"""
739 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600740 self._DoTestFile('007_bad_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700741 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
742 "of two", str(e.exception))
743
744 def testPackSimple(self):
745 """Test that packing works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600746 retcode = self._DoTestFile('008_pack.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700747 self.assertEqual(0, retcode)
748 self.assertIn('image', control.images)
749 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600750 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700751 self.assertEqual(5, len(entries))
752
753 # First u-boot
754 self.assertIn('u-boot', entries)
755 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600756 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700757 self.assertEqual(len(U_BOOT_DATA), entry.size)
758
759 # Second u-boot, aligned to 16-byte boundary
760 self.assertIn('u-boot-align', entries)
761 entry = entries['u-boot-align']
Simon Glass3ab95982018-08-01 15:22:37 -0600762 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700763 self.assertEqual(len(U_BOOT_DATA), entry.size)
764
765 # Third u-boot, size 23 bytes
766 self.assertIn('u-boot-size', entries)
767 entry = entries['u-boot-size']
Simon Glass3ab95982018-08-01 15:22:37 -0600768 self.assertEqual(20, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700769 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
770 self.assertEqual(23, entry.size)
771
772 # Fourth u-boot, placed immediate after the above
773 self.assertIn('u-boot-next', entries)
774 entry = entries['u-boot-next']
Simon Glass3ab95982018-08-01 15:22:37 -0600775 self.assertEqual(43, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700776 self.assertEqual(len(U_BOOT_DATA), entry.size)
777
Simon Glass3ab95982018-08-01 15:22:37 -0600778 # Fifth u-boot, placed at a fixed offset
Simon Glass4f443042016-11-25 20:15:52 -0700779 self.assertIn('u-boot-fixed', entries)
780 entry = entries['u-boot-fixed']
Simon Glass3ab95982018-08-01 15:22:37 -0600781 self.assertEqual(61, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700782 self.assertEqual(len(U_BOOT_DATA), entry.size)
783
Simon Glass8beb11e2019-07-08 14:25:47 -0600784 self.assertEqual(65, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700785
786 def testPackExtra(self):
787 """Test that extra packing feature works as expected"""
Simon Glassef439ed2020-10-26 17:40:08 -0600788 data = self._DoReadFile('009_pack_extra.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700789
Simon Glass4f443042016-11-25 20:15:52 -0700790 self.assertIn('image', control.images)
791 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600792 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700793 self.assertEqual(5, len(entries))
794
795 # First u-boot with padding before and after
796 self.assertIn('u-boot', entries)
797 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600798 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700799 self.assertEqual(3, entry.pad_before)
800 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600801 self.assertEqual(U_BOOT_DATA, entry.data)
802 self.assertEqual(tools.GetBytes(0, 3) + U_BOOT_DATA +
803 tools.GetBytes(0, 5), data[:entry.size])
804 pos = entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700805
806 # Second u-boot has an aligned size, but it has no effect
807 self.assertIn('u-boot-align-size-nop', entries)
808 entry = entries['u-boot-align-size-nop']
Simon Glassef439ed2020-10-26 17:40:08 -0600809 self.assertEqual(pos, entry.offset)
810 self.assertEqual(len(U_BOOT_DATA), entry.size)
811 self.assertEqual(U_BOOT_DATA, entry.data)
812 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
813 pos += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700814
815 # Third u-boot has an aligned size too
816 self.assertIn('u-boot-align-size', entries)
817 entry = entries['u-boot-align-size']
Simon Glassef439ed2020-10-26 17:40:08 -0600818 self.assertEqual(pos, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700819 self.assertEqual(32, entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600820 self.assertEqual(U_BOOT_DATA, entry.data)
821 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 32 - len(U_BOOT_DATA)),
822 data[pos:pos + entry.size])
823 pos += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700824
825 # Fourth u-boot has an aligned end
826 self.assertIn('u-boot-align-end', entries)
827 entry = entries['u-boot-align-end']
Simon Glass3ab95982018-08-01 15:22:37 -0600828 self.assertEqual(48, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700829 self.assertEqual(16, entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600830 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
831 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 16 - len(U_BOOT_DATA)),
832 data[pos:pos + entry.size])
833 pos += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700834
835 # Fifth u-boot immediately afterwards
836 self.assertIn('u-boot-align-both', entries)
837 entry = entries['u-boot-align-both']
Simon Glass3ab95982018-08-01 15:22:37 -0600838 self.assertEqual(64, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700839 self.assertEqual(64, 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, 64 - len(U_BOOT_DATA)),
842 data[pos:pos + entry.size])
Simon Glass4f443042016-11-25 20:15:52 -0700843
844 self.CheckNoGaps(entries)
Simon Glass8beb11e2019-07-08 14:25:47 -0600845 self.assertEqual(128, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700846
847 def testPackAlignPowerOf2(self):
848 """Test that invalid entry alignment is detected"""
849 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600850 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700851 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
852 "of two", str(e.exception))
853
854 def testPackAlignSizePowerOf2(self):
855 """Test that invalid entry size alignment is detected"""
856 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600857 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700858 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
859 "power of two", str(e.exception))
860
861 def testPackInvalidAlign(self):
Simon Glass3ab95982018-08-01 15:22:37 -0600862 """Test detection of an offset that does not match its alignment"""
Simon Glass4f443042016-11-25 20:15:52 -0700863 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600864 self._DoTestFile('012_pack_inv_align.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600865 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700866 "align 0x4 (4)", str(e.exception))
867
868 def testPackInvalidSizeAlign(self):
869 """Test that invalid entry size alignment is detected"""
870 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600871 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700872 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
873 "align-size 0x4 (4)", str(e.exception))
874
875 def testPackOverlap(self):
876 """Test that overlapping regions are detected"""
877 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600878 self._DoTestFile('014_pack_overlap.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600879 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -0700880 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
881 str(e.exception))
882
883 def testPackEntryOverflow(self):
884 """Test that entries that overflow their size are detected"""
885 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600886 self._DoTestFile('015_pack_overflow.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700887 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
888 "but entry size is 0x3 (3)", str(e.exception))
889
890 def testPackImageOverflow(self):
891 """Test that entries which overflow the image size are detected"""
892 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600893 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600894 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass4f443042016-11-25 20:15:52 -0700895 "size 0x3 (3)", str(e.exception))
896
897 def testPackImageSize(self):
898 """Test that the image size can be set"""
Simon Glass741f2d62018-10-01 12:22:30 -0600899 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700900 self.assertEqual(0, retcode)
901 self.assertIn('image', control.images)
902 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -0600903 self.assertEqual(7, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700904
905 def testPackImageSizeAlign(self):
906 """Test that image size alignemnt works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600907 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700908 self.assertEqual(0, retcode)
909 self.assertIn('image', control.images)
910 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -0600911 self.assertEqual(16, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700912
913 def testPackInvalidImageAlign(self):
914 """Test that invalid image alignment is detected"""
915 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600916 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600917 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700918 "align-size 0x8 (8)", str(e.exception))
919
920 def testPackAlignPowerOf2(self):
921 """Test that invalid image alignment is detected"""
922 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600923 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -0600924 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass4f443042016-11-25 20:15:52 -0700925 "two", str(e.exception))
926
927 def testImagePadByte(self):
928 """Test that the image pad byte can be specified"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600929 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600930 data = self._DoReadFile('021_image_pad.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -0600931 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0xff, 1) +
932 U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -0700933
934 def testImageName(self):
935 """Test that image files can be named"""
Simon Glass741f2d62018-10-01 12:22:30 -0600936 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700937 self.assertEqual(0, retcode)
938 image = control.images['image1']
939 fname = tools.GetOutputFilename('test-name')
940 self.assertTrue(os.path.exists(fname))
941
942 image = control.images['image2']
943 fname = tools.GetOutputFilename('test-name.xx')
944 self.assertTrue(os.path.exists(fname))
945
946 def testBlobFilename(self):
947 """Test that generic blobs can be provided by filename"""
Simon Glass741f2d62018-10-01 12:22:30 -0600948 data = self._DoReadFile('023_blob.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700949 self.assertEqual(BLOB_DATA, data)
950
951 def testPackSorted(self):
952 """Test that entries can be sorted"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600953 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600954 data = self._DoReadFile('024_sorted.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -0600955 self.assertEqual(tools.GetBytes(0, 1) + U_BOOT_SPL_DATA +
956 tools.GetBytes(0, 2) + U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -0700957
Simon Glass3ab95982018-08-01 15:22:37 -0600958 def testPackZeroOffset(self):
959 """Test that an entry at offset 0 is not given a new offset"""
Simon Glass4f443042016-11-25 20:15:52 -0700960 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600961 self._DoTestFile('025_pack_zero_size.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600962 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -0700963 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
964 str(e.exception))
965
966 def testPackUbootDtb(self):
967 """Test that a device tree can be added to U-Boot"""
Simon Glass741f2d62018-10-01 12:22:30 -0600968 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700969 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glasse0ff8552016-11-25 20:15:53 -0700970
971 def testPackX86RomNoSize(self):
972 """Test that the end-at-4gb property requires a size property"""
973 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600974 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -0600975 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glasse0ff8552016-11-25 20:15:53 -0700976 "using end-at-4gb", str(e.exception))
977
Jagdish Gediya94b57db2018-09-03 21:35:07 +0530978 def test4gbAndSkipAtStartTogether(self):
979 """Test that the end-at-4gb and skip-at-size property can't be used
980 together"""
981 with self.assertRaises(ValueError) as e:
Simon Glassdfdd2b62019-08-24 07:23:02 -0600982 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -0600983 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya94b57db2018-09-03 21:35:07 +0530984 "'skip-at-start'", str(e.exception))
985
Simon Glasse0ff8552016-11-25 20:15:53 -0700986 def testPackX86RomOutside(self):
Simon Glass3ab95982018-08-01 15:22:37 -0600987 """Test that the end-at-4gb property checks for offset boundaries"""
Simon Glasse0ff8552016-11-25 20:15:53 -0700988 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600989 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glasse6bed4f2020-10-26 17:40:05 -0600990 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
991 "is outside the section '/binman' starting at "
992 '0xffffffe0 (4294967264) of size 0x20 (32)',
Simon Glasse0ff8552016-11-25 20:15:53 -0700993 str(e.exception))
994
995 def testPackX86Rom(self):
996 """Test that a basic x86 ROM can be created"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600997 self._SetupSplElf()
Simon Glass9255f3c2019-08-24 07:23:01 -0600998 data = self._DoReadFile('029_x86_rom.dts')
Simon Glasseb0086f2019-08-24 07:23:04 -0600999 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 3) + U_BOOT_SPL_DATA +
Simon Glasse6d85ff2019-05-14 15:53:47 -06001000 tools.GetBytes(0, 2), data)
Simon Glasse0ff8552016-11-25 20:15:53 -07001001
1002 def testPackX86RomMeNoDesc(self):
1003 """Test that an invalid Intel descriptor entry is detected"""
Simon Glass0ba4b3d2020-07-09 18:39:41 -06001004 try:
Simon Glass52b10dd2020-07-25 15:11:19 -06001005 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
Simon Glass0ba4b3d2020-07-09 18:39:41 -06001006 with self.assertRaises(ValueError) as e:
Simon Glass52b10dd2020-07-25 15:11:19 -06001007 self._DoTestFile('163_x86_rom_me_empty.dts')
Simon Glass0ba4b3d2020-07-09 18:39:41 -06001008 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1009 str(e.exception))
1010 finally:
1011 self._SetupDescriptor()
Simon Glasse0ff8552016-11-25 20:15:53 -07001012
1013 def testPackX86RomBadDesc(self):
1014 """Test that the Intel requires a descriptor entry"""
1015 with self.assertRaises(ValueError) as e:
Simon Glass9255f3c2019-08-24 07:23:01 -06001016 self._DoTestFile('030_x86_rom_me_no_desc.dts')
Simon Glass3ab95982018-08-01 15:22:37 -06001017 self.assertIn("Node '/binman/intel-me': No offset set with "
1018 "offset-unset: should another entry provide this correct "
1019 "offset?", str(e.exception))
Simon Glasse0ff8552016-11-25 20:15:53 -07001020
1021 def testPackX86RomMe(self):
1022 """Test that an x86 ROM with an ME region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001023 data = self._DoReadFile('031_x86_rom_me.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06001024 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
1025 if data[:0x1000] != expected_desc:
1026 self.fail('Expected descriptor binary at start of image')
Simon Glasse0ff8552016-11-25 20:15:53 -07001027 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1028
1029 def testPackVga(self):
1030 """Test that an image with a VGA binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001031 data = self._DoReadFile('032_intel_vga.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -07001032 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1033
1034 def testPackStart16(self):
1035 """Test that an image with an x86 start16 region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001036 data = self._DoReadFile('033_x86_start16.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -07001037 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1038
Jagdish Gediya9d368f32018-09-03 21:35:08 +05301039 def testPackPowerpcMpc85xxBootpgResetvec(self):
1040 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1041 created"""
Simon Glassdfdd2b62019-08-24 07:23:02 -06001042 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
Jagdish Gediya9d368f32018-09-03 21:35:08 +05301043 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1044
Simon Glass736bb0a2018-07-06 10:27:17 -06001045 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glassadc57012018-07-06 10:27:16 -06001046 """Handle running a test for insertion of microcode
1047
1048 Args:
1049 dts_fname: Name of test .dts file
1050 nodtb_data: Data that we expect in the first section
Simon Glass736bb0a2018-07-06 10:27:17 -06001051 ucode_second: True if the microsecond entry is second instead of
1052 third
Simon Glassadc57012018-07-06 10:27:16 -06001053
1054 Returns:
1055 Tuple:
1056 Contents of first region (U-Boot or SPL)
Simon Glass3ab95982018-08-01 15:22:37 -06001057 Offset and size components of microcode pointer, as inserted
Simon Glassadc57012018-07-06 10:27:16 -06001058 in the above (two 4-byte words)
1059 """
Simon Glass6b187df2017-11-12 21:52:27 -07001060 data = self._DoReadFile(dts_fname, True)
Simon Glasse0ff8552016-11-25 20:15:53 -07001061
1062 # Now check the device tree has no microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001063 if ucode_second:
1064 ucode_content = data[len(nodtb_data):]
1065 ucode_pos = len(nodtb_data)
1066 dtb_with_ucode = ucode_content[16:]
1067 fdt_len = self.GetFdtLen(dtb_with_ucode)
1068 else:
1069 dtb_with_ucode = data[len(nodtb_data):]
1070 fdt_len = self.GetFdtLen(dtb_with_ucode)
1071 ucode_content = dtb_with_ucode[fdt_len:]
1072 ucode_pos = len(nodtb_data) + fdt_len
Simon Glasse0ff8552016-11-25 20:15:53 -07001073 fname = tools.GetOutputFilename('test.dtb')
1074 with open(fname, 'wb') as fd:
Simon Glassadc57012018-07-06 10:27:16 -06001075 fd.write(dtb_with_ucode)
Simon Glassec3f3782017-05-27 07:38:29 -06001076 dtb = fdt.FdtScan(fname)
1077 ucode = dtb.GetNode('/microcode')
Simon Glasse0ff8552016-11-25 20:15:53 -07001078 self.assertTrue(ucode)
1079 for node in ucode.subnodes:
1080 self.assertFalse(node.props.get('data'))
1081
Simon Glasse0ff8552016-11-25 20:15:53 -07001082 # Check that the microcode appears immediately after the Fdt
1083 # This matches the concatenation of the data properties in
Simon Glass87722132017-11-12 21:52:26 -07001084 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glasse0ff8552016-11-25 20:15:53 -07001085 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1086 0x78235609)
Simon Glassadc57012018-07-06 10:27:16 -06001087 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glasse0ff8552016-11-25 20:15:53 -07001088
1089 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -06001090 # expected offset and size
Simon Glasse0ff8552016-11-25 20:15:53 -07001091 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1092 len(ucode_data))
Simon Glass736bb0a2018-07-06 10:27:17 -06001093 u_boot = data[:len(nodtb_data)]
1094 return u_boot, pos_and_size
Simon Glass6b187df2017-11-12 21:52:27 -07001095
1096 def testPackUbootMicrocode(self):
1097 """Test that x86 microcode can be handled correctly
1098
1099 We expect to see the following in the image, in order:
1100 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1101 place
1102 u-boot.dtb with the microcode removed
1103 the microcode
1104 """
Simon Glass741f2d62018-10-01 12:22:30 -06001105 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass6b187df2017-11-12 21:52:27 -07001106 U_BOOT_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001107 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1108 b' somewhere in here', first)
Simon Glasse0ff8552016-11-25 20:15:53 -07001109
Simon Glass160a7662017-05-27 07:38:26 -06001110 def _RunPackUbootSingleMicrocode(self):
Simon Glasse0ff8552016-11-25 20:15:53 -07001111 """Test that x86 microcode can be handled correctly
1112
1113 We expect to see the following in the image, in order:
1114 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1115 place
1116 u-boot.dtb with the microcode
1117 an empty microcode region
1118 """
1119 # We need the libfdt library to run this test since only that allows
1120 # finding the offset of a property. This is required by
1121 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass741f2d62018-10-01 12:22:30 -06001122 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glasse0ff8552016-11-25 20:15:53 -07001123
1124 second = data[len(U_BOOT_NODTB_DATA):]
1125
1126 fdt_len = self.GetFdtLen(second)
1127 third = second[fdt_len:]
1128 second = second[:fdt_len]
1129
Simon Glass160a7662017-05-27 07:38:26 -06001130 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1131 self.assertIn(ucode_data, second)
1132 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -07001133
Simon Glass160a7662017-05-27 07:38:26 -06001134 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -06001135 # expected offset and size
Simon Glass160a7662017-05-27 07:38:26 -06001136 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1137 len(ucode_data))
1138 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glassc6c10e72019-05-17 22:00:46 -06001139 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1140 b' somewhere in here', first)
Simon Glassc49deb82016-11-25 20:15:54 -07001141
Simon Glass75db0862016-11-25 20:15:55 -07001142 def testPackUbootSingleMicrocode(self):
1143 """Test that x86 microcode can be handled correctly with fdt_normal.
1144 """
Simon Glass160a7662017-05-27 07:38:26 -06001145 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001146
Simon Glassc49deb82016-11-25 20:15:54 -07001147 def testUBootImg(self):
1148 """Test that u-boot.img can be put in a file"""
Simon Glass741f2d62018-10-01 12:22:30 -06001149 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glassc49deb82016-11-25 20:15:54 -07001150 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glass75db0862016-11-25 20:15:55 -07001151
1152 def testNoMicrocode(self):
1153 """Test that a missing microcode region is detected"""
1154 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001155 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001156 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1157 "node found in ", str(e.exception))
1158
1159 def testMicrocodeWithoutNode(self):
1160 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1161 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001162 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001163 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1164 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1165
1166 def testMicrocodeWithoutNode2(self):
1167 """Test that a missing u-boot-ucode node is detected"""
1168 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001169 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001170 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1171 "microcode region u-boot-ucode", str(e.exception))
1172
1173 def testMicrocodeWithoutPtrInElf(self):
1174 """Test that a U-Boot binary without the microcode symbol is detected"""
1175 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glass75db0862016-11-25 20:15:55 -07001176 try:
Simon Glassbccd91d2019-08-24 07:22:55 -06001177 TestFunctional._MakeInputFile('u-boot',
1178 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass75db0862016-11-25 20:15:55 -07001179
1180 with self.assertRaises(ValueError) as e:
Simon Glass160a7662017-05-27 07:38:26 -06001181 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001182 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1183 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1184
1185 finally:
1186 # Put the original file back
Simon Glassf514d8f2019-08-24 07:22:54 -06001187 TestFunctional._MakeInputFile('u-boot',
1188 tools.ReadFile(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glass75db0862016-11-25 20:15:55 -07001189
1190 def testMicrocodeNotInImage(self):
1191 """Test that microcode must be placed within the image"""
1192 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001193 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001194 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1195 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glass25ac0e62018-06-01 09:38:14 -06001196 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glass75db0862016-11-25 20:15:55 -07001197
1198 def testWithoutMicrocode(self):
1199 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glassbccd91d2019-08-24 07:22:55 -06001200 TestFunctional._MakeInputFile('u-boot',
1201 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass741f2d62018-10-01 12:22:30 -06001202 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001203
1204 # Now check the device tree has no microcode
1205 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1206 second = data[len(U_BOOT_NODTB_DATA):]
1207
1208 fdt_len = self.GetFdtLen(second)
1209 self.assertEqual(dtb, second[:fdt_len])
1210
1211 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1212 third = data[used_len:]
Simon Glasse6d85ff2019-05-14 15:53:47 -06001213 self.assertEqual(tools.GetBytes(0, 0x200 - used_len), third)
Simon Glass75db0862016-11-25 20:15:55 -07001214
1215 def testUnknownPosSize(self):
1216 """Test that microcode must be placed within the image"""
1217 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001218 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glass3ab95982018-08-01 15:22:37 -06001219 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glass75db0862016-11-25 20:15:55 -07001220 "entry 'invalid-entry'", str(e.exception))
Simon Glassda229092016-11-25 20:15:56 -07001221
1222 def testPackFsp(self):
1223 """Test that an image with a FSP binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001224 data = self._DoReadFile('042_intel_fsp.dts')
Simon Glassda229092016-11-25 20:15:56 -07001225 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1226
1227 def testPackCmc(self):
Bin Meng59ea8c22017-08-15 22:41:54 -07001228 """Test that an image with a CMC binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001229 data = self._DoReadFile('043_intel_cmc.dts')
Simon Glassda229092016-11-25 20:15:56 -07001230 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Meng59ea8c22017-08-15 22:41:54 -07001231
1232 def testPackVbt(self):
1233 """Test that an image with a VBT binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001234 data = self._DoReadFile('046_intel_vbt.dts')
Bin Meng59ea8c22017-08-15 22:41:54 -07001235 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glass9fc60b42017-11-12 21:52:22 -07001236
Simon Glass56509842017-11-12 21:52:25 -07001237 def testSplBssPad(self):
1238 """Test that we can pad SPL's BSS with zeros"""
Simon Glass6b187df2017-11-12 21:52:27 -07001239 # ELF file with a '__bss_size' symbol
Simon Glass11ae93e2018-10-01 21:12:47 -06001240 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001241 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001242 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
1243 data)
Simon Glass56509842017-11-12 21:52:25 -07001244
Simon Glass86af5112018-10-01 21:12:42 -06001245 def testSplBssPadMissing(self):
1246 """Test that a missing symbol is detected"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001247 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glassb50e5612017-11-13 18:54:54 -07001248 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001249 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassb50e5612017-11-13 18:54:54 -07001250 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1251 str(e.exception))
1252
Simon Glass87722132017-11-12 21:52:26 -07001253 def testPackStart16Spl(self):
Simon Glass35b384c2018-09-14 04:57:10 -06001254 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001255 data = self._DoReadFile('048_x86_start16_spl.dts')
Simon Glass87722132017-11-12 21:52:26 -07001256 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1257
Simon Glass736bb0a2018-07-06 10:27:17 -06001258 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1259 """Helper function for microcode tests
Simon Glass6b187df2017-11-12 21:52:27 -07001260
1261 We expect to see the following in the image, in order:
1262 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1263 correct place
1264 u-boot.dtb with the microcode removed
1265 the microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001266
1267 Args:
1268 dts: Device tree file to use for test
1269 ucode_second: True if the microsecond entry is second instead of
1270 third
Simon Glass6b187df2017-11-12 21:52:27 -07001271 """
Simon Glass11ae93e2018-10-01 21:12:47 -06001272 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass736bb0a2018-07-06 10:27:17 -06001273 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1274 ucode_second=ucode_second)
Simon Glassc6c10e72019-05-17 22:00:46 -06001275 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1276 b'ter somewhere in here', first)
Simon Glass6b187df2017-11-12 21:52:27 -07001277
Simon Glass736bb0a2018-07-06 10:27:17 -06001278 def testPackUbootSplMicrocode(self):
1279 """Test that x86 microcode can be handled correctly in SPL"""
Simon Glass741f2d62018-10-01 12:22:30 -06001280 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass736bb0a2018-07-06 10:27:17 -06001281
1282 def testPackUbootSplMicrocodeReorder(self):
1283 """Test that order doesn't matter for microcode entries
1284
1285 This is the same as testPackUbootSplMicrocode but when we process the
1286 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1287 entry, so we reply on binman to try later.
1288 """
Simon Glass741f2d62018-10-01 12:22:30 -06001289 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass736bb0a2018-07-06 10:27:17 -06001290 ucode_second=True)
1291
Simon Glassca4f4ff2017-11-12 21:52:28 -07001292 def testPackMrc(self):
1293 """Test that an image with an MRC binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001294 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassca4f4ff2017-11-12 21:52:28 -07001295 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1296
Simon Glass47419ea2017-11-13 18:54:55 -07001297 def testSplDtb(self):
1298 """Test that an image with spl/u-boot-spl.dtb can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001299 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass47419ea2017-11-13 18:54:55 -07001300 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1301
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001302 def testSplNoDtb(self):
1303 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001304 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001305 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1306
Simon Glass19790632017-11-13 18:55:01 -07001307 def testSymbols(self):
1308 """Test binman can assign symbols embedded in U-Boot"""
Simon Glass1542c8b2019-08-24 07:22:56 -06001309 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass19790632017-11-13 18:55:01 -07001310 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1311 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Simon Glass3ab95982018-08-01 15:22:37 -06001312 self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr)
Simon Glass19790632017-11-13 18:55:01 -07001313
Simon Glass11ae93e2018-10-01 21:12:47 -06001314 self._SetupSplElf('u_boot_binman_syms')
Simon Glass741f2d62018-10-01 12:22:30 -06001315 data = self._DoReadFile('053_symbols.dts')
Simon Glass7c150132019-11-06 17:22:44 -07001316 sym_values = struct.pack('<LQLL', 0x00, 0x1c, 0x28, 0x04)
Simon Glassb87064c2019-08-24 07:23:05 -06001317 expected = (sym_values + U_BOOT_SPL_DATA[20:] +
Simon Glasse6d85ff2019-05-14 15:53:47 -06001318 tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
Simon Glassb87064c2019-08-24 07:23:05 -06001319 U_BOOT_SPL_DATA[20:])
Simon Glass19790632017-11-13 18:55:01 -07001320 self.assertEqual(expected, data)
1321
Simon Glassdd57c132018-06-01 09:38:11 -06001322 def testPackUnitAddress(self):
1323 """Test that we support multiple binaries with the same name"""
Simon Glass741f2d62018-10-01 12:22:30 -06001324 data = self._DoReadFile('054_unit_address.dts')
Simon Glassdd57c132018-06-01 09:38:11 -06001325 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1326
Simon Glass18546952018-06-01 09:38:16 -06001327 def testSections(self):
1328 """Basic test of sections"""
Simon Glass741f2d62018-10-01 12:22:30 -06001329 data = self._DoReadFile('055_sections.dts')
Simon Glassc6c10e72019-05-17 22:00:46 -06001330 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1331 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
1332 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
Simon Glass18546952018-06-01 09:38:16 -06001333 self.assertEqual(expected, data)
Simon Glass9fc60b42017-11-12 21:52:22 -07001334
Simon Glass3b0c3822018-06-01 09:38:20 -06001335 def testMap(self):
1336 """Tests outputting a map of the images"""
Simon Glass741f2d62018-10-01 12:22:30 -06001337 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001338 self.assertEqual('''ImagePos Offset Size Name
133900000000 00000000 00000028 main-section
134000000000 00000000 00000010 section@0
134100000000 00000000 00000004 u-boot
134200000010 00000010 00000010 section@1
134300000010 00000000 00000004 u-boot
134400000020 00000020 00000004 section@2
134500000020 00000000 00000004 u-boot
Simon Glass3b0c3822018-06-01 09:38:20 -06001346''', map_data)
1347
Simon Glassc8d48ef2018-06-01 09:38:21 -06001348 def testNamePrefix(self):
1349 """Tests that name prefixes are used"""
Simon Glass741f2d62018-10-01 12:22:30 -06001350 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001351 self.assertEqual('''ImagePos Offset Size Name
135200000000 00000000 00000028 main-section
135300000000 00000000 00000010 section@0
135400000000 00000000 00000004 ro-u-boot
135500000010 00000010 00000010 section@1
135600000010 00000000 00000004 rw-u-boot
Simon Glassc8d48ef2018-06-01 09:38:21 -06001357''', map_data)
1358
Simon Glass736bb0a2018-07-06 10:27:17 -06001359 def testUnknownContents(self):
1360 """Test that obtaining the contents works as expected"""
1361 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001362 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass8beb11e2019-07-08 14:25:47 -06001363 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glass16287932020-04-17 18:09:03 -06001364 "processing of contents: remaining ["
1365 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass736bb0a2018-07-06 10:27:17 -06001366
Simon Glass5c890232018-07-06 10:27:19 -06001367 def testBadChangeSize(self):
1368 """Test that trying to change the size of an entry fails"""
Simon Glassc52c9e72019-07-08 14:25:37 -06001369 try:
1370 state.SetAllowEntryExpansion(False)
1371 with self.assertRaises(ValueError) as e:
1372 self._DoReadFile('059_change_size.dts', True)
Simon Glass79d3c582019-07-20 12:23:57 -06001373 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glassc52c9e72019-07-08 14:25:37 -06001374 str(e.exception))
1375 finally:
1376 state.SetAllowEntryExpansion(True)
Simon Glass5c890232018-07-06 10:27:19 -06001377
Simon Glass16b8d6b2018-07-06 10:27:42 -06001378 def testUpdateFdt(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001379 """Test that we can update the device tree with offset/size info"""
Simon Glass741f2d62018-10-01 12:22:30 -06001380 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glass16b8d6b2018-07-06 10:27:42 -06001381 update_dtb=True)
Simon Glasscee02e62018-07-17 13:25:52 -06001382 dtb = fdt.Fdt(out_dtb_fname)
1383 dtb.Scan()
Simon Glass12bb1a92019-07-20 12:23:51 -06001384 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001385 self.assertEqual({
Simon Glassdbf6be92018-08-01 15:22:42 -06001386 'image-pos': 0,
Simon Glass8122f392018-07-17 13:25:28 -06001387 'offset': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001388 '_testing:offset': 32,
Simon Glass79d3c582019-07-20 12:23:57 -06001389 '_testing:size': 2,
Simon Glassdbf6be92018-08-01 15:22:42 -06001390 '_testing:image-pos': 32,
Simon Glass3ab95982018-08-01 15:22:37 -06001391 'section@0/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001392 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001393 'section@0/u-boot:image-pos': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001394 'section@0:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001395 'section@0:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001396 'section@0:image-pos': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001397
Simon Glass3ab95982018-08-01 15:22:37 -06001398 'section@1/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001399 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001400 'section@1/u-boot:image-pos': 16,
Simon Glass3ab95982018-08-01 15:22:37 -06001401 'section@1:offset': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001402 'section@1:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001403 'section@1:image-pos': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001404 'size': 40
1405 }, props)
1406
1407 def testUpdateFdtBad(self):
1408 """Test that we detect when ProcessFdt never completes"""
1409 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001410 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001411 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glass16287932020-04-17 18:09:03 -06001412 '[<binman.etype._testing.Entry__testing',
1413 str(e.exception))
Simon Glass5c890232018-07-06 10:27:19 -06001414
Simon Glass53af22a2018-07-17 13:25:32 -06001415 def testEntryArgs(self):
1416 """Test passing arguments to entries from the command line"""
1417 entry_args = {
1418 'test-str-arg': 'test1',
1419 'test-int-arg': '456',
1420 }
Simon Glass741f2d62018-10-01 12:22:30 -06001421 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001422 self.assertIn('image', control.images)
1423 entry = control.images['image'].GetEntries()['_testing']
1424 self.assertEqual('test0', entry.test_str_fdt)
1425 self.assertEqual('test1', entry.test_str_arg)
1426 self.assertEqual(123, entry.test_int_fdt)
1427 self.assertEqual(456, entry.test_int_arg)
1428
1429 def testEntryArgsMissing(self):
1430 """Test missing arguments and properties"""
1431 entry_args = {
1432 'test-int-arg': '456',
1433 }
Simon Glass741f2d62018-10-01 12:22:30 -06001434 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001435 entry = control.images['image'].GetEntries()['_testing']
1436 self.assertEqual('test0', entry.test_str_fdt)
1437 self.assertEqual(None, entry.test_str_arg)
1438 self.assertEqual(None, entry.test_int_fdt)
1439 self.assertEqual(456, entry.test_int_arg)
1440
1441 def testEntryArgsRequired(self):
1442 """Test missing arguments and properties"""
1443 entry_args = {
1444 'test-int-arg': '456',
1445 }
1446 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001447 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass3decfa32020-09-01 05:13:54 -06001448 self.assertIn("Node '/binman/_testing': "
1449 'Missing required properties/entry args: test-str-arg, '
1450 'test-int-fdt, test-int-arg',
Simon Glass53af22a2018-07-17 13:25:32 -06001451 str(e.exception))
1452
1453 def testEntryArgsInvalidFormat(self):
1454 """Test that an invalid entry-argument format is detected"""
Simon Glass53cd5d92019-07-08 14:25:29 -06001455 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1456 '-ano-value']
Simon Glass53af22a2018-07-17 13:25:32 -06001457 with self.assertRaises(ValueError) as e:
1458 self._DoBinman(*args)
1459 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1460
1461 def testEntryArgsInvalidInteger(self):
1462 """Test that an invalid entry-argument integer is detected"""
1463 entry_args = {
1464 'test-int-arg': 'abc',
1465 }
1466 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001467 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001468 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1469 "'test-int-arg' (value 'abc') to integer",
1470 str(e.exception))
1471
1472 def testEntryArgsInvalidDatatype(self):
1473 """Test that an invalid entry-argument datatype is detected
1474
1475 This test could be written in entry_test.py except that it needs
1476 access to control.entry_args, which seems more than that module should
1477 be able to see.
1478 """
1479 entry_args = {
1480 'test-bad-datatype-arg': '12',
1481 }
1482 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001483 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass53af22a2018-07-17 13:25:32 -06001484 entry_args=entry_args)
1485 self.assertIn('GetArg() internal error: Unknown data type ',
1486 str(e.exception))
1487
Simon Glassbb748372018-07-17 13:25:33 -06001488 def testText(self):
1489 """Test for a text entry type"""
1490 entry_args = {
1491 'test-id': TEXT_DATA,
1492 'test-id2': TEXT_DATA2,
1493 'test-id3': TEXT_DATA3,
1494 }
Simon Glass741f2d62018-10-01 12:22:30 -06001495 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glassbb748372018-07-17 13:25:33 -06001496 entry_args=entry_args)
Simon Glassc6c10e72019-05-17 22:00:46 -06001497 expected = (tools.ToBytes(TEXT_DATA) +
1498 tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1499 tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
Simon Glassaa88b502019-07-08 13:18:40 -06001500 b'some text' + b'more text')
Simon Glassbb748372018-07-17 13:25:33 -06001501 self.assertEqual(expected, data)
1502
Simon Glassfd8d1f72018-07-17 13:25:36 -06001503 def testEntryDocs(self):
1504 """Test for creation of entry documentation"""
1505 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass87d43322020-08-05 13:27:46 -06001506 control.WriteEntryDocs(control.GetEntryModules())
Simon Glassfd8d1f72018-07-17 13:25:36 -06001507 self.assertTrue(len(stdout.getvalue()) > 0)
1508
1509 def testEntryDocsMissing(self):
1510 """Test handling of missing entry documentation"""
1511 with self.assertRaises(ValueError) as e:
1512 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass87d43322020-08-05 13:27:46 -06001513 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glassfd8d1f72018-07-17 13:25:36 -06001514 self.assertIn('Documentation is missing for modules: u_boot',
1515 str(e.exception))
1516
Simon Glass11e36cc2018-07-17 13:25:38 -06001517 def testFmap(self):
1518 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001519 data = self._DoReadFile('067_fmap.dts')
Simon Glass11e36cc2018-07-17 13:25:38 -06001520 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc6c10e72019-05-17 22:00:46 -06001521 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1522 U_BOOT_DATA + tools.GetBytes(ord('a'), 12))
Simon Glass11e36cc2018-07-17 13:25:38 -06001523 self.assertEqual(expected, data[:32])
Simon Glassc6c10e72019-05-17 22:00:46 -06001524 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass11e36cc2018-07-17 13:25:38 -06001525 self.assertEqual(1, fhdr.ver_major)
1526 self.assertEqual(0, fhdr.ver_minor)
1527 self.assertEqual(0, fhdr.base)
1528 self.assertEqual(16 + 16 +
1529 fmap_util.FMAP_HEADER_LEN +
1530 fmap_util.FMAP_AREA_LEN * 3, fhdr.image_size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001531 self.assertEqual(b'FMAP', fhdr.name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001532 self.assertEqual(3, fhdr.nareas)
1533 for fentry in fentries:
1534 self.assertEqual(0, fentry.flags)
1535
1536 self.assertEqual(0, fentries[0].offset)
1537 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001538 self.assertEqual(b'RO_U_BOOT', fentries[0].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001539
1540 self.assertEqual(16, fentries[1].offset)
1541 self.assertEqual(4, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001542 self.assertEqual(b'RW_U_BOOT', fentries[1].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001543
1544 self.assertEqual(32, fentries[2].offset)
1545 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1546 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001547 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001548
Simon Glassec127af2018-07-17 13:25:39 -06001549 def testBlobNamedByArg(self):
1550 """Test we can add a blob with the filename coming from an entry arg"""
1551 entry_args = {
1552 'cros-ec-rw-path': 'ecrw.bin',
1553 }
Simon Glass3decfa32020-09-01 05:13:54 -06001554 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassec127af2018-07-17 13:25:39 -06001555
Simon Glass3af8e492018-07-17 13:25:40 -06001556 def testFill(self):
1557 """Test for an fill entry type"""
Simon Glass741f2d62018-10-01 12:22:30 -06001558 data = self._DoReadFile('069_fill.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001559 expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
Simon Glass3af8e492018-07-17 13:25:40 -06001560 self.assertEqual(expected, data)
1561
1562 def testFillNoSize(self):
1563 """Test for an fill entry type with no size"""
1564 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001565 self._DoReadFile('070_fill_no_size.dts')
Simon Glass3af8e492018-07-17 13:25:40 -06001566 self.assertIn("'fill' entry must have a size property",
1567 str(e.exception))
1568
Simon Glass0ef87aa2018-07-17 13:25:44 -06001569 def _HandleGbbCommand(self, pipe_list):
1570 """Fake calls to the futility utility"""
1571 if pipe_list[0][0] == 'futility':
1572 fname = pipe_list[0][-1]
1573 # Append our GBB data to the file, which will happen every time the
1574 # futility command is called.
Simon Glass1d0ebf72019-05-14 15:53:42 -06001575 with open(fname, 'ab') as fd:
Simon Glass0ef87aa2018-07-17 13:25:44 -06001576 fd.write(GBB_DATA)
1577 return command.CommandResult()
1578
1579 def testGbb(self):
1580 """Test for the Chromium OS Google Binary Block"""
1581 command.test_result = self._HandleGbbCommand
1582 entry_args = {
1583 'keydir': 'devkeys',
1584 'bmpblk': 'bmpblk.bin',
1585 }
Simon Glass741f2d62018-10-01 12:22:30 -06001586 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glass0ef87aa2018-07-17 13:25:44 -06001587
1588 # Since futility
Simon Glasse6d85ff2019-05-14 15:53:47 -06001589 expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1590 tools.GetBytes(0, 0x2180 - 16))
Simon Glass0ef87aa2018-07-17 13:25:44 -06001591 self.assertEqual(expected, data)
1592
1593 def testGbbTooSmall(self):
1594 """Test for the Chromium OS Google Binary Block being large enough"""
1595 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001596 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001597 self.assertIn("Node '/binman/gbb': GBB is too small",
1598 str(e.exception))
1599
1600 def testGbbNoSize(self):
1601 """Test for the Chromium OS Google Binary Block having a size"""
1602 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001603 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001604 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1605 str(e.exception))
1606
Simon Glass24d0d3c2018-07-17 13:25:47 -06001607 def _HandleVblockCommand(self, pipe_list):
1608 """Fake calls to the futility utility"""
1609 if pipe_list[0][0] == 'futility':
1610 fname = pipe_list[0][3]
Simon Glassa326b492018-09-14 04:57:11 -06001611 with open(fname, 'wb') as fd:
Simon Glass24d0d3c2018-07-17 13:25:47 -06001612 fd.write(VBLOCK_DATA)
1613 return command.CommandResult()
1614
1615 def testVblock(self):
1616 """Test for the Chromium OS Verified Boot Block"""
1617 command.test_result = self._HandleVblockCommand
1618 entry_args = {
1619 'keydir': 'devkeys',
1620 }
Simon Glass741f2d62018-10-01 12:22:30 -06001621 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass24d0d3c2018-07-17 13:25:47 -06001622 entry_args=entry_args)
1623 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1624 self.assertEqual(expected, data)
1625
1626 def testVblockNoContent(self):
1627 """Test we detect a vblock which has no content to sign"""
1628 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001629 self._DoReadFile('075_vblock_no_content.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001630 self.assertIn("Node '/binman/vblock': Vblock must have a 'content' "
1631 'property', str(e.exception))
1632
1633 def testVblockBadPhandle(self):
1634 """Test that we detect a vblock with an invalid phandle in contents"""
1635 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001636 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001637 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1638 '1000', str(e.exception))
1639
1640 def testVblockBadEntry(self):
1641 """Test that we detect an entry that points to a non-entry"""
1642 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001643 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001644 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1645 "'other'", str(e.exception))
1646
Simon Glassb8ef5b62018-07-17 13:25:48 -06001647 def testTpl(self):
Simon Glass2090f1e2019-08-24 07:23:00 -06001648 """Test that an image with TPL and its device tree can be created"""
Simon Glassb8ef5b62018-07-17 13:25:48 -06001649 # ELF file with a '__bss_size' symbol
Simon Glass2090f1e2019-08-24 07:23:00 -06001650 self._SetupTplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001651 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glassb8ef5b62018-07-17 13:25:48 -06001652 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1653
Simon Glass15a587c2018-07-17 13:25:51 -06001654 def testUsesPos(self):
1655 """Test that the 'pos' property cannot be used anymore"""
1656 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001657 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass15a587c2018-07-17 13:25:51 -06001658 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1659 "'pos'", str(e.exception))
1660
Simon Glassd178eab2018-09-14 04:57:08 -06001661 def testFillZero(self):
1662 """Test for an fill entry type with a size of 0"""
Simon Glass741f2d62018-10-01 12:22:30 -06001663 data = self._DoReadFile('080_fill_empty.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001664 self.assertEqual(tools.GetBytes(0, 16), data)
Simon Glassd178eab2018-09-14 04:57:08 -06001665
Simon Glass0b489362018-09-14 04:57:09 -06001666 def testTextMissing(self):
1667 """Test for a text entry type where there is no text"""
1668 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001669 self._DoReadFileDtb('066_text.dts',)
Simon Glass0b489362018-09-14 04:57:09 -06001670 self.assertIn("Node '/binman/text': No value provided for text label "
1671 "'test-id'", str(e.exception))
1672
Simon Glass35b384c2018-09-14 04:57:10 -06001673 def testPackStart16Tpl(self):
1674 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001675 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glass35b384c2018-09-14 04:57:10 -06001676 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1677
Simon Glass0bfa7b02018-09-14 04:57:12 -06001678 def testSelectImage(self):
1679 """Test that we can select which images to build"""
Simon Glasseb833d82019-04-25 21:58:34 -06001680 expected = 'Skipping images: image1'
Simon Glass0bfa7b02018-09-14 04:57:12 -06001681
Simon Glasseb833d82019-04-25 21:58:34 -06001682 # We should only get the expected message in verbose mode
Simon Glassee0c9a72019-07-08 13:18:48 -06001683 for verbosity in (0, 2):
Simon Glasseb833d82019-04-25 21:58:34 -06001684 with test_util.capture_sys_output() as (stdout, stderr):
1685 retcode = self._DoTestFile('006_dual_image.dts',
1686 verbosity=verbosity,
1687 images=['image2'])
1688 self.assertEqual(0, retcode)
1689 if verbosity:
1690 self.assertIn(expected, stdout.getvalue())
1691 else:
1692 self.assertNotIn(expected, stdout.getvalue())
1693
1694 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1695 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
Simon Glassf86a7362019-07-20 12:24:10 -06001696 self._CleanupOutputDir()
Simon Glass0bfa7b02018-09-14 04:57:12 -06001697
Simon Glass6ed45ba2018-09-14 04:57:24 -06001698 def testUpdateFdtAll(self):
1699 """Test that all device trees are updated with offset/size info"""
Simon Glass3c081312019-07-08 14:25:26 -06001700 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glass6ed45ba2018-09-14 04:57:24 -06001701
1702 base_expected = {
1703 'section:image-pos': 0,
1704 'u-boot-tpl-dtb:size': 513,
1705 'u-boot-spl-dtb:size': 513,
1706 'u-boot-spl-dtb:offset': 493,
1707 'image-pos': 0,
1708 'section/u-boot-dtb:image-pos': 0,
1709 'u-boot-spl-dtb:image-pos': 493,
1710 'section/u-boot-dtb:size': 493,
1711 'u-boot-tpl-dtb:image-pos': 1006,
1712 'section/u-boot-dtb:offset': 0,
1713 'section:size': 493,
1714 'offset': 0,
1715 'section:offset': 0,
1716 'u-boot-tpl-dtb:offset': 1006,
1717 'size': 1519
1718 }
1719
1720 # We expect three device-tree files in the output, one after the other.
1721 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1722 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1723 # main U-Boot tree. All three should have the same postions and offset.
1724 start = 0
1725 for item in ['', 'spl', 'tpl']:
1726 dtb = fdt.Fdt.FromData(data[start:])
1727 dtb.Scan()
Simon Glass12bb1a92019-07-20 12:23:51 -06001728 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
1729 ['spl', 'tpl'])
Simon Glass6ed45ba2018-09-14 04:57:24 -06001730 expected = dict(base_expected)
1731 if item:
1732 expected[item] = 0
1733 self.assertEqual(expected, props)
1734 start += dtb._fdt_obj.totalsize()
1735
1736 def testUpdateFdtOutput(self):
1737 """Test that output DTB files are updated"""
1738 try:
Simon Glass741f2d62018-10-01 12:22:30 -06001739 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glass6ed45ba2018-09-14 04:57:24 -06001740 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1741
1742 # Unfortunately, compiling a source file always results in a file
1743 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass741f2d62018-10-01 12:22:30 -06001744 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glass6ed45ba2018-09-14 04:57:24 -06001745 # binman as a file called u-boot.dtb. To fix this, copy the file
1746 # over to the expected place.
Simon Glass6ed45ba2018-09-14 04:57:24 -06001747 start = 0
1748 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1749 'tpl/u-boot-tpl.dtb.out']:
1750 dtb = fdt.Fdt.FromData(data[start:])
1751 size = dtb._fdt_obj.totalsize()
1752 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1753 outdata = tools.ReadFile(pathname)
1754 name = os.path.split(fname)[0]
1755
1756 if name:
1757 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1758 else:
1759 orig_indata = dtb_data
1760 self.assertNotEqual(outdata, orig_indata,
1761 "Expected output file '%s' be updated" % pathname)
1762 self.assertEqual(outdata, data[start:start + size],
1763 "Expected output file '%s' to match output image" %
1764 pathname)
1765 start += size
1766 finally:
1767 self._ResetDtbs()
1768
Simon Glass83d73c22018-09-14 04:57:26 -06001769 def _decompress(self, data):
Simon Glassff5c7e32019-07-08 13:18:42 -06001770 return tools.Decompress(data, 'lz4')
Simon Glass83d73c22018-09-14 04:57:26 -06001771
1772 def testCompress(self):
1773 """Test compression of blobs"""
Simon Glassac62fba2019-07-08 13:18:53 -06001774 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06001775 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass83d73c22018-09-14 04:57:26 -06001776 use_real_dtb=True, update_dtb=True)
1777 dtb = fdt.Fdt(out_dtb_fname)
1778 dtb.Scan()
1779 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1780 orig = self._decompress(data)
1781 self.assertEquals(COMPRESS_DATA, orig)
1782 expected = {
1783 'blob:uncomp-size': len(COMPRESS_DATA),
1784 'blob:size': len(data),
1785 'size': len(data),
1786 }
1787 self.assertEqual(expected, props)
1788
Simon Glass0a98b282018-09-14 04:57:28 -06001789 def testFiles(self):
1790 """Test bringing in multiple files"""
Simon Glass741f2d62018-10-01 12:22:30 -06001791 data = self._DoReadFile('084_files.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001792 self.assertEqual(FILES_DATA, data)
1793
1794 def testFilesCompress(self):
1795 """Test bringing in multiple files and compressing them"""
Simon Glassac62fba2019-07-08 13:18:53 -06001796 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06001797 data = self._DoReadFile('085_files_compress.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001798
1799 image = control.images['image']
1800 entries = image.GetEntries()
1801 files = entries['files']
Simon Glass8beb11e2019-07-08 14:25:47 -06001802 entries = files._entries
Simon Glass0a98b282018-09-14 04:57:28 -06001803
Simon Glassc6c10e72019-05-17 22:00:46 -06001804 orig = b''
Simon Glass0a98b282018-09-14 04:57:28 -06001805 for i in range(1, 3):
1806 key = '%d.dat' % i
1807 start = entries[key].image_pos
1808 len = entries[key].size
1809 chunk = data[start:start + len]
1810 orig += self._decompress(chunk)
1811
1812 self.assertEqual(FILES_DATA, orig)
1813
1814 def testFilesMissing(self):
1815 """Test missing files"""
1816 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001817 data = self._DoReadFile('086_files_none.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001818 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1819 'no files', str(e.exception))
1820
1821 def testFilesNoPattern(self):
1822 """Test missing files"""
1823 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001824 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001825 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1826 str(e.exception))
1827
Simon Glassba64a0b2018-09-14 04:57:29 -06001828 def testExpandSize(self):
1829 """Test an expanding entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001830 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
Simon Glassba64a0b2018-09-14 04:57:29 -06001831 map=True)
Simon Glassc6c10e72019-05-17 22:00:46 -06001832 expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA +
1833 MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA +
1834 tools.GetBytes(ord('c'), 8) + U_BOOT_DATA +
1835 tools.GetBytes(ord('d'), 8))
Simon Glassba64a0b2018-09-14 04:57:29 -06001836 self.assertEqual(expect, data)
1837 self.assertEqual('''ImagePos Offset Size Name
183800000000 00000000 00000028 main-section
183900000000 00000000 00000008 fill
184000000008 00000008 00000004 u-boot
18410000000c 0000000c 00000004 section
18420000000c 00000000 00000003 intel-mrc
184300000010 00000010 00000004 u-boot2
184400000014 00000014 0000000c section2
184500000014 00000000 00000008 fill
18460000001c 00000008 00000004 u-boot
184700000020 00000020 00000008 fill2
1848''', map_data)
1849
1850 def testExpandSizeBad(self):
1851 """Test an expanding entry which fails to provide contents"""
Simon Glass163ed6c2018-09-14 04:57:36 -06001852 with test_util.capture_sys_output() as (stdout, stderr):
1853 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001854 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
Simon Glassba64a0b2018-09-14 04:57:29 -06001855 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
1856 'expanding entry', str(e.exception))
1857
Simon Glasse0e5df92018-09-14 04:57:31 -06001858 def testHash(self):
1859 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001860 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06001861 use_real_dtb=True, update_dtb=True)
1862 dtb = fdt.Fdt(out_dtb_fname)
1863 dtb.Scan()
1864 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
1865 m = hashlib.sha256()
1866 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001867 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06001868
1869 def testHashNoAlgo(self):
1870 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001871 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06001872 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
1873 'hash node', str(e.exception))
1874
1875 def testHashBadAlgo(self):
1876 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001877 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06001878 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
1879 str(e.exception))
1880
1881 def testHashSection(self):
1882 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001883 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06001884 use_real_dtb=True, update_dtb=True)
1885 dtb = fdt.Fdt(out_dtb_fname)
1886 dtb.Scan()
1887 hash_node = dtb.GetNode('/binman/section/hash').props['value']
1888 m = hashlib.sha256()
1889 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001890 m.update(tools.GetBytes(ord('a'), 16))
1891 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06001892
Simon Glassf0253632018-09-14 04:57:32 -06001893 def testPackUBootTplMicrocode(self):
1894 """Test that x86 microcode can be handled correctly in TPL
1895
1896 We expect to see the following in the image, in order:
1897 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
1898 place
1899 u-boot-tpl.dtb with the microcode removed
1900 the microcode
1901 """
Simon Glass2090f1e2019-08-24 07:23:00 -06001902 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass741f2d62018-10-01 12:22:30 -06001903 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glassf0253632018-09-14 04:57:32 -06001904 U_BOOT_TPL_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001905 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
1906 b'ter somewhere in here', first)
Simon Glassf0253632018-09-14 04:57:32 -06001907
Simon Glassf8f8df62018-09-14 04:57:34 -06001908 def testFmapX86(self):
1909 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001910 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassf8f8df62018-09-14 04:57:34 -06001911 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc6c10e72019-05-17 22:00:46 -06001912 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06001913 self.assertEqual(expected, data[:32])
1914 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1915
1916 self.assertEqual(0x100, fhdr.image_size)
1917
1918 self.assertEqual(0, fentries[0].offset)
1919 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001920 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001921
1922 self.assertEqual(4, fentries[1].offset)
1923 self.assertEqual(3, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001924 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001925
1926 self.assertEqual(32, fentries[2].offset)
1927 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1928 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001929 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001930
1931 def testFmapX86Section(self):
1932 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001933 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glassc6c10e72019-05-17 22:00:46 -06001934 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06001935 self.assertEqual(expected, data[:32])
1936 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
1937
1938 self.assertEqual(0x100, fhdr.image_size)
1939
1940 self.assertEqual(0, fentries[0].offset)
1941 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001942 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001943
1944 self.assertEqual(4, fentries[1].offset)
1945 self.assertEqual(3, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001946 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001947
1948 self.assertEqual(36, fentries[2].offset)
1949 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1950 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001951 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001952
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001953 def testElf(self):
1954 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001955 self._SetupSplElf()
Simon Glass2090f1e2019-08-24 07:23:00 -06001956 self._SetupTplElf()
Simon Glass53e22bf2019-08-24 07:22:53 -06001957 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001958 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001959 data = self._DoReadFile('096_elf.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001960
Simon Glass093d1682019-07-08 13:18:25 -06001961 def testElfStrip(self):
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001962 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001963 self._SetupSplElf()
Simon Glass53e22bf2019-08-24 07:22:53 -06001964 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001965 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001966 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001967
Simon Glass163ed6c2018-09-14 04:57:36 -06001968 def testPackOverlapMap(self):
1969 """Test that overlapping regions are detected"""
1970 with test_util.capture_sys_output() as (stdout, stderr):
1971 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001972 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glass163ed6c2018-09-14 04:57:36 -06001973 map_fname = tools.GetOutputFilename('image.map')
1974 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
1975 stdout.getvalue())
1976
1977 # We should not get an inmage, but there should be a map file
1978 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
1979 self.assertTrue(os.path.exists(map_fname))
Simon Glasseb546ac2019-05-17 22:00:51 -06001980 map_data = tools.ReadFile(map_fname, binary=False)
Simon Glass163ed6c2018-09-14 04:57:36 -06001981 self.assertEqual('''ImagePos Offset Size Name
1982<none> 00000000 00000007 main-section
1983<none> 00000000 00000004 u-boot
1984<none> 00000003 00000004 u-boot-align
1985''', map_data)
1986
Simon Glass093d1682019-07-08 13:18:25 -06001987 def testPackRefCode(self):
Simon Glass3ae192c2018-10-01 12:22:31 -06001988 """Test that an image with an Intel Reference code binary works"""
1989 data = self._DoReadFile('100_intel_refcode.dts')
1990 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
1991
Simon Glass9481c802019-04-25 21:58:39 -06001992 def testSectionOffset(self):
1993 """Tests use of a section with an offset"""
1994 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
1995 map=True)
1996 self.assertEqual('''ImagePos Offset Size Name
199700000000 00000000 00000038 main-section
199800000004 00000004 00000010 section@0
199900000004 00000000 00000004 u-boot
200000000018 00000018 00000010 section@1
200100000018 00000000 00000004 u-boot
20020000002c 0000002c 00000004 section@2
20030000002c 00000000 00000004 u-boot
2004''', map_data)
2005 self.assertEqual(data,
Simon Glasse6d85ff2019-05-14 15:53:47 -06002006 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2007 tools.GetBytes(0x21, 12) +
2008 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2009 tools.GetBytes(0x61, 12) +
2010 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2011 tools.GetBytes(0x26, 8))
Simon Glass9481c802019-04-25 21:58:39 -06002012
Simon Glassac62fba2019-07-08 13:18:53 -06002013 def testCbfsRaw(self):
2014 """Test base handling of a Coreboot Filesystem (CBFS)
2015
2016 The exact contents of the CBFS is verified by similar tests in
2017 cbfs_util_test.py. The tests here merely check that the files added to
2018 the CBFS can be found in the final image.
2019 """
2020 data = self._DoReadFile('102_cbfs_raw.dts')
2021 size = 0xb0
2022
2023 cbfs = cbfs_util.CbfsReader(data)
2024 self.assertEqual(size, cbfs.rom_size)
2025
2026 self.assertIn('u-boot-dtb', cbfs.files)
2027 cfile = cbfs.files['u-boot-dtb']
2028 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2029
2030 def testCbfsArch(self):
2031 """Test on non-x86 architecture"""
2032 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2033 size = 0x100
2034
2035 cbfs = cbfs_util.CbfsReader(data)
2036 self.assertEqual(size, cbfs.rom_size)
2037
2038 self.assertIn('u-boot-dtb', cbfs.files)
2039 cfile = cbfs.files['u-boot-dtb']
2040 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2041
2042 def testCbfsStage(self):
2043 """Tests handling of a Coreboot Filesystem (CBFS)"""
2044 if not elf.ELF_TOOLS:
2045 self.skipTest('Python elftools not available')
2046 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2047 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2048 size = 0xb0
2049
2050 data = self._DoReadFile('104_cbfs_stage.dts')
2051 cbfs = cbfs_util.CbfsReader(data)
2052 self.assertEqual(size, cbfs.rom_size)
2053
2054 self.assertIn('u-boot', cbfs.files)
2055 cfile = cbfs.files['u-boot']
2056 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2057
2058 def testCbfsRawCompress(self):
2059 """Test handling of compressing raw files"""
2060 self._CheckLz4()
2061 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2062 size = 0x140
2063
2064 cbfs = cbfs_util.CbfsReader(data)
2065 self.assertIn('u-boot', cbfs.files)
2066 cfile = cbfs.files['u-boot']
2067 self.assertEqual(COMPRESS_DATA, cfile.data)
2068
2069 def testCbfsBadArch(self):
2070 """Test handling of a bad architecture"""
2071 with self.assertRaises(ValueError) as e:
2072 self._DoReadFile('106_cbfs_bad_arch.dts')
2073 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2074
2075 def testCbfsNoSize(self):
2076 """Test handling of a missing size property"""
2077 with self.assertRaises(ValueError) as e:
2078 self._DoReadFile('107_cbfs_no_size.dts')
2079 self.assertIn('entry must have a size property', str(e.exception))
2080
2081 def testCbfsNoCOntents(self):
2082 """Test handling of a CBFS entry which does not provide contentsy"""
2083 with self.assertRaises(ValueError) as e:
2084 self._DoReadFile('108_cbfs_no_contents.dts')
2085 self.assertIn('Could not complete processing of contents',
2086 str(e.exception))
2087
2088 def testCbfsBadCompress(self):
2089 """Test handling of a bad architecture"""
2090 with self.assertRaises(ValueError) as e:
2091 self._DoReadFile('109_cbfs_bad_compress.dts')
2092 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2093 str(e.exception))
2094
2095 def testCbfsNamedEntries(self):
2096 """Test handling of named entries"""
2097 data = self._DoReadFile('110_cbfs_name.dts')
2098
2099 cbfs = cbfs_util.CbfsReader(data)
2100 self.assertIn('FRED', cbfs.files)
2101 cfile1 = cbfs.files['FRED']
2102 self.assertEqual(U_BOOT_DATA, cfile1.data)
2103
2104 self.assertIn('hello', cbfs.files)
2105 cfile2 = cbfs.files['hello']
2106 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2107
Simon Glassc5ac1382019-07-08 13:18:54 -06002108 def _SetupIfwi(self, fname):
2109 """Set up to run an IFWI test
2110
2111 Args:
2112 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2113 """
2114 self._SetupSplElf()
Simon Glass2090f1e2019-08-24 07:23:00 -06002115 self._SetupTplElf()
Simon Glassc5ac1382019-07-08 13:18:54 -06002116
2117 # Intel Integrated Firmware Image (IFWI) file
2118 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2119 data = fd.read()
2120 TestFunctional._MakeInputFile(fname,data)
2121
2122 def _CheckIfwi(self, data):
2123 """Check that an image with an IFWI contains the correct output
2124
2125 Args:
2126 data: Conents of output file
2127 """
2128 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
2129 if data[:0x1000] != expected_desc:
2130 self.fail('Expected descriptor binary at start of image')
2131
2132 # We expect to find the TPL wil in subpart IBBP entry IBBL
2133 image_fname = tools.GetOutputFilename('image.bin')
2134 tpl_fname = tools.GetOutputFilename('tpl.out')
2135 tools.RunIfwiTool(image_fname, tools.CMD_EXTRACT, fname=tpl_fname,
2136 subpart='IBBP', entry_name='IBBL')
2137
2138 tpl_data = tools.ReadFile(tpl_fname)
Simon Glasse95be632019-08-24 07:22:51 -06002139 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glassc5ac1382019-07-08 13:18:54 -06002140
2141 def testPackX86RomIfwi(self):
2142 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2143 self._SetupIfwi('fitimage.bin')
Simon Glass9255f3c2019-08-24 07:23:01 -06002144 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002145 self._CheckIfwi(data)
2146
2147 def testPackX86RomIfwiNoDesc(self):
2148 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2149 self._SetupIfwi('ifwi.bin')
Simon Glass9255f3c2019-08-24 07:23:01 -06002150 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002151 self._CheckIfwi(data)
2152
2153 def testPackX86RomIfwiNoData(self):
2154 """Test that an x86 ROM with IFWI handles missing data"""
2155 self._SetupIfwi('ifwi.bin')
2156 with self.assertRaises(ValueError) as e:
Simon Glass9255f3c2019-08-24 07:23:01 -06002157 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002158 self.assertIn('Could not complete processing of contents',
2159 str(e.exception))
Simon Glass53af22a2018-07-17 13:25:32 -06002160
Simon Glasse073d4e2019-07-08 13:18:56 -06002161 def testCbfsOffset(self):
2162 """Test a CBFS with files at particular offsets
2163
2164 Like all CFBS tests, this is just checking the logic that calls
2165 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2166 """
2167 data = self._DoReadFile('114_cbfs_offset.dts')
2168 size = 0x200
2169
2170 cbfs = cbfs_util.CbfsReader(data)
2171 self.assertEqual(size, cbfs.rom_size)
2172
2173 self.assertIn('u-boot', cbfs.files)
2174 cfile = cbfs.files['u-boot']
2175 self.assertEqual(U_BOOT_DATA, cfile.data)
2176 self.assertEqual(0x40, cfile.cbfs_offset)
2177
2178 self.assertIn('u-boot-dtb', cbfs.files)
2179 cfile2 = cbfs.files['u-boot-dtb']
2180 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2181 self.assertEqual(0x140, cfile2.cbfs_offset)
2182
Simon Glass086cec92019-07-08 14:25:27 -06002183 def testFdtmap(self):
2184 """Test an FDT map can be inserted in the image"""
2185 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2186 fdtmap_data = data[len(U_BOOT_DATA):]
2187 magic = fdtmap_data[:8]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002188 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass086cec92019-07-08 14:25:27 -06002189 self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
2190
2191 fdt_data = fdtmap_data[16:]
2192 dtb = fdt.Fdt.FromData(fdt_data)
2193 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002194 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass086cec92019-07-08 14:25:27 -06002195 self.assertEqual({
2196 'image-pos': 0,
2197 'offset': 0,
2198 'u-boot:offset': 0,
2199 'u-boot:size': len(U_BOOT_DATA),
2200 'u-boot:image-pos': 0,
2201 'fdtmap:image-pos': 4,
2202 'fdtmap:offset': 4,
2203 'fdtmap:size': len(fdtmap_data),
2204 'size': len(data),
2205 }, props)
2206
2207 def testFdtmapNoMatch(self):
2208 """Check handling of an FDT map when the section cannot be found"""
2209 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2210
2211 # Mangle the section name, which should cause a mismatch between the
2212 # correct FDT path and the one expected by the section
2213 image = control.images['image']
Simon Glasscf228942019-07-08 14:25:28 -06002214 image._node.path += '-suffix'
Simon Glass086cec92019-07-08 14:25:27 -06002215 entries = image.GetEntries()
2216 fdtmap = entries['fdtmap']
2217 with self.assertRaises(ValueError) as e:
2218 fdtmap._GetFdtmap()
2219 self.assertIn("Cannot locate node for path '/binman-suffix'",
2220 str(e.exception))
2221
Simon Glasscf228942019-07-08 14:25:28 -06002222 def testFdtmapHeader(self):
2223 """Test an FDT map and image header can be inserted in the image"""
2224 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2225 fdtmap_pos = len(U_BOOT_DATA)
2226 fdtmap_data = data[fdtmap_pos:]
2227 fdt_data = fdtmap_data[16:]
2228 dtb = fdt.Fdt.FromData(fdt_data)
2229 fdt_size = dtb.GetFdtObj().totalsize()
2230 hdr_data = data[-8:]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002231 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002232 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2233 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2234
2235 def testFdtmapHeaderStart(self):
2236 """Test an image header can be inserted at the image start"""
2237 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2238 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2239 hdr_data = data[:8]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002240 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002241 offset = struct.unpack('<I', hdr_data[4:])[0]
2242 self.assertEqual(fdtmap_pos, offset)
2243
2244 def testFdtmapHeaderPos(self):
2245 """Test an image header can be inserted at a chosen position"""
2246 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2247 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2248 hdr_data = data[0x80:0x88]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002249 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002250 offset = struct.unpack('<I', hdr_data[4:])[0]
2251 self.assertEqual(fdtmap_pos, offset)
2252
2253 def testHeaderMissingFdtmap(self):
2254 """Test an image header requires an fdtmap"""
2255 with self.assertRaises(ValueError) as e:
2256 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2257 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2258 str(e.exception))
2259
2260 def testHeaderNoLocation(self):
2261 """Test an image header with a no specified location is detected"""
2262 with self.assertRaises(ValueError) as e:
2263 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2264 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2265 str(e.exception))
2266
Simon Glassc52c9e72019-07-08 14:25:37 -06002267 def testEntryExpand(self):
2268 """Test expanding an entry after it is packed"""
2269 data = self._DoReadFile('121_entry_expand.dts')
Simon Glass79d3c582019-07-20 12:23:57 -06002270 self.assertEqual(b'aaa', data[:3])
2271 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2272 self.assertEqual(b'aaa', data[-3:])
Simon Glassc52c9e72019-07-08 14:25:37 -06002273
2274 def testEntryExpandBad(self):
2275 """Test expanding an entry after it is packed, twice"""
2276 with self.assertRaises(ValueError) as e:
2277 self._DoReadFile('122_entry_expand_twice.dts')
Simon Glass61ec04f2019-07-20 12:23:58 -06002278 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glassc52c9e72019-07-08 14:25:37 -06002279 str(e.exception))
2280
2281 def testEntryExpandSection(self):
2282 """Test expanding an entry within a section after it is packed"""
2283 data = self._DoReadFile('123_entry_expand_section.dts')
Simon Glass79d3c582019-07-20 12:23:57 -06002284 self.assertEqual(b'aaa', data[:3])
2285 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2286 self.assertEqual(b'aaa', data[-3:])
Simon Glassc52c9e72019-07-08 14:25:37 -06002287
Simon Glass6c223fd2019-07-08 14:25:38 -06002288 def testCompressDtb(self):
2289 """Test that compress of device-tree files is supported"""
2290 self._CheckLz4()
2291 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2292 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2293 comp_data = data[len(U_BOOT_DATA):]
2294 orig = self._decompress(comp_data)
2295 dtb = fdt.Fdt.FromData(orig)
2296 dtb.Scan()
2297 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2298 expected = {
2299 'u-boot:size': len(U_BOOT_DATA),
2300 'u-boot-dtb:uncomp-size': len(orig),
2301 'u-boot-dtb:size': len(comp_data),
2302 'size': len(data),
2303 }
2304 self.assertEqual(expected, props)
2305
Simon Glass69f7cb32019-07-08 14:25:41 -06002306 def testCbfsUpdateFdt(self):
2307 """Test that we can update the device tree with CBFS offset/size info"""
2308 self._CheckLz4()
2309 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2310 update_dtb=True)
2311 dtb = fdt.Fdt(out_dtb_fname)
2312 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002313 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass69f7cb32019-07-08 14:25:41 -06002314 del props['cbfs/u-boot:size']
2315 self.assertEqual({
2316 'offset': 0,
2317 'size': len(data),
2318 'image-pos': 0,
2319 'cbfs:offset': 0,
2320 'cbfs:size': len(data),
2321 'cbfs:image-pos': 0,
2322 'cbfs/u-boot:offset': 0x38,
2323 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2324 'cbfs/u-boot:image-pos': 0x38,
2325 'cbfs/u-boot-dtb:offset': 0xb8,
2326 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2327 'cbfs/u-boot-dtb:image-pos': 0xb8,
2328 }, props)
2329
Simon Glass8a1ad062019-07-08 14:25:42 -06002330 def testCbfsBadType(self):
2331 """Test an image header with a no specified location is detected"""
2332 with self.assertRaises(ValueError) as e:
2333 self._DoReadFile('126_cbfs_bad_type.dts')
2334 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2335
Simon Glass41b8ba02019-07-08 14:25:43 -06002336 def testList(self):
2337 """Test listing the files in an image"""
2338 self._CheckLz4()
2339 data = self._DoReadFile('127_list.dts')
2340 image = control.images['image']
2341 entries = image.BuildEntryList()
2342 self.assertEqual(7, len(entries))
2343
2344 ent = entries[0]
2345 self.assertEqual(0, ent.indent)
2346 self.assertEqual('main-section', ent.name)
2347 self.assertEqual('section', ent.etype)
2348 self.assertEqual(len(data), ent.size)
2349 self.assertEqual(0, ent.image_pos)
2350 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002351 self.assertEqual(0, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002352
2353 ent = entries[1]
2354 self.assertEqual(1, ent.indent)
2355 self.assertEqual('u-boot', ent.name)
2356 self.assertEqual('u-boot', ent.etype)
2357 self.assertEqual(len(U_BOOT_DATA), ent.size)
2358 self.assertEqual(0, ent.image_pos)
2359 self.assertEqual(None, ent.uncomp_size)
2360 self.assertEqual(0, ent.offset)
2361
2362 ent = entries[2]
2363 self.assertEqual(1, ent.indent)
2364 self.assertEqual('section', ent.name)
2365 self.assertEqual('section', ent.etype)
2366 section_size = ent.size
2367 self.assertEqual(0x100, ent.image_pos)
2368 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002369 self.assertEqual(0x100, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002370
2371 ent = entries[3]
2372 self.assertEqual(2, ent.indent)
2373 self.assertEqual('cbfs', ent.name)
2374 self.assertEqual('cbfs', ent.etype)
2375 self.assertEqual(0x400, ent.size)
2376 self.assertEqual(0x100, ent.image_pos)
2377 self.assertEqual(None, ent.uncomp_size)
2378 self.assertEqual(0, ent.offset)
2379
2380 ent = entries[4]
2381 self.assertEqual(3, ent.indent)
2382 self.assertEqual('u-boot', ent.name)
2383 self.assertEqual('u-boot', ent.etype)
2384 self.assertEqual(len(U_BOOT_DATA), ent.size)
2385 self.assertEqual(0x138, ent.image_pos)
2386 self.assertEqual(None, ent.uncomp_size)
2387 self.assertEqual(0x38, ent.offset)
2388
2389 ent = entries[5]
2390 self.assertEqual(3, ent.indent)
2391 self.assertEqual('u-boot-dtb', ent.name)
2392 self.assertEqual('text', ent.etype)
2393 self.assertGreater(len(COMPRESS_DATA), ent.size)
2394 self.assertEqual(0x178, ent.image_pos)
2395 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2396 self.assertEqual(0x78, ent.offset)
2397
2398 ent = entries[6]
2399 self.assertEqual(2, ent.indent)
2400 self.assertEqual('u-boot-dtb', ent.name)
2401 self.assertEqual('u-boot-dtb', ent.etype)
2402 self.assertEqual(0x500, ent.image_pos)
2403 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2404 dtb_size = ent.size
2405 # Compressing this data expands it since headers are added
2406 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2407 self.assertEqual(0x400, ent.offset)
2408
2409 self.assertEqual(len(data), 0x100 + section_size)
2410 self.assertEqual(section_size, 0x400 + dtb_size)
2411
Simon Glasse1925fa2019-07-08 14:25:44 -06002412 def testFindFdtmap(self):
2413 """Test locating an FDT map in an image"""
2414 self._CheckLz4()
2415 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2416 image = control.images['image']
2417 entries = image.GetEntries()
2418 entry = entries['fdtmap']
2419 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2420
2421 def testFindFdtmapMissing(self):
2422 """Test failing to locate an FDP map"""
2423 data = self._DoReadFile('005_simple.dts')
2424 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2425
Simon Glass2d260032019-07-08 14:25:45 -06002426 def testFindImageHeader(self):
2427 """Test locating a image header"""
2428 self._CheckLz4()
Simon Glassffded752019-07-08 14:25:46 -06002429 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002430 image = control.images['image']
2431 entries = image.GetEntries()
2432 entry = entries['fdtmap']
2433 # The header should point to the FDT map
2434 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2435
2436 def testFindImageHeaderStart(self):
2437 """Test locating a image header located at the start of an image"""
Simon Glassffded752019-07-08 14:25:46 -06002438 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002439 image = control.images['image']
2440 entries = image.GetEntries()
2441 entry = entries['fdtmap']
2442 # The header should point to the FDT map
2443 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2444
2445 def testFindImageHeaderMissing(self):
2446 """Test failing to locate an image header"""
2447 data = self._DoReadFile('005_simple.dts')
2448 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2449
Simon Glassffded752019-07-08 14:25:46 -06002450 def testReadImage(self):
2451 """Test reading an image and accessing its FDT map"""
2452 self._CheckLz4()
2453 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2454 image_fname = tools.GetOutputFilename('image.bin')
2455 orig_image = control.images['image']
2456 image = Image.FromFile(image_fname)
2457 self.assertEqual(orig_image.GetEntries().keys(),
2458 image.GetEntries().keys())
2459
2460 orig_entry = orig_image.GetEntries()['fdtmap']
2461 entry = image.GetEntries()['fdtmap']
2462 self.assertEquals(orig_entry.offset, entry.offset)
2463 self.assertEquals(orig_entry.size, entry.size)
2464 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2465
2466 def testReadImageNoHeader(self):
2467 """Test accessing an image's FDT map without an image header"""
2468 self._CheckLz4()
2469 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
2470 image_fname = tools.GetOutputFilename('image.bin')
2471 image = Image.FromFile(image_fname)
2472 self.assertTrue(isinstance(image, Image))
Simon Glass10f9d002019-07-20 12:23:50 -06002473 self.assertEqual('image', image.image_name[-5:])
Simon Glassffded752019-07-08 14:25:46 -06002474
2475 def testReadImageFail(self):
2476 """Test failing to read an image image's FDT map"""
2477 self._DoReadFile('005_simple.dts')
2478 image_fname = tools.GetOutputFilename('image.bin')
2479 with self.assertRaises(ValueError) as e:
2480 image = Image.FromFile(image_fname)
2481 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glasse073d4e2019-07-08 13:18:56 -06002482
Simon Glass61f564d2019-07-08 14:25:48 -06002483 def testListCmd(self):
2484 """Test listing the files in an image using an Fdtmap"""
2485 self._CheckLz4()
2486 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2487
2488 # lz4 compression size differs depending on the version
2489 image = control.images['image']
2490 entries = image.GetEntries()
2491 section_size = entries['section'].size
2492 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2493 fdtmap_offset = entries['fdtmap'].offset
2494
Simon Glassf86a7362019-07-20 12:24:10 -06002495 try:
2496 tmpdir, updated_fname = self._SetupImageInTmpdir()
2497 with test_util.capture_sys_output() as (stdout, stderr):
2498 self._DoBinman('ls', '-i', updated_fname)
2499 finally:
2500 shutil.rmtree(tmpdir)
Simon Glass61f564d2019-07-08 14:25:48 -06002501 lines = stdout.getvalue().splitlines()
2502 expected = [
2503'Name Image-pos Size Entry-type Offset Uncomp-size',
2504'----------------------------------------------------------------------',
2505'main-section 0 c00 section 0',
2506' u-boot 0 4 u-boot 0',
2507' section 100 %x section 100' % section_size,
2508' cbfs 100 400 cbfs 0',
2509' u-boot 138 4 u-boot 38',
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002510' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glass61f564d2019-07-08 14:25:48 -06002511' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002512' fdtmap %x 3bd fdtmap %x' %
Simon Glass61f564d2019-07-08 14:25:48 -06002513 (fdtmap_offset, fdtmap_offset),
2514' image-header bf8 8 image-header bf8',
2515 ]
2516 self.assertEqual(expected, lines)
2517
2518 def testListCmdFail(self):
2519 """Test failing to list an image"""
2520 self._DoReadFile('005_simple.dts')
Simon Glassf86a7362019-07-20 12:24:10 -06002521 try:
2522 tmpdir, updated_fname = self._SetupImageInTmpdir()
2523 with self.assertRaises(ValueError) as e:
2524 self._DoBinman('ls', '-i', updated_fname)
2525 finally:
2526 shutil.rmtree(tmpdir)
Simon Glass61f564d2019-07-08 14:25:48 -06002527 self.assertIn("Cannot find FDT map in image", str(e.exception))
2528
2529 def _RunListCmd(self, paths, expected):
2530 """List out entries and check the result
2531
2532 Args:
2533 paths: List of paths to pass to the list command
2534 expected: Expected list of filenames to be returned, in order
2535 """
2536 self._CheckLz4()
2537 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2538 image_fname = tools.GetOutputFilename('image.bin')
2539 image = Image.FromFile(image_fname)
2540 lines = image.GetListEntries(paths)[1]
2541 files = [line[0].strip() for line in lines[1:]]
2542 self.assertEqual(expected, files)
2543
2544 def testListCmdSection(self):
2545 """Test listing the files in a section"""
2546 self._RunListCmd(['section'],
2547 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2548
2549 def testListCmdFile(self):
2550 """Test listing a particular file"""
2551 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2552
2553 def testListCmdWildcard(self):
2554 """Test listing a wildcarded file"""
2555 self._RunListCmd(['*boot*'],
2556 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2557
2558 def testListCmdWildcardMulti(self):
2559 """Test listing a wildcarded file"""
2560 self._RunListCmd(['*cb*', '*head*'],
2561 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2562
2563 def testListCmdEmpty(self):
2564 """Test listing a wildcarded file"""
2565 self._RunListCmd(['nothing'], [])
2566
2567 def testListCmdPath(self):
2568 """Test listing the files in a sub-entry of a section"""
2569 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2570
Simon Glassf667e452019-07-08 14:25:50 -06002571 def _RunExtractCmd(self, entry_name, decomp=True):
2572 """Extract an entry from an image
2573
2574 Args:
2575 entry_name: Entry name to extract
2576 decomp: True to decompress the data if compressed, False to leave
2577 it in its raw uncompressed format
2578
2579 Returns:
2580 data from entry
2581 """
2582 self._CheckLz4()
2583 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2584 image_fname = tools.GetOutputFilename('image.bin')
2585 return control.ReadEntry(image_fname, entry_name, decomp)
2586
2587 def testExtractSimple(self):
2588 """Test extracting a single file"""
2589 data = self._RunExtractCmd('u-boot')
2590 self.assertEqual(U_BOOT_DATA, data)
2591
Simon Glass71ce0ba2019-07-08 14:25:52 -06002592 def testExtractSection(self):
2593 """Test extracting the files in a section"""
2594 data = self._RunExtractCmd('section')
2595 cbfs_data = data[:0x400]
2596 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002597 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass71ce0ba2019-07-08 14:25:52 -06002598 dtb_data = data[0x400:]
2599 dtb = self._decompress(dtb_data)
2600 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2601
2602 def testExtractCompressed(self):
2603 """Test extracting compressed data"""
2604 data = self._RunExtractCmd('section/u-boot-dtb')
2605 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2606
2607 def testExtractRaw(self):
2608 """Test extracting compressed data without decompressing it"""
2609 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2610 dtb = self._decompress(data)
2611 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2612
2613 def testExtractCbfs(self):
2614 """Test extracting CBFS data"""
2615 data = self._RunExtractCmd('section/cbfs/u-boot')
2616 self.assertEqual(U_BOOT_DATA, data)
2617
2618 def testExtractCbfsCompressed(self):
2619 """Test extracting CBFS compressed data"""
2620 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2621 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2622
2623 def testExtractCbfsRaw(self):
2624 """Test extracting CBFS compressed data without decompressing it"""
2625 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Simon Glasseb0f4a42019-07-20 12:24:06 -06002626 dtb = tools.Decompress(data, 'lzma', with_header=False)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002627 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2628
Simon Glassf667e452019-07-08 14:25:50 -06002629 def testExtractBadEntry(self):
2630 """Test extracting a bad section path"""
2631 with self.assertRaises(ValueError) as e:
2632 self._RunExtractCmd('section/does-not-exist')
2633 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2634 str(e.exception))
2635
2636 def testExtractMissingFile(self):
2637 """Test extracting file that does not exist"""
2638 with self.assertRaises(IOError) as e:
2639 control.ReadEntry('missing-file', 'name')
2640
2641 def testExtractBadFile(self):
2642 """Test extracting an invalid file"""
2643 fname = os.path.join(self._indir, 'badfile')
2644 tools.WriteFile(fname, b'')
2645 with self.assertRaises(ValueError) as e:
2646 control.ReadEntry(fname, 'name')
2647
Simon Glass71ce0ba2019-07-08 14:25:52 -06002648 def testExtractCmd(self):
2649 """Test extracting a file fron an image on the command line"""
2650 self._CheckLz4()
2651 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass71ce0ba2019-07-08 14:25:52 -06002652 fname = os.path.join(self._indir, 'output.extact')
Simon Glassf86a7362019-07-20 12:24:10 -06002653 try:
2654 tmpdir, updated_fname = self._SetupImageInTmpdir()
2655 with test_util.capture_sys_output() as (stdout, stderr):
2656 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2657 '-f', fname)
2658 finally:
2659 shutil.rmtree(tmpdir)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002660 data = tools.ReadFile(fname)
2661 self.assertEqual(U_BOOT_DATA, data)
2662
2663 def testExtractOneEntry(self):
2664 """Test extracting a single entry fron an image """
2665 self._CheckLz4()
2666 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2667 image_fname = tools.GetOutputFilename('image.bin')
2668 fname = os.path.join(self._indir, 'output.extact')
2669 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
2670 data = tools.ReadFile(fname)
2671 self.assertEqual(U_BOOT_DATA, data)
2672
2673 def _CheckExtractOutput(self, decomp):
2674 """Helper to test file output with and without decompression
2675
2676 Args:
2677 decomp: True to decompress entry data, False to output it raw
2678 """
2679 def _CheckPresent(entry_path, expect_data, expect_size=None):
2680 """Check and remove expected file
2681
2682 This checks the data/size of a file and removes the file both from
2683 the outfiles set and from the output directory. Once all files are
2684 processed, both the set and directory should be empty.
2685
2686 Args:
2687 entry_path: Entry path
2688 expect_data: Data to expect in file, or None to skip check
2689 expect_size: Size of data to expect in file, or None to skip
2690 """
2691 path = os.path.join(outdir, entry_path)
2692 data = tools.ReadFile(path)
2693 os.remove(path)
2694 if expect_data:
2695 self.assertEqual(expect_data, data)
2696 elif expect_size:
2697 self.assertEqual(expect_size, len(data))
2698 outfiles.remove(path)
2699
2700 def _CheckDirPresent(name):
2701 """Remove expected directory
2702
2703 This gives an error if the directory does not exist as expected
2704
2705 Args:
2706 name: Name of directory to remove
2707 """
2708 path = os.path.join(outdir, name)
2709 os.rmdir(path)
2710
2711 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2712 image_fname = tools.GetOutputFilename('image.bin')
2713 outdir = os.path.join(self._indir, 'extract')
2714 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2715
2716 # Create a set of all file that were output (should be 9)
2717 outfiles = set()
2718 for root, dirs, files in os.walk(outdir):
2719 outfiles |= set([os.path.join(root, fname) for fname in files])
2720 self.assertEqual(9, len(outfiles))
2721 self.assertEqual(9, len(einfos))
2722
2723 image = control.images['image']
2724 entries = image.GetEntries()
2725
2726 # Check the 9 files in various ways
2727 section = entries['section']
2728 section_entries = section.GetEntries()
2729 cbfs_entries = section_entries['cbfs'].GetEntries()
2730 _CheckPresent('u-boot', U_BOOT_DATA)
2731 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
2732 dtb_len = EXTRACT_DTB_SIZE
2733 if not decomp:
2734 dtb_len = cbfs_entries['u-boot-dtb'].size
2735 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
2736 if not decomp:
2737 dtb_len = section_entries['u-boot-dtb'].size
2738 _CheckPresent('section/u-boot-dtb', None, dtb_len)
2739
2740 fdtmap = entries['fdtmap']
2741 _CheckPresent('fdtmap', fdtmap.data)
2742 hdr = entries['image-header']
2743 _CheckPresent('image-header', hdr.data)
2744
2745 _CheckPresent('section/root', section.data)
2746 cbfs = section_entries['cbfs']
2747 _CheckPresent('section/cbfs/root', cbfs.data)
2748 data = tools.ReadFile(image_fname)
2749 _CheckPresent('root', data)
2750
2751 # There should be no files left. Remove all the directories to check.
2752 # If there are any files/dirs remaining, one of these checks will fail.
2753 self.assertEqual(0, len(outfiles))
2754 _CheckDirPresent('section/cbfs')
2755 _CheckDirPresent('section')
2756 _CheckDirPresent('')
2757 self.assertFalse(os.path.exists(outdir))
2758
2759 def testExtractAllEntries(self):
2760 """Test extracting all entries"""
2761 self._CheckLz4()
2762 self._CheckExtractOutput(decomp=True)
2763
2764 def testExtractAllEntriesRaw(self):
2765 """Test extracting all entries without decompressing them"""
2766 self._CheckLz4()
2767 self._CheckExtractOutput(decomp=False)
2768
2769 def testExtractSelectedEntries(self):
2770 """Test extracting some entries"""
2771 self._CheckLz4()
2772 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2773 image_fname = tools.GetOutputFilename('image.bin')
2774 outdir = os.path.join(self._indir, 'extract')
2775 einfos = control.ExtractEntries(image_fname, None, outdir,
2776 ['*cb*', '*head*'])
2777
2778 # File output is tested by testExtractAllEntries(), so just check that
2779 # the expected entries are selected
2780 names = [einfo.name for einfo in einfos]
2781 self.assertEqual(names,
2782 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2783
2784 def testExtractNoEntryPaths(self):
2785 """Test extracting some entries"""
2786 self._CheckLz4()
2787 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2788 image_fname = tools.GetOutputFilename('image.bin')
2789 with self.assertRaises(ValueError) as e:
2790 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassbb5edc12019-07-20 12:24:14 -06002791 self.assertIn('Must specify an entry path to write with -f',
Simon Glass71ce0ba2019-07-08 14:25:52 -06002792 str(e.exception))
2793
2794 def testExtractTooManyEntryPaths(self):
2795 """Test extracting some entries"""
2796 self._CheckLz4()
2797 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2798 image_fname = tools.GetOutputFilename('image.bin')
2799 with self.assertRaises(ValueError) as e:
2800 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassbb5edc12019-07-20 12:24:14 -06002801 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass71ce0ba2019-07-08 14:25:52 -06002802 str(e.exception))
2803
Simon Glasse2705fa2019-07-08 14:25:53 -06002804 def testPackAlignSection(self):
2805 """Test that sections can have alignment"""
2806 self._DoReadFile('131_pack_align_section.dts')
2807
2808 self.assertIn('image', control.images)
2809 image = control.images['image']
2810 entries = image.GetEntries()
2811 self.assertEqual(3, len(entries))
2812
2813 # First u-boot
2814 self.assertIn('u-boot', entries)
2815 entry = entries['u-boot']
2816 self.assertEqual(0, entry.offset)
2817 self.assertEqual(0, entry.image_pos)
2818 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2819 self.assertEqual(len(U_BOOT_DATA), entry.size)
2820
2821 # Section0
2822 self.assertIn('section0', entries)
2823 section0 = entries['section0']
2824 self.assertEqual(0x10, section0.offset)
2825 self.assertEqual(0x10, section0.image_pos)
2826 self.assertEqual(len(U_BOOT_DATA), section0.size)
2827
2828 # Second u-boot
2829 section_entries = section0.GetEntries()
2830 self.assertIn('u-boot', section_entries)
2831 entry = section_entries['u-boot']
2832 self.assertEqual(0, entry.offset)
2833 self.assertEqual(0x10, entry.image_pos)
2834 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2835 self.assertEqual(len(U_BOOT_DATA), entry.size)
2836
2837 # Section1
2838 self.assertIn('section1', entries)
2839 section1 = entries['section1']
2840 self.assertEqual(0x14, section1.offset)
2841 self.assertEqual(0x14, section1.image_pos)
2842 self.assertEqual(0x20, section1.size)
2843
2844 # Second u-boot
2845 section_entries = section1.GetEntries()
2846 self.assertIn('u-boot', section_entries)
2847 entry = section_entries['u-boot']
2848 self.assertEqual(0, entry.offset)
2849 self.assertEqual(0x14, entry.image_pos)
2850 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2851 self.assertEqual(len(U_BOOT_DATA), entry.size)
2852
2853 # Section2
2854 self.assertIn('section2', section_entries)
2855 section2 = section_entries['section2']
2856 self.assertEqual(0x4, section2.offset)
2857 self.assertEqual(0x18, section2.image_pos)
2858 self.assertEqual(4, section2.size)
2859
2860 # Third u-boot
2861 section_entries = section2.GetEntries()
2862 self.assertIn('u-boot', section_entries)
2863 entry = section_entries['u-boot']
2864 self.assertEqual(0, entry.offset)
2865 self.assertEqual(0x18, entry.image_pos)
2866 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2867 self.assertEqual(len(U_BOOT_DATA), entry.size)
2868
Simon Glass51014aa2019-07-20 12:23:56 -06002869 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
2870 dts='132_replace.dts'):
Simon Glass10f9d002019-07-20 12:23:50 -06002871 """Replace an entry in an image
2872
2873 This writes the entry data to update it, then opens the updated file and
2874 returns the value that it now finds there.
2875
2876 Args:
2877 entry_name: Entry name to replace
2878 data: Data to replace it with
2879 decomp: True to compress the data if needed, False if data is
2880 already compressed so should be used as is
Simon Glass51014aa2019-07-20 12:23:56 -06002881 allow_resize: True to allow entries to change size, False to raise
2882 an exception
Simon Glass10f9d002019-07-20 12:23:50 -06002883
2884 Returns:
2885 Tuple:
2886 data from entry
2887 data from fdtmap (excluding header)
Simon Glass51014aa2019-07-20 12:23:56 -06002888 Image object that was modified
Simon Glass10f9d002019-07-20 12:23:50 -06002889 """
Simon Glass51014aa2019-07-20 12:23:56 -06002890 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass10f9d002019-07-20 12:23:50 -06002891 update_dtb=True)[1]
2892
2893 self.assertIn('image', control.images)
2894 image = control.images['image']
2895 entries = image.GetEntries()
2896 orig_dtb_data = entries['u-boot-dtb'].data
2897 orig_fdtmap_data = entries['fdtmap'].data
2898
2899 image_fname = tools.GetOutputFilename('image.bin')
2900 updated_fname = tools.GetOutputFilename('image-updated.bin')
2901 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
Simon Glass51014aa2019-07-20 12:23:56 -06002902 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
2903 allow_resize)
Simon Glass10f9d002019-07-20 12:23:50 -06002904 data = control.ReadEntry(updated_fname, entry_name, decomp)
2905
Simon Glass51014aa2019-07-20 12:23:56 -06002906 # The DT data should not change unless resized:
2907 if not allow_resize:
2908 new_dtb_data = entries['u-boot-dtb'].data
2909 self.assertEqual(new_dtb_data, orig_dtb_data)
2910 new_fdtmap_data = entries['fdtmap'].data
2911 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass10f9d002019-07-20 12:23:50 -06002912
Simon Glass51014aa2019-07-20 12:23:56 -06002913 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass10f9d002019-07-20 12:23:50 -06002914
2915 def testReplaceSimple(self):
2916 """Test replacing a single file"""
2917 expected = b'x' * len(U_BOOT_DATA)
Simon Glass51014aa2019-07-20 12:23:56 -06002918 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
2919 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06002920 self.assertEqual(expected, data)
2921
2922 # Test that the state looks right. There should be an FDT for the fdtmap
2923 # that we jsut read back in, and it should match what we find in the
2924 # 'control' tables. Checking for an FDT that does not exist should
2925 # return None.
2926 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glass51014aa2019-07-20 12:23:56 -06002927 self.assertIsNotNone(path)
Simon Glass10f9d002019-07-20 12:23:50 -06002928 self.assertEqual(expected_fdtmap, fdtmap)
2929
2930 dtb = state.GetFdtForEtype('fdtmap')
2931 self.assertEqual(dtb.GetContents(), fdtmap)
2932
2933 missing_path, missing_fdtmap = state.GetFdtContents('missing')
2934 self.assertIsNone(missing_path)
2935 self.assertIsNone(missing_fdtmap)
2936
2937 missing_dtb = state.GetFdtForEtype('missing')
2938 self.assertIsNone(missing_dtb)
2939
2940 self.assertEqual('/binman', state.fdt_path_prefix)
2941
2942 def testReplaceResizeFail(self):
2943 """Test replacing a file by something larger"""
2944 expected = U_BOOT_DATA + b'x'
2945 with self.assertRaises(ValueError) as e:
Simon Glass51014aa2019-07-20 12:23:56 -06002946 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
2947 dts='139_replace_repack.dts')
Simon Glass10f9d002019-07-20 12:23:50 -06002948 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
2949 str(e.exception))
2950
2951 def testReplaceMulti(self):
2952 """Test replacing entry data where multiple images are generated"""
2953 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
2954 update_dtb=True)[0]
2955 expected = b'x' * len(U_BOOT_DATA)
2956 updated_fname = tools.GetOutputFilename('image-updated.bin')
2957 tools.WriteFile(updated_fname, data)
2958 entry_name = 'u-boot'
Simon Glass51014aa2019-07-20 12:23:56 -06002959 control.WriteEntry(updated_fname, entry_name, expected,
2960 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06002961 data = control.ReadEntry(updated_fname, entry_name)
2962 self.assertEqual(expected, data)
2963
2964 # Check the state looks right.
2965 self.assertEqual('/binman/image', state.fdt_path_prefix)
2966
2967 # Now check we can write the first image
2968 image_fname = tools.GetOutputFilename('first-image.bin')
2969 updated_fname = tools.GetOutputFilename('first-updated.bin')
2970 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
2971 entry_name = 'u-boot'
Simon Glass51014aa2019-07-20 12:23:56 -06002972 control.WriteEntry(updated_fname, entry_name, expected,
2973 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06002974 data = control.ReadEntry(updated_fname, entry_name)
2975 self.assertEqual(expected, data)
2976
2977 # Check the state looks right.
2978 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass8beb11e2019-07-08 14:25:47 -06002979
Simon Glass12bb1a92019-07-20 12:23:51 -06002980 def testUpdateFdtAllRepack(self):
2981 """Test that all device trees are updated with offset/size info"""
2982 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
2983 SECTION_SIZE = 0x300
2984 DTB_SIZE = 602
2985 FDTMAP_SIZE = 608
2986 base_expected = {
2987 'offset': 0,
2988 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
2989 'image-pos': 0,
2990 'section:offset': 0,
2991 'section:size': SECTION_SIZE,
2992 'section:image-pos': 0,
2993 'section/u-boot-dtb:offset': 4,
2994 'section/u-boot-dtb:size': 636,
2995 'section/u-boot-dtb:image-pos': 4,
2996 'u-boot-spl-dtb:offset': SECTION_SIZE,
2997 'u-boot-spl-dtb:size': DTB_SIZE,
2998 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
2999 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3000 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3001 'u-boot-tpl-dtb:size': DTB_SIZE,
3002 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3003 'fdtmap:size': FDTMAP_SIZE,
3004 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3005 }
3006 main_expected = {
3007 'section:orig-size': SECTION_SIZE,
3008 'section/u-boot-dtb:orig-offset': 4,
3009 }
3010
3011 # We expect three device-tree files in the output, with the first one
3012 # within a fixed-size section.
3013 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3014 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3015 # main U-Boot tree. All three should have the same positions and offset
3016 # except that the main tree should include the main_expected properties
3017 start = 4
3018 for item in ['', 'spl', 'tpl', None]:
3019 if item is None:
3020 start += 16 # Move past fdtmap header
3021 dtb = fdt.Fdt.FromData(data[start:])
3022 dtb.Scan()
3023 props = self._GetPropTree(dtb,
3024 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3025 prefix='/' if item is None else '/binman/')
3026 expected = dict(base_expected)
3027 if item:
3028 expected[item] = 0
3029 else:
3030 # Main DTB and fdtdec should include the 'orig-' properties
3031 expected.update(main_expected)
3032 # Helpful for debugging:
3033 #for prop in sorted(props):
3034 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3035 self.assertEqual(expected, props)
3036 if item == '':
3037 start = SECTION_SIZE
3038 else:
3039 start += dtb._fdt_obj.totalsize()
3040
Simon Glasseba1f0c2019-07-20 12:23:55 -06003041 def testFdtmapHeaderMiddle(self):
3042 """Test an FDT map in the middle of an image when it should be at end"""
3043 with self.assertRaises(ValueError) as e:
3044 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3045 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3046 str(e.exception))
3047
3048 def testFdtmapHeaderStartBad(self):
3049 """Test an FDT map in middle of an image when it should be at start"""
3050 with self.assertRaises(ValueError) as e:
3051 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3052 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3053 str(e.exception))
3054
3055 def testFdtmapHeaderEndBad(self):
3056 """Test an FDT map at the start of an image when it should be at end"""
3057 with self.assertRaises(ValueError) as e:
3058 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3059 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3060 str(e.exception))
3061
3062 def testFdtmapHeaderNoSize(self):
3063 """Test an image header at the end of an image with undefined size"""
3064 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3065
Simon Glass51014aa2019-07-20 12:23:56 -06003066 def testReplaceResize(self):
3067 """Test replacing a single file in an entry with a larger file"""
3068 expected = U_BOOT_DATA + b'x'
3069 data, _, image = self._RunReplaceCmd('u-boot', expected,
3070 dts='139_replace_repack.dts')
3071 self.assertEqual(expected, data)
3072
3073 entries = image.GetEntries()
3074 dtb_data = entries['u-boot-dtb'].data
3075 dtb = fdt.Fdt.FromData(dtb_data)
3076 dtb.Scan()
3077
3078 # The u-boot section should now be larger in the dtb
3079 node = dtb.GetNode('/binman/u-boot')
3080 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3081
3082 # Same for the fdtmap
3083 fdata = entries['fdtmap'].data
3084 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3085 fdtb.Scan()
3086 fnode = fdtb.GetNode('/u-boot')
3087 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3088
3089 def testReplaceResizeNoRepack(self):
3090 """Test replacing an entry with a larger file when not allowed"""
3091 expected = U_BOOT_DATA + b'x'
3092 with self.assertRaises(ValueError) as e:
3093 self._RunReplaceCmd('u-boot', expected)
3094 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3095 str(e.exception))
3096
Simon Glass61ec04f2019-07-20 12:23:58 -06003097 def testEntryShrink(self):
3098 """Test contracting an entry after it is packed"""
3099 try:
3100 state.SetAllowEntryContraction(True)
3101 data = self._DoReadFileDtb('140_entry_shrink.dts',
3102 update_dtb=True)[0]
3103 finally:
3104 state.SetAllowEntryContraction(False)
3105 self.assertEqual(b'a', data[:1])
3106 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3107 self.assertEqual(b'a', data[-1:])
3108
3109 def testEntryShrinkFail(self):
3110 """Test not being allowed to contract an entry after it is packed"""
3111 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3112
3113 # In this case there is a spare byte at the end of the data. The size of
3114 # the contents is only 1 byte but we still have the size before it
3115 # shrunk.
3116 self.assertEqual(b'a\0', data[:2])
3117 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3118 self.assertEqual(b'a\0', data[-2:])
3119
Simon Glass27145fd2019-07-20 12:24:01 -06003120 def testDescriptorOffset(self):
3121 """Test that the Intel descriptor is always placed at at the start"""
3122 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3123 image = control.images['image']
3124 entries = image.GetEntries()
3125 desc = entries['intel-descriptor']
3126 self.assertEqual(0xff800000, desc.offset);
3127 self.assertEqual(0xff800000, desc.image_pos);
3128
Simon Glasseb0f4a42019-07-20 12:24:06 -06003129 def testReplaceCbfs(self):
3130 """Test replacing a single file in CBFS without changing the size"""
3131 self._CheckLz4()
3132 expected = b'x' * len(U_BOOT_DATA)
3133 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3134 updated_fname = tools.GetOutputFilename('image-updated.bin')
3135 tools.WriteFile(updated_fname, data)
3136 entry_name = 'section/cbfs/u-boot'
3137 control.WriteEntry(updated_fname, entry_name, expected,
3138 allow_resize=True)
3139 data = control.ReadEntry(updated_fname, entry_name)
3140 self.assertEqual(expected, data)
3141
3142 def testReplaceResizeCbfs(self):
3143 """Test replacing a single file in CBFS with one of a different size"""
3144 self._CheckLz4()
3145 expected = U_BOOT_DATA + b'x'
3146 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3147 updated_fname = tools.GetOutputFilename('image-updated.bin')
3148 tools.WriteFile(updated_fname, data)
3149 entry_name = 'section/cbfs/u-boot'
3150 control.WriteEntry(updated_fname, entry_name, expected,
3151 allow_resize=True)
3152 data = control.ReadEntry(updated_fname, entry_name)
3153 self.assertEqual(expected, data)
3154
Simon Glassa6cb9952019-07-20 12:24:15 -06003155 def _SetupForReplace(self):
3156 """Set up some files to use to replace entries
3157
3158 This generates an image, copies it to a new file, extracts all the files
3159 in it and updates some of them
3160
3161 Returns:
3162 List
3163 Image filename
3164 Output directory
3165 Expected values for updated entries, each a string
3166 """
3167 data = self._DoReadFileRealDtb('143_replace_all.dts')
3168
3169 updated_fname = tools.GetOutputFilename('image-updated.bin')
3170 tools.WriteFile(updated_fname, data)
3171
3172 outdir = os.path.join(self._indir, 'extract')
3173 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3174
3175 expected1 = b'x' + U_BOOT_DATA + b'y'
3176 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3177 tools.WriteFile(u_boot_fname1, expected1)
3178
3179 expected2 = b'a' + U_BOOT_DATA + b'b'
3180 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
3181 tools.WriteFile(u_boot_fname2, expected2)
3182
3183 expected_text = b'not the same text'
3184 text_fname = os.path.join(outdir, 'text')
3185 tools.WriteFile(text_fname, expected_text)
3186
3187 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3188 dtb = fdt.FdtScan(dtb_fname)
3189 node = dtb.GetNode('/binman/text')
3190 node.AddString('my-property', 'the value')
3191 dtb.Sync(auto_resize=True)
3192 dtb.Flush()
3193
3194 return updated_fname, outdir, expected1, expected2, expected_text
3195
3196 def _CheckReplaceMultiple(self, entry_paths):
3197 """Handle replacing the contents of multiple entries
3198
3199 Args:
3200 entry_paths: List of entry paths to replace
3201
3202 Returns:
3203 List
3204 Dict of entries in the image:
3205 key: Entry name
3206 Value: Entry object
3207 Expected values for updated entries, each a string
3208 """
3209 updated_fname, outdir, expected1, expected2, expected_text = (
3210 self._SetupForReplace())
3211 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3212
3213 image = Image.FromFile(updated_fname)
3214 image.LoadData()
3215 return image.GetEntries(), expected1, expected2, expected_text
3216
3217 def testReplaceAll(self):
3218 """Test replacing the contents of all entries"""
3219 entries, expected1, expected2, expected_text = (
3220 self._CheckReplaceMultiple([]))
3221 data = entries['u-boot'].data
3222 self.assertEqual(expected1, data)
3223
3224 data = entries['u-boot2'].data
3225 self.assertEqual(expected2, data)
3226
3227 data = entries['text'].data
3228 self.assertEqual(expected_text, data)
3229
3230 # Check that the device tree is updated
3231 data = entries['u-boot-dtb'].data
3232 dtb = fdt.Fdt.FromData(data)
3233 dtb.Scan()
3234 node = dtb.GetNode('/binman/text')
3235 self.assertEqual('the value', node.props['my-property'].value)
3236
3237 def testReplaceSome(self):
3238 """Test replacing the contents of a few entries"""
3239 entries, expected1, expected2, expected_text = (
3240 self._CheckReplaceMultiple(['u-boot2', 'text']))
3241
3242 # This one should not change
3243 data = entries['u-boot'].data
3244 self.assertEqual(U_BOOT_DATA, data)
3245
3246 data = entries['u-boot2'].data
3247 self.assertEqual(expected2, data)
3248
3249 data = entries['text'].data
3250 self.assertEqual(expected_text, data)
3251
3252 def testReplaceCmd(self):
3253 """Test replacing a file fron an image on the command line"""
3254 self._DoReadFileRealDtb('143_replace_all.dts')
3255
3256 try:
3257 tmpdir, updated_fname = self._SetupImageInTmpdir()
3258
3259 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3260 expected = b'x' * len(U_BOOT_DATA)
3261 tools.WriteFile(fname, expected)
3262
3263 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
3264 data = tools.ReadFile(updated_fname)
3265 self.assertEqual(expected, data[:len(expected)])
3266 map_fname = os.path.join(tmpdir, 'image-updated.map')
3267 self.assertFalse(os.path.exists(map_fname))
3268 finally:
3269 shutil.rmtree(tmpdir)
3270
3271 def testReplaceCmdSome(self):
3272 """Test replacing some files fron an image on the command line"""
3273 updated_fname, outdir, expected1, expected2, expected_text = (
3274 self._SetupForReplace())
3275
3276 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3277 'u-boot2', 'text')
3278
3279 tools.PrepareOutputDir(None)
3280 image = Image.FromFile(updated_fname)
3281 image.LoadData()
3282 entries = image.GetEntries()
3283
3284 # This one should not change
3285 data = entries['u-boot'].data
3286 self.assertEqual(U_BOOT_DATA, data)
3287
3288 data = entries['u-boot2'].data
3289 self.assertEqual(expected2, data)
3290
3291 data = entries['text'].data
3292 self.assertEqual(expected_text, data)
3293
3294 def testReplaceMissing(self):
3295 """Test replacing entries where the file is missing"""
3296 updated_fname, outdir, expected1, expected2, expected_text = (
3297 self._SetupForReplace())
3298
3299 # Remove one of the files, to generate a warning
3300 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3301 os.remove(u_boot_fname1)
3302
3303 with test_util.capture_sys_output() as (stdout, stderr):
3304 control.ReplaceEntries(updated_fname, None, outdir, [])
3305 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass38fdb4c2020-07-09 18:39:39 -06003306 stderr.getvalue())
Simon Glassa6cb9952019-07-20 12:24:15 -06003307
3308 def testReplaceCmdMap(self):
3309 """Test replacing a file fron an image on the command line"""
3310 self._DoReadFileRealDtb('143_replace_all.dts')
3311
3312 try:
3313 tmpdir, updated_fname = self._SetupImageInTmpdir()
3314
3315 fname = os.path.join(self._indir, 'update-u-boot.bin')
3316 expected = b'x' * len(U_BOOT_DATA)
3317 tools.WriteFile(fname, expected)
3318
3319 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3320 '-f', fname, '-m')
3321 map_fname = os.path.join(tmpdir, 'image-updated.map')
3322 self.assertTrue(os.path.exists(map_fname))
3323 finally:
3324 shutil.rmtree(tmpdir)
3325
3326 def testReplaceNoEntryPaths(self):
3327 """Test replacing an entry without an entry path"""
3328 self._DoReadFileRealDtb('143_replace_all.dts')
3329 image_fname = tools.GetOutputFilename('image.bin')
3330 with self.assertRaises(ValueError) as e:
3331 control.ReplaceEntries(image_fname, 'fname', None, [])
3332 self.assertIn('Must specify an entry path to read with -f',
3333 str(e.exception))
3334
3335 def testReplaceTooManyEntryPaths(self):
3336 """Test extracting some entries"""
3337 self._DoReadFileRealDtb('143_replace_all.dts')
3338 image_fname = tools.GetOutputFilename('image.bin')
3339 with self.assertRaises(ValueError) as e:
3340 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3341 self.assertIn('Must specify exactly one entry path to write with -f',
3342 str(e.exception))
3343
Simon Glass2250ee62019-08-24 07:22:48 -06003344 def testPackReset16(self):
3345 """Test that an image with an x86 reset16 region can be created"""
3346 data = self._DoReadFile('144_x86_reset16.dts')
3347 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3348
3349 def testPackReset16Spl(self):
3350 """Test that an image with an x86 reset16-spl region can be created"""
3351 data = self._DoReadFile('145_x86_reset16_spl.dts')
3352 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3353
3354 def testPackReset16Tpl(self):
3355 """Test that an image with an x86 reset16-tpl region can be created"""
3356 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3357 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3358
Simon Glass5af12072019-08-24 07:22:50 -06003359 def testPackIntelFit(self):
3360 """Test that an image with an Intel FIT and pointer can be created"""
3361 data = self._DoReadFile('147_intel_fit.dts')
3362 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3363 fit = data[16:32];
3364 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3365 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3366
3367 image = control.images['image']
3368 entries = image.GetEntries()
3369 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3370 self.assertEqual(expected_ptr, ptr)
3371
3372 def testPackIntelFitMissing(self):
3373 """Test detection of a FIT pointer with not FIT region"""
3374 with self.assertRaises(ValueError) as e:
3375 self._DoReadFile('148_intel_fit_missing.dts')
3376 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3377 str(e.exception))
3378
Simon Glass7c150132019-11-06 17:22:44 -07003379 def _CheckSymbolsTplSection(self, dts, expected_vals):
3380 data = self._DoReadFile(dts)
3381 sym_values = struct.pack('<LQLL', *expected_vals)
Simon Glass2090f1e2019-08-24 07:23:00 -06003382 upto1 = 4 + len(U_BOOT_SPL_DATA)
Simon Glassb87064c2019-08-24 07:23:05 -06003383 expected1 = tools.GetBytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[20:]
Simon Glass2090f1e2019-08-24 07:23:00 -06003384 self.assertEqual(expected1, data[:upto1])
3385
3386 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Simon Glassb87064c2019-08-24 07:23:05 -06003387 expected2 = tools.GetBytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[20:]
Simon Glass2090f1e2019-08-24 07:23:00 -06003388 self.assertEqual(expected2, data[upto1:upto2])
3389
Simon Glasseb0086f2019-08-24 07:23:04 -06003390 upto3 = 0x34 + len(U_BOOT_DATA)
3391 expected3 = tools.GetBytes(0xff, 1) + U_BOOT_DATA
Simon Glass2090f1e2019-08-24 07:23:00 -06003392 self.assertEqual(expected3, data[upto2:upto3])
3393
Simon Glassb87064c2019-08-24 07:23:05 -06003394 expected4 = sym_values + U_BOOT_TPL_DATA[20:]
Simon Glass7c150132019-11-06 17:22:44 -07003395 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3396
3397 def testSymbolsTplSection(self):
3398 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3399 self._SetupSplElf('u_boot_binman_syms')
3400 self._SetupTplElf('u_boot_binman_syms')
3401 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
3402 [0x04, 0x1c, 0x10 + 0x34, 0x04])
3403
3404 def testSymbolsTplSectionX86(self):
3405 """Test binman can assign symbols in a section with end-at-4gb"""
3406 self._SetupSplElf('u_boot_binman_syms_x86')
3407 self._SetupTplElf('u_boot_binman_syms_x86')
3408 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
3409 [0xffffff04, 0xffffff1c, 0xffffff34,
3410 0x04])
Simon Glass2090f1e2019-08-24 07:23:00 -06003411
Simon Glassbf4d0e22019-08-24 07:23:03 -06003412 def testPackX86RomIfwiSectiom(self):
3413 """Test that a section can be placed in an IFWI region"""
3414 self._SetupIfwi('fitimage.bin')
3415 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3416 self._CheckIfwi(data)
3417
Simon Glassea0fff92019-08-24 07:23:07 -06003418 def testPackFspM(self):
3419 """Test that an image with a FSP memory-init binary can be created"""
3420 data = self._DoReadFile('152_intel_fsp_m.dts')
3421 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3422
Simon Glassbc6a88f2019-10-20 21:31:35 -06003423 def testPackFspS(self):
3424 """Test that an image with a FSP silicon-init binary can be created"""
3425 data = self._DoReadFile('153_intel_fsp_s.dts')
3426 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassea0fff92019-08-24 07:23:07 -06003427
Simon Glass998d1482019-10-20 21:31:36 -06003428 def testPackFspT(self):
3429 """Test that an image with a FSP temp-ram-init binary can be created"""
3430 data = self._DoReadFile('154_intel_fsp_t.dts')
3431 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3432
Simon Glass0dc706f2020-07-09 18:39:31 -06003433 def testMkimage(self):
3434 """Test using mkimage to build an image"""
3435 data = self._DoReadFile('156_mkimage.dts')
3436
3437 # Just check that the data appears in the file somewhere
3438 self.assertIn(U_BOOT_SPL_DATA, data)
3439
Simon Glassce867ad2020-07-09 18:39:36 -06003440 def testExtblob(self):
3441 """Test an image with an external blob"""
3442 data = self._DoReadFile('157_blob_ext.dts')
3443 self.assertEqual(REFCODE_DATA, data)
3444
3445 def testExtblobMissing(self):
3446 """Test an image with a missing external blob"""
3447 with self.assertRaises(ValueError) as e:
3448 self._DoReadFile('158_blob_ext_missing.dts')
3449 self.assertIn("Filename 'missing-file' not found in input path",
3450 str(e.exception))
3451
Simon Glass4f9f1052020-07-09 18:39:38 -06003452 def testExtblobMissingOk(self):
3453 """Test an image with an missing external blob that is allowed"""
Simon Glassb1cca952020-07-09 18:39:40 -06003454 with test_util.capture_sys_output() as (stdout, stderr):
3455 self._DoTestFile('158_blob_ext_missing.dts', allow_missing=True)
3456 err = stderr.getvalue()
3457 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
3458
3459 def testExtblobMissingOkSect(self):
3460 """Test an image with an missing external blob that is allowed"""
3461 with test_util.capture_sys_output() as (stdout, stderr):
3462 self._DoTestFile('159_blob_ext_missing_sect.dts',
3463 allow_missing=True)
3464 err = stderr.getvalue()
3465 self.assertRegex(err, "Image 'main-section'.*missing.*: "
3466 "blob-ext blob-ext2")
Simon Glass4f9f1052020-07-09 18:39:38 -06003467
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003468 def testPackX86RomMeMissingDesc(self):
3469 """Test that an missing Intel descriptor entry is allowed"""
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003470 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass52b10dd2020-07-25 15:11:19 -06003471 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003472 err = stderr.getvalue()
3473 self.assertRegex(err,
3474 "Image 'main-section'.*missing.*: intel-descriptor")
3475
3476 def testPackX86RomMissingIfwi(self):
3477 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3478 self._SetupIfwi('fitimage.bin')
3479 pathname = os.path.join(self._indir, 'fitimage.bin')
3480 os.remove(pathname)
3481 with test_util.capture_sys_output() as (stdout, stderr):
3482 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3483 err = stderr.getvalue()
3484 self.assertRegex(err, "Image 'main-section'.*missing.*: intel-ifwi")
3485
Simon Glassb3295fd2020-07-09 18:39:42 -06003486 def testPackOverlap(self):
3487 """Test that zero-size overlapping regions are ignored"""
3488 self._DoTestFile('160_pack_overlap_zero.dts')
3489
Simon Glassfdc34362020-07-09 18:39:45 -06003490 def testSimpleFit(self):
3491 """Test an image with a FIT inside"""
3492 data = self._DoReadFile('161_fit.dts')
3493 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3494 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3495 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3496
3497 # The data should be inside the FIT
3498 dtb = fdt.Fdt.FromData(fit_data)
3499 dtb.Scan()
3500 fnode = dtb.GetNode('/images/kernel')
3501 self.assertIn('data', fnode.props)
3502
3503 fname = os.path.join(self._indir, 'fit_data.fit')
3504 tools.WriteFile(fname, fit_data)
3505 out = tools.Run('dumpimage', '-l', fname)
3506
3507 # Check a few features to make sure the plumbing works. We don't need
3508 # to test the operation of mkimage or dumpimage here. First convert the
3509 # output into a dict where the keys are the fields printed by dumpimage
3510 # and the values are a list of values for each field
3511 lines = out.splitlines()
3512
3513 # Converts "Compression: gzip compressed" into two groups:
3514 # 'Compression' and 'gzip compressed'
3515 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3516 vals = collections.defaultdict(list)
3517 for line in lines:
3518 mat = re_line.match(line)
3519 vals[mat.group(1)].append(mat.group(2))
3520
3521 self.assertEquals('FIT description: test-desc', lines[0])
3522 self.assertIn('Created:', lines[1])
3523 self.assertIn('Image 0 (kernel)', vals)
3524 self.assertIn('Hash value', vals)
3525 data_sizes = vals.get('Data Size')
3526 self.assertIsNotNone(data_sizes)
3527 self.assertEqual(2, len(data_sizes))
3528 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
3529 self.assertEqual(len(U_BOOT_DATA), int(data_sizes[0].split()[0]))
3530 self.assertEqual(len(U_BOOT_SPL_DTB_DATA), int(data_sizes[1].split()[0]))
3531
3532 def testFitExternal(self):
Simon Glasse9d336d2020-09-01 05:13:55 -06003533 """Test an image with an FIT with external images"""
Simon Glassfdc34362020-07-09 18:39:45 -06003534 data = self._DoReadFile('162_fit_external.dts')
3535 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3536
3537 # The data should be outside the FIT
3538 dtb = fdt.Fdt.FromData(fit_data)
3539 dtb.Scan()
3540 fnode = dtb.GetNode('/images/kernel')
3541 self.assertNotIn('data', fnode.props)
Simon Glass12bb1a92019-07-20 12:23:51 -06003542
Alper Nebi Yasak8001d0b2020-08-31 12:58:18 +03003543 def testSectionIgnoreHashSignature(self):
3544 """Test that sections ignore hash, signature nodes for its data"""
3545 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
3546 expected = (U_BOOT_DATA + U_BOOT_DATA)
3547 self.assertEqual(expected, data)
3548
Alper Nebi Yasak3fdeb142020-08-31 12:58:19 +03003549 def testPadInSections(self):
3550 """Test pad-before, pad-after for entries in sections"""
3551 data = self._DoReadFile('166_pad_in_sections.dts')
3552 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
3553 U_BOOT_DATA + tools.GetBytes(ord('!'), 6) +
3554 U_BOOT_DATA)
3555 self.assertEqual(expected, data)
3556
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03003557 def testFitImageSubentryAlignment(self):
3558 """Test relative alignability of FIT image subentries"""
3559 entry_args = {
3560 'test-id': TEXT_DATA,
3561 }
3562 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
3563 entry_args=entry_args)
3564 dtb = fdt.Fdt.FromData(data)
3565 dtb.Scan()
3566
3567 node = dtb.GetNode('/images/kernel')
3568 data = dtb.GetProps(node)["data"].bytes
3569 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
3570 expected = (tools.GetBytes(0, 0x20) + U_BOOT_SPL_DATA +
3571 tools.GetBytes(0, align_pad) + U_BOOT_DATA)
3572 self.assertEqual(expected, data)
3573
3574 node = dtb.GetNode('/images/fdt-1')
3575 data = dtb.GetProps(node)["data"].bytes
3576 expected = (U_BOOT_SPL_DTB_DATA + tools.GetBytes(0, 20) +
3577 tools.ToBytes(TEXT_DATA) + tools.GetBytes(0, 30) +
3578 U_BOOT_DTB_DATA)
3579 self.assertEqual(expected, data)
3580
3581 def testFitExtblobMissingOk(self):
3582 """Test a FIT with a missing external blob that is allowed"""
3583 with test_util.capture_sys_output() as (stdout, stderr):
3584 self._DoTestFile('168_fit_missing_blob.dts',
3585 allow_missing=True)
3586 err = stderr.getvalue()
Simon Glassb2381432020-09-06 10:39:09 -06003587 self.assertRegex(err, "Image 'main-section'.*missing.*: atf-bl31")
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03003588
Simon Glass3decfa32020-09-01 05:13:54 -06003589 def testBlobNamedByArgMissing(self):
3590 """Test handling of a missing entry arg"""
3591 with self.assertRaises(ValueError) as e:
3592 self._DoReadFile('068_blob_named_by_arg.dts')
3593 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
3594 str(e.exception))
3595
Simon Glassdc2f81a2020-09-01 05:13:58 -06003596 def testPackBl31(self):
3597 """Test that an image with an ATF BL31 binary can be created"""
3598 data = self._DoReadFile('169_atf_bl31.dts')
3599 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
3600
Samuel Holland18bd4552020-10-21 21:12:15 -05003601 def testPackScp(self):
3602 """Test that an image with an SCP binary can be created"""
3603 data = self._DoReadFile('172_scp.dts')
3604 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
3605
Simon Glass6cf99532020-09-01 05:13:59 -06003606 def testFitFdt(self):
3607 """Test an image with an FIT with multiple FDT images"""
3608 def _CheckFdt(seq, expected_data):
3609 """Check the FDT nodes
3610
3611 Args:
3612 seq: Sequence number to check (0 or 1)
3613 expected_data: Expected contents of 'data' property
3614 """
3615 name = 'fdt-%d' % seq
3616 fnode = dtb.GetNode('/images/%s' % name)
3617 self.assertIsNotNone(fnode)
3618 self.assertEqual({'description','type', 'compression', 'data'},
3619 set(fnode.props.keys()))
3620 self.assertEqual(expected_data, fnode.props['data'].bytes)
3621 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
3622 fnode.props['description'].value)
3623
3624 def _CheckConfig(seq, expected_data):
3625 """Check the configuration nodes
3626
3627 Args:
3628 seq: Sequence number to check (0 or 1)
3629 expected_data: Expected contents of 'data' property
3630 """
3631 cnode = dtb.GetNode('/configurations')
3632 self.assertIn('default', cnode.props)
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003633 self.assertEqual('config-2', cnode.props['default'].value)
Simon Glass6cf99532020-09-01 05:13:59 -06003634
3635 name = 'config-%d' % seq
3636 fnode = dtb.GetNode('/configurations/%s' % name)
3637 self.assertIsNotNone(fnode)
3638 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
3639 set(fnode.props.keys()))
3640 self.assertEqual('conf-test-fdt%d.dtb' % seq,
3641 fnode.props['description'].value)
3642 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
3643
3644 entry_args = {
3645 'of-list': 'test-fdt1 test-fdt2',
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003646 'default-dt': 'test-fdt2',
Simon Glass6cf99532020-09-01 05:13:59 -06003647 }
3648 data = self._DoReadFileDtb(
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003649 '172_fit_fdt.dts',
Simon Glass6cf99532020-09-01 05:13:59 -06003650 entry_args=entry_args,
3651 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3652 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3653 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3654
3655 dtb = fdt.Fdt.FromData(fit_data)
3656 dtb.Scan()
3657 fnode = dtb.GetNode('/images/kernel')
3658 self.assertIn('data', fnode.props)
3659
3660 # Check all the properties in fdt-1 and fdt-2
3661 _CheckFdt(1, TEST_FDT1_DATA)
3662 _CheckFdt(2, TEST_FDT2_DATA)
3663
3664 # Check configurations
3665 _CheckConfig(1, TEST_FDT1_DATA)
3666 _CheckConfig(2, TEST_FDT2_DATA)
3667
3668 def testFitFdtMissingList(self):
3669 """Test handling of a missing 'of-list' entry arg"""
3670 with self.assertRaises(ValueError) as e:
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003671 self._DoReadFile('172_fit_fdt.dts')
Simon Glass6cf99532020-09-01 05:13:59 -06003672 self.assertIn("Generator node requires 'of-list' entry argument",
3673 str(e.exception))
3674
3675 def testFitFdtEmptyList(self):
3676 """Test handling of an empty 'of-list' entry arg"""
3677 entry_args = {
3678 'of-list': '',
3679 }
3680 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
3681
3682 def testFitFdtMissingProp(self):
3683 """Test handling of a missing 'fit,fdt-list' property"""
3684 with self.assertRaises(ValueError) as e:
3685 self._DoReadFile('171_fit_fdt_missing_prop.dts')
3686 self.assertIn("Generator node requires 'fit,fdt-list' property",
3687 str(e.exception))
Simon Glassdc2f81a2020-09-01 05:13:58 -06003688
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003689 def testFitFdtEmptyList(self):
3690 """Test handling of an empty 'of-list' entry arg"""
3691 entry_args = {
3692 'of-list': '',
3693 }
3694 data = self._DoReadFileDtb('172_fit_fdt.dts', entry_args=entry_args)[0]
3695
3696 def testFitFdtMissing(self):
3697 """Test handling of a missing 'default-dt' entry arg"""
3698 entry_args = {
3699 'of-list': 'test-fdt1 test-fdt2',
3700 }
3701 with self.assertRaises(ValueError) as e:
3702 self._DoReadFileDtb(
3703 '172_fit_fdt.dts',
3704 entry_args=entry_args,
3705 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3706 self.assertIn("Generated 'default' node requires default-dt entry argument",
3707 str(e.exception))
3708
3709 def testFitFdtNotInList(self):
3710 """Test handling of a default-dt that is not in the of-list"""
3711 entry_args = {
3712 'of-list': 'test-fdt1 test-fdt2',
3713 'default-dt': 'test-fdt3',
3714 }
3715 with self.assertRaises(ValueError) as e:
3716 self._DoReadFileDtb(
3717 '172_fit_fdt.dts',
3718 entry_args=entry_args,
3719 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3720 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
3721 str(e.exception))
3722
Simon Glassb2381432020-09-06 10:39:09 -06003723 def testFitExtblobMissingHelp(self):
3724 """Test display of help messages when an external blob is missing"""
3725 control.missing_blob_help = control._ReadMissingBlobHelp()
3726 control.missing_blob_help['wibble'] = 'Wibble test'
3727 control.missing_blob_help['another'] = 'Another test'
3728 with test_util.capture_sys_output() as (stdout, stderr):
3729 self._DoTestFile('168_fit_missing_blob.dts',
3730 allow_missing=True)
3731 err = stderr.getvalue()
3732
3733 # We can get the tag from the name, the type or the missing-msg
3734 # property. Check all three.
3735 self.assertIn('You may need to build ARM Trusted', err)
3736 self.assertIn('Wibble test', err)
3737 self.assertIn('Another test', err)
3738
Simon Glass204aa782020-09-06 10:35:32 -06003739 def testMissingBlob(self):
3740 """Test handling of a blob containing a missing file"""
3741 with self.assertRaises(ValueError) as e:
3742 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
3743 self.assertIn("Filename 'missing' not found in input path",
3744 str(e.exception))
3745
Simon Glassfb91d562020-09-06 10:35:33 -06003746 def testEnvironment(self):
3747 """Test adding a U-Boot environment"""
3748 data = self._DoReadFile('174_env.dts')
3749 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3750 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3751 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3752 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
3753 env)
3754
3755 def testEnvironmentNoSize(self):
3756 """Test that a missing 'size' property is detected"""
3757 with self.assertRaises(ValueError) as e:
Simon Glassa4dfe3e2020-10-26 17:40:00 -06003758 self._DoTestFile('175_env_no_size.dts')
Simon Glassfb91d562020-09-06 10:35:33 -06003759 self.assertIn("'u-boot-env' entry must have a size property",
3760 str(e.exception))
3761
3762 def testEnvironmentTooSmall(self):
3763 """Test handling of an environment that does not fit"""
3764 with self.assertRaises(ValueError) as e:
Simon Glassa4dfe3e2020-10-26 17:40:00 -06003765 self._DoTestFile('176_env_too_small.dts')
Simon Glassfb91d562020-09-06 10:35:33 -06003766
3767 # checksum, start byte, environment with \0 terminator, final \0
3768 need = 4 + 1 + len(ENV_DATA) + 1 + 1
3769 short = need - 0x8
3770 self.assertIn("too small to hold data (need %#x more bytes)" % short,
3771 str(e.exception))
3772
Simon Glassf2c0dd82020-10-26 17:40:01 -06003773 def testSkipAtStart(self):
3774 """Test handling of skip-at-start section"""
3775 data = self._DoReadFile('177_skip_at_start.dts')
3776 self.assertEqual(U_BOOT_DATA, data)
3777
3778 image = control.images['image']
3779 entries = image.GetEntries()
3780 section = entries['section']
3781 self.assertEqual(0, section.offset)
3782 self.assertEqual(len(U_BOOT_DATA), section.size)
3783 self.assertEqual(U_BOOT_DATA, section.GetData())
3784
3785 entry = section.GetEntries()['u-boot']
3786 self.assertEqual(16, entry.offset)
3787 self.assertEqual(len(U_BOOT_DATA), entry.size)
3788 self.assertEqual(U_BOOT_DATA, entry.data)
3789
3790 def testSkipAtStartPad(self):
3791 """Test handling of skip-at-start section with padded entry"""
3792 data = self._DoReadFile('178_skip_at_start_pad.dts')
3793 before = tools.GetBytes(0, 8)
3794 after = tools.GetBytes(0, 4)
3795 all = before + U_BOOT_DATA + after
3796 self.assertEqual(all, data)
3797
3798 image = control.images['image']
3799 entries = image.GetEntries()
3800 section = entries['section']
3801 self.assertEqual(0, section.offset)
3802 self.assertEqual(len(all), section.size)
3803 self.assertEqual(all, section.GetData())
3804
3805 entry = section.GetEntries()['u-boot']
3806 self.assertEqual(16, entry.offset)
3807 self.assertEqual(len(all), entry.size)
3808 self.assertEqual(U_BOOT_DATA, entry.data)
3809
3810 def testSkipAtStartSectionPad(self):
3811 """Test handling of skip-at-start section with padding"""
3812 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
3813 before = tools.GetBytes(0, 8)
3814 after = tools.GetBytes(0, 4)
3815 all = before + U_BOOT_DATA + after
3816
3817 # This is not correct, but it is what binman currently produces
3818 self.assertEqual(tools.GetBytes(0, 16) + U_BOOT_DATA + after, data)
3819
3820 image = control.images['image']
3821 entries = image.GetEntries()
3822 section = entries['section']
3823 self.assertEqual(0, section.offset)
3824 self.assertEqual(len(all), section.size)
3825 self.assertIsNone(section.data)
3826 self.assertEqual(all, section.GetData())
3827
3828 entry = section.GetEntries()['u-boot']
3829 self.assertEqual(16, entry.offset)
3830 self.assertEqual(len(U_BOOT_DATA), entry.size)
3831 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassfb91d562020-09-06 10:35:33 -06003832
Simon Glass9fc60b42017-11-12 21:52:22 -07003833if __name__ == "__main__":
3834 unittest.main()