blob: 82be9976c329aa40cdddc31ca6bcdb01677723af [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 Glass17ea9f32020-10-26 17:40:11 -0600711 @unittest.skip('Disable for now until padding of images is supported')
Simon Glass4f443042016-11-25 20:15:52 -0700712 def testDual(self):
713 """Test that we can handle creating two images
714
715 This also tests image padding.
716 """
Simon Glass741f2d62018-10-01 12:22:30 -0600717 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700718 self.assertEqual(0, retcode)
719
720 image = control.images['image1']
Simon Glass8beb11e2019-07-08 14:25:47 -0600721 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700722 fname = tools.GetOutputFilename('image1.bin')
723 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600724 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700725 data = fd.read()
726 self.assertEqual(U_BOOT_DATA, data)
727
728 image = control.images['image2']
Simon Glass8beb11e2019-07-08 14:25:47 -0600729 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700730 fname = tools.GetOutputFilename('image2.bin')
731 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600732 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700733 data = fd.read()
734 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glasse6d85ff2019-05-14 15:53:47 -0600735 self.assertEqual(tools.GetBytes(0, 3), data[:3])
736 self.assertEqual(tools.GetBytes(0, 5), data[7:])
Simon Glass4f443042016-11-25 20:15:52 -0700737
738 def testBadAlign(self):
739 """Test that an invalid alignment value is detected"""
740 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600741 self._DoTestFile('007_bad_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700742 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
743 "of two", str(e.exception))
744
745 def testPackSimple(self):
746 """Test that packing works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600747 retcode = self._DoTestFile('008_pack.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700748 self.assertEqual(0, retcode)
749 self.assertIn('image', control.images)
750 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600751 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700752 self.assertEqual(5, len(entries))
753
754 # First u-boot
755 self.assertIn('u-boot', entries)
756 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600757 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700758 self.assertEqual(len(U_BOOT_DATA), entry.size)
759
760 # Second u-boot, aligned to 16-byte boundary
761 self.assertIn('u-boot-align', entries)
762 entry = entries['u-boot-align']
Simon Glass3ab95982018-08-01 15:22:37 -0600763 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700764 self.assertEqual(len(U_BOOT_DATA), entry.size)
765
766 # Third u-boot, size 23 bytes
767 self.assertIn('u-boot-size', entries)
768 entry = entries['u-boot-size']
Simon Glass3ab95982018-08-01 15:22:37 -0600769 self.assertEqual(20, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700770 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
771 self.assertEqual(23, entry.size)
772
773 # Fourth u-boot, placed immediate after the above
774 self.assertIn('u-boot-next', entries)
775 entry = entries['u-boot-next']
Simon Glass3ab95982018-08-01 15:22:37 -0600776 self.assertEqual(43, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700777 self.assertEqual(len(U_BOOT_DATA), entry.size)
778
Simon Glass3ab95982018-08-01 15:22:37 -0600779 # Fifth u-boot, placed at a fixed offset
Simon Glass4f443042016-11-25 20:15:52 -0700780 self.assertIn('u-boot-fixed', entries)
781 entry = entries['u-boot-fixed']
Simon Glass3ab95982018-08-01 15:22:37 -0600782 self.assertEqual(61, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700783 self.assertEqual(len(U_BOOT_DATA), entry.size)
784
Simon Glass8beb11e2019-07-08 14:25:47 -0600785 self.assertEqual(65, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700786
787 def testPackExtra(self):
788 """Test that extra packing feature works as expected"""
Simon Glass4eec34c2020-10-26 17:40:10 -0600789 data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
790 update_dtb=True)
Simon Glass4f443042016-11-25 20:15:52 -0700791
Simon Glass4f443042016-11-25 20:15:52 -0700792 self.assertIn('image', control.images)
793 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600794 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700795 self.assertEqual(5, len(entries))
796
797 # First u-boot with padding before and after
798 self.assertIn('u-boot', entries)
799 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600800 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700801 self.assertEqual(3, entry.pad_before)
802 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600803 self.assertEqual(U_BOOT_DATA, entry.data)
804 self.assertEqual(tools.GetBytes(0, 3) + U_BOOT_DATA +
805 tools.GetBytes(0, 5), data[:entry.size])
806 pos = entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700807
808 # Second u-boot has an aligned size, but it has no effect
809 self.assertIn('u-boot-align-size-nop', entries)
810 entry = entries['u-boot-align-size-nop']
Simon Glassef439ed2020-10-26 17:40:08 -0600811 self.assertEqual(pos, entry.offset)
812 self.assertEqual(len(U_BOOT_DATA), entry.size)
813 self.assertEqual(U_BOOT_DATA, entry.data)
814 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
815 pos += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700816
817 # Third u-boot has an aligned size too
818 self.assertIn('u-boot-align-size', entries)
819 entry = entries['u-boot-align-size']
Simon Glassef439ed2020-10-26 17:40:08 -0600820 self.assertEqual(pos, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700821 self.assertEqual(32, entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600822 self.assertEqual(U_BOOT_DATA, entry.data)
823 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 32 - len(U_BOOT_DATA)),
824 data[pos:pos + entry.size])
825 pos += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700826
827 # Fourth u-boot has an aligned end
828 self.assertIn('u-boot-align-end', entries)
829 entry = entries['u-boot-align-end']
Simon Glass3ab95982018-08-01 15:22:37 -0600830 self.assertEqual(48, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700831 self.assertEqual(16, entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600832 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
833 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 16 - len(U_BOOT_DATA)),
834 data[pos:pos + entry.size])
835 pos += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700836
837 # Fifth u-boot immediately afterwards
838 self.assertIn('u-boot-align-both', entries)
839 entry = entries['u-boot-align-both']
Simon Glass3ab95982018-08-01 15:22:37 -0600840 self.assertEqual(64, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700841 self.assertEqual(64, entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600842 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
843 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 64 - len(U_BOOT_DATA)),
844 data[pos:pos + entry.size])
Simon Glass4f443042016-11-25 20:15:52 -0700845
846 self.CheckNoGaps(entries)
Simon Glass8beb11e2019-07-08 14:25:47 -0600847 self.assertEqual(128, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700848
Simon Glass4eec34c2020-10-26 17:40:10 -0600849 dtb = fdt.Fdt(out_dtb_fname)
850 dtb.Scan()
851 props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
852 expected = {
853 'image-pos': 0,
854 'offset': 0,
855 'size': 128,
856
857 'u-boot:image-pos': 0,
858 'u-boot:offset': 0,
859 'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
860
861 'u-boot-align-size-nop:image-pos': 12,
862 'u-boot-align-size-nop:offset': 12,
863 'u-boot-align-size-nop:size': 4,
864
865 'u-boot-align-size:image-pos': 16,
866 'u-boot-align-size:offset': 16,
867 'u-boot-align-size:size': 32,
868
869 'u-boot-align-end:image-pos': 48,
870 'u-boot-align-end:offset': 48,
871 'u-boot-align-end:size': 16,
872
873 'u-boot-align-both:image-pos': 64,
874 'u-boot-align-both:offset': 64,
875 'u-boot-align-both:size': 64,
876 }
877 self.assertEqual(expected, props)
878
Simon Glass4f443042016-11-25 20:15:52 -0700879 def testPackAlignPowerOf2(self):
880 """Test that invalid entry alignment is detected"""
881 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600882 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700883 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
884 "of two", str(e.exception))
885
886 def testPackAlignSizePowerOf2(self):
887 """Test that invalid entry size alignment is detected"""
888 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600889 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700890 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
891 "power of two", str(e.exception))
892
893 def testPackInvalidAlign(self):
Simon Glass3ab95982018-08-01 15:22:37 -0600894 """Test detection of an offset that does not match its alignment"""
Simon Glass4f443042016-11-25 20:15:52 -0700895 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600896 self._DoTestFile('012_pack_inv_align.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600897 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700898 "align 0x4 (4)", str(e.exception))
899
900 def testPackInvalidSizeAlign(self):
901 """Test that invalid entry size alignment is detected"""
902 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600903 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700904 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
905 "align-size 0x4 (4)", str(e.exception))
906
907 def testPackOverlap(self):
908 """Test that overlapping regions are detected"""
909 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600910 self._DoTestFile('014_pack_overlap.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600911 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -0700912 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
913 str(e.exception))
914
915 def testPackEntryOverflow(self):
916 """Test that entries that overflow their size are detected"""
917 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600918 self._DoTestFile('015_pack_overflow.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700919 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
920 "but entry size is 0x3 (3)", str(e.exception))
921
922 def testPackImageOverflow(self):
923 """Test that entries which overflow the image size are detected"""
924 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600925 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600926 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass4f443042016-11-25 20:15:52 -0700927 "size 0x3 (3)", str(e.exception))
928
929 def testPackImageSize(self):
930 """Test that the image size can be set"""
Simon Glass741f2d62018-10-01 12:22:30 -0600931 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700932 self.assertEqual(0, retcode)
933 self.assertIn('image', control.images)
934 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -0600935 self.assertEqual(7, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700936
937 def testPackImageSizeAlign(self):
938 """Test that image size alignemnt works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600939 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700940 self.assertEqual(0, retcode)
941 self.assertIn('image', control.images)
942 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -0600943 self.assertEqual(16, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700944
945 def testPackInvalidImageAlign(self):
946 """Test that invalid image alignment is detected"""
947 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600948 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600949 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700950 "align-size 0x8 (8)", str(e.exception))
951
952 def testPackAlignPowerOf2(self):
953 """Test that invalid image alignment is detected"""
954 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600955 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -0600956 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass4f443042016-11-25 20:15:52 -0700957 "two", str(e.exception))
958
959 def testImagePadByte(self):
960 """Test that the image pad byte can be specified"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600961 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600962 data = self._DoReadFile('021_image_pad.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -0600963 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0xff, 1) +
964 U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -0700965
966 def testImageName(self):
967 """Test that image files can be named"""
Simon Glass741f2d62018-10-01 12:22:30 -0600968 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700969 self.assertEqual(0, retcode)
970 image = control.images['image1']
971 fname = tools.GetOutputFilename('test-name')
972 self.assertTrue(os.path.exists(fname))
973
974 image = control.images['image2']
975 fname = tools.GetOutputFilename('test-name.xx')
976 self.assertTrue(os.path.exists(fname))
977
978 def testBlobFilename(self):
979 """Test that generic blobs can be provided by filename"""
Simon Glass741f2d62018-10-01 12:22:30 -0600980 data = self._DoReadFile('023_blob.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700981 self.assertEqual(BLOB_DATA, data)
982
983 def testPackSorted(self):
984 """Test that entries can be sorted"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600985 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600986 data = self._DoReadFile('024_sorted.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -0600987 self.assertEqual(tools.GetBytes(0, 1) + U_BOOT_SPL_DATA +
988 tools.GetBytes(0, 2) + U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -0700989
Simon Glass3ab95982018-08-01 15:22:37 -0600990 def testPackZeroOffset(self):
991 """Test that an entry at offset 0 is not given a new offset"""
Simon Glass4f443042016-11-25 20:15:52 -0700992 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600993 self._DoTestFile('025_pack_zero_size.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600994 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -0700995 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
996 str(e.exception))
997
998 def testPackUbootDtb(self):
999 """Test that a device tree can be added to U-Boot"""
Simon Glass741f2d62018-10-01 12:22:30 -06001000 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001001 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glasse0ff8552016-11-25 20:15:53 -07001002
1003 def testPackX86RomNoSize(self):
1004 """Test that the end-at-4gb property requires a size property"""
1005 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001006 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -06001007 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glasse0ff8552016-11-25 20:15:53 -07001008 "using end-at-4gb", str(e.exception))
1009
Jagdish Gediya94b57db2018-09-03 21:35:07 +05301010 def test4gbAndSkipAtStartTogether(self):
1011 """Test that the end-at-4gb and skip-at-size property can't be used
1012 together"""
1013 with self.assertRaises(ValueError) as e:
Simon Glassdfdd2b62019-08-24 07:23:02 -06001014 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -06001015 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya94b57db2018-09-03 21:35:07 +05301016 "'skip-at-start'", str(e.exception))
1017
Simon Glasse0ff8552016-11-25 20:15:53 -07001018 def testPackX86RomOutside(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001019 """Test that the end-at-4gb property checks for offset boundaries"""
Simon Glasse0ff8552016-11-25 20:15:53 -07001020 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001021 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glasse6bed4f2020-10-26 17:40:05 -06001022 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
1023 "is outside the section '/binman' starting at "
1024 '0xffffffe0 (4294967264) of size 0x20 (32)',
Simon Glasse0ff8552016-11-25 20:15:53 -07001025 str(e.exception))
1026
1027 def testPackX86Rom(self):
1028 """Test that a basic x86 ROM can be created"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001029 self._SetupSplElf()
Simon Glass9255f3c2019-08-24 07:23:01 -06001030 data = self._DoReadFile('029_x86_rom.dts')
Simon Glasseb0086f2019-08-24 07:23:04 -06001031 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 3) + U_BOOT_SPL_DATA +
Simon Glasse6d85ff2019-05-14 15:53:47 -06001032 tools.GetBytes(0, 2), data)
Simon Glasse0ff8552016-11-25 20:15:53 -07001033
1034 def testPackX86RomMeNoDesc(self):
1035 """Test that an invalid Intel descriptor entry is detected"""
Simon Glass0ba4b3d2020-07-09 18:39:41 -06001036 try:
Simon Glass52b10dd2020-07-25 15:11:19 -06001037 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
Simon Glass0ba4b3d2020-07-09 18:39:41 -06001038 with self.assertRaises(ValueError) as e:
Simon Glass52b10dd2020-07-25 15:11:19 -06001039 self._DoTestFile('163_x86_rom_me_empty.dts')
Simon Glass0ba4b3d2020-07-09 18:39:41 -06001040 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1041 str(e.exception))
1042 finally:
1043 self._SetupDescriptor()
Simon Glasse0ff8552016-11-25 20:15:53 -07001044
1045 def testPackX86RomBadDesc(self):
1046 """Test that the Intel requires a descriptor entry"""
1047 with self.assertRaises(ValueError) as e:
Simon Glass9255f3c2019-08-24 07:23:01 -06001048 self._DoTestFile('030_x86_rom_me_no_desc.dts')
Simon Glass3ab95982018-08-01 15:22:37 -06001049 self.assertIn("Node '/binman/intel-me': No offset set with "
1050 "offset-unset: should another entry provide this correct "
1051 "offset?", str(e.exception))
Simon Glasse0ff8552016-11-25 20:15:53 -07001052
1053 def testPackX86RomMe(self):
1054 """Test that an x86 ROM with an ME region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001055 data = self._DoReadFile('031_x86_rom_me.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06001056 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
1057 if data[:0x1000] != expected_desc:
1058 self.fail('Expected descriptor binary at start of image')
Simon Glasse0ff8552016-11-25 20:15:53 -07001059 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1060
1061 def testPackVga(self):
1062 """Test that an image with a VGA binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001063 data = self._DoReadFile('032_intel_vga.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -07001064 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1065
1066 def testPackStart16(self):
1067 """Test that an image with an x86 start16 region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001068 data = self._DoReadFile('033_x86_start16.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -07001069 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1070
Jagdish Gediya9d368f32018-09-03 21:35:08 +05301071 def testPackPowerpcMpc85xxBootpgResetvec(self):
1072 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1073 created"""
Simon Glassdfdd2b62019-08-24 07:23:02 -06001074 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
Jagdish Gediya9d368f32018-09-03 21:35:08 +05301075 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1076
Simon Glass736bb0a2018-07-06 10:27:17 -06001077 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glassadc57012018-07-06 10:27:16 -06001078 """Handle running a test for insertion of microcode
1079
1080 Args:
1081 dts_fname: Name of test .dts file
1082 nodtb_data: Data that we expect in the first section
Simon Glass736bb0a2018-07-06 10:27:17 -06001083 ucode_second: True if the microsecond entry is second instead of
1084 third
Simon Glassadc57012018-07-06 10:27:16 -06001085
1086 Returns:
1087 Tuple:
1088 Contents of first region (U-Boot or SPL)
Simon Glass3ab95982018-08-01 15:22:37 -06001089 Offset and size components of microcode pointer, as inserted
Simon Glassadc57012018-07-06 10:27:16 -06001090 in the above (two 4-byte words)
1091 """
Simon Glass6b187df2017-11-12 21:52:27 -07001092 data = self._DoReadFile(dts_fname, True)
Simon Glasse0ff8552016-11-25 20:15:53 -07001093
1094 # Now check the device tree has no microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001095 if ucode_second:
1096 ucode_content = data[len(nodtb_data):]
1097 ucode_pos = len(nodtb_data)
1098 dtb_with_ucode = ucode_content[16:]
1099 fdt_len = self.GetFdtLen(dtb_with_ucode)
1100 else:
1101 dtb_with_ucode = data[len(nodtb_data):]
1102 fdt_len = self.GetFdtLen(dtb_with_ucode)
1103 ucode_content = dtb_with_ucode[fdt_len:]
1104 ucode_pos = len(nodtb_data) + fdt_len
Simon Glasse0ff8552016-11-25 20:15:53 -07001105 fname = tools.GetOutputFilename('test.dtb')
1106 with open(fname, 'wb') as fd:
Simon Glassadc57012018-07-06 10:27:16 -06001107 fd.write(dtb_with_ucode)
Simon Glassec3f3782017-05-27 07:38:29 -06001108 dtb = fdt.FdtScan(fname)
1109 ucode = dtb.GetNode('/microcode')
Simon Glasse0ff8552016-11-25 20:15:53 -07001110 self.assertTrue(ucode)
1111 for node in ucode.subnodes:
1112 self.assertFalse(node.props.get('data'))
1113
Simon Glasse0ff8552016-11-25 20:15:53 -07001114 # Check that the microcode appears immediately after the Fdt
1115 # This matches the concatenation of the data properties in
Simon Glass87722132017-11-12 21:52:26 -07001116 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glasse0ff8552016-11-25 20:15:53 -07001117 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1118 0x78235609)
Simon Glassadc57012018-07-06 10:27:16 -06001119 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glasse0ff8552016-11-25 20:15:53 -07001120
1121 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -06001122 # expected offset and size
Simon Glasse0ff8552016-11-25 20:15:53 -07001123 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1124 len(ucode_data))
Simon Glass736bb0a2018-07-06 10:27:17 -06001125 u_boot = data[:len(nodtb_data)]
1126 return u_boot, pos_and_size
Simon Glass6b187df2017-11-12 21:52:27 -07001127
1128 def testPackUbootMicrocode(self):
1129 """Test that x86 microcode can be handled correctly
1130
1131 We expect to see the following in the image, in order:
1132 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1133 place
1134 u-boot.dtb with the microcode removed
1135 the microcode
1136 """
Simon Glass741f2d62018-10-01 12:22:30 -06001137 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass6b187df2017-11-12 21:52:27 -07001138 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 Glasse0ff8552016-11-25 20:15:53 -07001141
Simon Glass160a7662017-05-27 07:38:26 -06001142 def _RunPackUbootSingleMicrocode(self):
Simon Glasse0ff8552016-11-25 20:15:53 -07001143 """Test that x86 microcode can be handled correctly
1144
1145 We expect to see the following in the image, in order:
1146 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1147 place
1148 u-boot.dtb with the microcode
1149 an empty microcode region
1150 """
1151 # We need the libfdt library to run this test since only that allows
1152 # finding the offset of a property. This is required by
1153 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass741f2d62018-10-01 12:22:30 -06001154 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glasse0ff8552016-11-25 20:15:53 -07001155
1156 second = data[len(U_BOOT_NODTB_DATA):]
1157
1158 fdt_len = self.GetFdtLen(second)
1159 third = second[fdt_len:]
1160 second = second[:fdt_len]
1161
Simon Glass160a7662017-05-27 07:38:26 -06001162 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1163 self.assertIn(ucode_data, second)
1164 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -07001165
Simon Glass160a7662017-05-27 07:38:26 -06001166 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -06001167 # expected offset and size
Simon Glass160a7662017-05-27 07:38:26 -06001168 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1169 len(ucode_data))
1170 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glassc6c10e72019-05-17 22:00:46 -06001171 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1172 b' somewhere in here', first)
Simon Glassc49deb82016-11-25 20:15:54 -07001173
Simon Glass75db0862016-11-25 20:15:55 -07001174 def testPackUbootSingleMicrocode(self):
1175 """Test that x86 microcode can be handled correctly with fdt_normal.
1176 """
Simon Glass160a7662017-05-27 07:38:26 -06001177 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001178
Simon Glassc49deb82016-11-25 20:15:54 -07001179 def testUBootImg(self):
1180 """Test that u-boot.img can be put in a file"""
Simon Glass741f2d62018-10-01 12:22:30 -06001181 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glassc49deb82016-11-25 20:15:54 -07001182 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glass75db0862016-11-25 20:15:55 -07001183
1184 def testNoMicrocode(self):
1185 """Test that a missing microcode region is detected"""
1186 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001187 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001188 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1189 "node found in ", str(e.exception))
1190
1191 def testMicrocodeWithoutNode(self):
1192 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1193 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001194 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001195 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1196 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1197
1198 def testMicrocodeWithoutNode2(self):
1199 """Test that a missing u-boot-ucode node is detected"""
1200 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001201 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001202 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1203 "microcode region u-boot-ucode", str(e.exception))
1204
1205 def testMicrocodeWithoutPtrInElf(self):
1206 """Test that a U-Boot binary without the microcode symbol is detected"""
1207 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glass75db0862016-11-25 20:15:55 -07001208 try:
Simon Glassbccd91d2019-08-24 07:22:55 -06001209 TestFunctional._MakeInputFile('u-boot',
1210 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass75db0862016-11-25 20:15:55 -07001211
1212 with self.assertRaises(ValueError) as e:
Simon Glass160a7662017-05-27 07:38:26 -06001213 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001214 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1215 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1216
1217 finally:
1218 # Put the original file back
Simon Glassf514d8f2019-08-24 07:22:54 -06001219 TestFunctional._MakeInputFile('u-boot',
1220 tools.ReadFile(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glass75db0862016-11-25 20:15:55 -07001221
1222 def testMicrocodeNotInImage(self):
1223 """Test that microcode must be placed within the image"""
1224 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001225 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001226 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1227 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glass25ac0e62018-06-01 09:38:14 -06001228 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glass75db0862016-11-25 20:15:55 -07001229
1230 def testWithoutMicrocode(self):
1231 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glassbccd91d2019-08-24 07:22:55 -06001232 TestFunctional._MakeInputFile('u-boot',
1233 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass741f2d62018-10-01 12:22:30 -06001234 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001235
1236 # Now check the device tree has no microcode
1237 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1238 second = data[len(U_BOOT_NODTB_DATA):]
1239
1240 fdt_len = self.GetFdtLen(second)
1241 self.assertEqual(dtb, second[:fdt_len])
1242
1243 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1244 third = data[used_len:]
Simon Glasse6d85ff2019-05-14 15:53:47 -06001245 self.assertEqual(tools.GetBytes(0, 0x200 - used_len), third)
Simon Glass75db0862016-11-25 20:15:55 -07001246
1247 def testUnknownPosSize(self):
1248 """Test that microcode must be placed within the image"""
1249 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001250 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glass3ab95982018-08-01 15:22:37 -06001251 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glass75db0862016-11-25 20:15:55 -07001252 "entry 'invalid-entry'", str(e.exception))
Simon Glassda229092016-11-25 20:15:56 -07001253
1254 def testPackFsp(self):
1255 """Test that an image with a FSP binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001256 data = self._DoReadFile('042_intel_fsp.dts')
Simon Glassda229092016-11-25 20:15:56 -07001257 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1258
1259 def testPackCmc(self):
Bin Meng59ea8c22017-08-15 22:41:54 -07001260 """Test that an image with a CMC binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001261 data = self._DoReadFile('043_intel_cmc.dts')
Simon Glassda229092016-11-25 20:15:56 -07001262 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Meng59ea8c22017-08-15 22:41:54 -07001263
1264 def testPackVbt(self):
1265 """Test that an image with a VBT binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001266 data = self._DoReadFile('046_intel_vbt.dts')
Bin Meng59ea8c22017-08-15 22:41:54 -07001267 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glass9fc60b42017-11-12 21:52:22 -07001268
Simon Glass56509842017-11-12 21:52:25 -07001269 def testSplBssPad(self):
1270 """Test that we can pad SPL's BSS with zeros"""
Simon Glass6b187df2017-11-12 21:52:27 -07001271 # ELF file with a '__bss_size' symbol
Simon Glass11ae93e2018-10-01 21:12:47 -06001272 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001273 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001274 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
1275 data)
Simon Glass56509842017-11-12 21:52:25 -07001276
Simon Glass86af5112018-10-01 21:12:42 -06001277 def testSplBssPadMissing(self):
1278 """Test that a missing symbol is detected"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001279 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glassb50e5612017-11-13 18:54:54 -07001280 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001281 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassb50e5612017-11-13 18:54:54 -07001282 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1283 str(e.exception))
1284
Simon Glass87722132017-11-12 21:52:26 -07001285 def testPackStart16Spl(self):
Simon Glass35b384c2018-09-14 04:57:10 -06001286 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001287 data = self._DoReadFile('048_x86_start16_spl.dts')
Simon Glass87722132017-11-12 21:52:26 -07001288 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1289
Simon Glass736bb0a2018-07-06 10:27:17 -06001290 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1291 """Helper function for microcode tests
Simon Glass6b187df2017-11-12 21:52:27 -07001292
1293 We expect to see the following in the image, in order:
1294 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1295 correct place
1296 u-boot.dtb with the microcode removed
1297 the microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001298
1299 Args:
1300 dts: Device tree file to use for test
1301 ucode_second: True if the microsecond entry is second instead of
1302 third
Simon Glass6b187df2017-11-12 21:52:27 -07001303 """
Simon Glass11ae93e2018-10-01 21:12:47 -06001304 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass736bb0a2018-07-06 10:27:17 -06001305 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1306 ucode_second=ucode_second)
Simon Glassc6c10e72019-05-17 22:00:46 -06001307 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1308 b'ter somewhere in here', first)
Simon Glass6b187df2017-11-12 21:52:27 -07001309
Simon Glass736bb0a2018-07-06 10:27:17 -06001310 def testPackUbootSplMicrocode(self):
1311 """Test that x86 microcode can be handled correctly in SPL"""
Simon Glass741f2d62018-10-01 12:22:30 -06001312 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass736bb0a2018-07-06 10:27:17 -06001313
1314 def testPackUbootSplMicrocodeReorder(self):
1315 """Test that order doesn't matter for microcode entries
1316
1317 This is the same as testPackUbootSplMicrocode but when we process the
1318 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1319 entry, so we reply on binman to try later.
1320 """
Simon Glass741f2d62018-10-01 12:22:30 -06001321 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass736bb0a2018-07-06 10:27:17 -06001322 ucode_second=True)
1323
Simon Glassca4f4ff2017-11-12 21:52:28 -07001324 def testPackMrc(self):
1325 """Test that an image with an MRC binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001326 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassca4f4ff2017-11-12 21:52:28 -07001327 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1328
Simon Glass47419ea2017-11-13 18:54:55 -07001329 def testSplDtb(self):
1330 """Test that an image with spl/u-boot-spl.dtb can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001331 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass47419ea2017-11-13 18:54:55 -07001332 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1333
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001334 def testSplNoDtb(self):
1335 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001336 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001337 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1338
Simon Glass19790632017-11-13 18:55:01 -07001339 def testSymbols(self):
1340 """Test binman can assign symbols embedded in U-Boot"""
Simon Glass1542c8b2019-08-24 07:22:56 -06001341 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass19790632017-11-13 18:55:01 -07001342 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1343 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Simon Glass3ab95982018-08-01 15:22:37 -06001344 self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr)
Simon Glass19790632017-11-13 18:55:01 -07001345
Simon Glass11ae93e2018-10-01 21:12:47 -06001346 self._SetupSplElf('u_boot_binman_syms')
Simon Glass741f2d62018-10-01 12:22:30 -06001347 data = self._DoReadFile('053_symbols.dts')
Simon Glass7c150132019-11-06 17:22:44 -07001348 sym_values = struct.pack('<LQLL', 0x00, 0x1c, 0x28, 0x04)
Simon Glassb87064c2019-08-24 07:23:05 -06001349 expected = (sym_values + U_BOOT_SPL_DATA[20:] +
Simon Glasse6d85ff2019-05-14 15:53:47 -06001350 tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
Simon Glassb87064c2019-08-24 07:23:05 -06001351 U_BOOT_SPL_DATA[20:])
Simon Glass19790632017-11-13 18:55:01 -07001352 self.assertEqual(expected, data)
1353
Simon Glassdd57c132018-06-01 09:38:11 -06001354 def testPackUnitAddress(self):
1355 """Test that we support multiple binaries with the same name"""
Simon Glass741f2d62018-10-01 12:22:30 -06001356 data = self._DoReadFile('054_unit_address.dts')
Simon Glassdd57c132018-06-01 09:38:11 -06001357 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1358
Simon Glass18546952018-06-01 09:38:16 -06001359 def testSections(self):
1360 """Basic test of sections"""
Simon Glass741f2d62018-10-01 12:22:30 -06001361 data = self._DoReadFile('055_sections.dts')
Simon Glassc6c10e72019-05-17 22:00:46 -06001362 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1363 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
1364 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
Simon Glass18546952018-06-01 09:38:16 -06001365 self.assertEqual(expected, data)
Simon Glass9fc60b42017-11-12 21:52:22 -07001366
Simon Glass3b0c3822018-06-01 09:38:20 -06001367 def testMap(self):
1368 """Tests outputting a map of the images"""
Simon Glass741f2d62018-10-01 12:22:30 -06001369 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001370 self.assertEqual('''ImagePos Offset Size Name
137100000000 00000000 00000028 main-section
137200000000 00000000 00000010 section@0
137300000000 00000000 00000004 u-boot
137400000010 00000010 00000010 section@1
137500000010 00000000 00000004 u-boot
137600000020 00000020 00000004 section@2
137700000020 00000000 00000004 u-boot
Simon Glass3b0c3822018-06-01 09:38:20 -06001378''', map_data)
1379
Simon Glassc8d48ef2018-06-01 09:38:21 -06001380 def testNamePrefix(self):
1381 """Tests that name prefixes are used"""
Simon Glass741f2d62018-10-01 12:22:30 -06001382 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001383 self.assertEqual('''ImagePos Offset Size Name
138400000000 00000000 00000028 main-section
138500000000 00000000 00000010 section@0
138600000000 00000000 00000004 ro-u-boot
138700000010 00000010 00000010 section@1
138800000010 00000000 00000004 rw-u-boot
Simon Glassc8d48ef2018-06-01 09:38:21 -06001389''', map_data)
1390
Simon Glass736bb0a2018-07-06 10:27:17 -06001391 def testUnknownContents(self):
1392 """Test that obtaining the contents works as expected"""
1393 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001394 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass8beb11e2019-07-08 14:25:47 -06001395 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glass16287932020-04-17 18:09:03 -06001396 "processing of contents: remaining ["
1397 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass736bb0a2018-07-06 10:27:17 -06001398
Simon Glass5c890232018-07-06 10:27:19 -06001399 def testBadChangeSize(self):
1400 """Test that trying to change the size of an entry fails"""
Simon Glassc52c9e72019-07-08 14:25:37 -06001401 try:
1402 state.SetAllowEntryExpansion(False)
1403 with self.assertRaises(ValueError) as e:
1404 self._DoReadFile('059_change_size.dts', True)
Simon Glass79d3c582019-07-20 12:23:57 -06001405 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glassc52c9e72019-07-08 14:25:37 -06001406 str(e.exception))
1407 finally:
1408 state.SetAllowEntryExpansion(True)
Simon Glass5c890232018-07-06 10:27:19 -06001409
Simon Glass16b8d6b2018-07-06 10:27:42 -06001410 def testUpdateFdt(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001411 """Test that we can update the device tree with offset/size info"""
Simon Glass741f2d62018-10-01 12:22:30 -06001412 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glass16b8d6b2018-07-06 10:27:42 -06001413 update_dtb=True)
Simon Glasscee02e62018-07-17 13:25:52 -06001414 dtb = fdt.Fdt(out_dtb_fname)
1415 dtb.Scan()
Simon Glass12bb1a92019-07-20 12:23:51 -06001416 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001417 self.assertEqual({
Simon Glassdbf6be92018-08-01 15:22:42 -06001418 'image-pos': 0,
Simon Glass8122f392018-07-17 13:25:28 -06001419 'offset': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001420 '_testing:offset': 32,
Simon Glass79d3c582019-07-20 12:23:57 -06001421 '_testing:size': 2,
Simon Glassdbf6be92018-08-01 15:22:42 -06001422 '_testing:image-pos': 32,
Simon Glass3ab95982018-08-01 15:22:37 -06001423 'section@0/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001424 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001425 'section@0/u-boot:image-pos': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001426 'section@0:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001427 'section@0:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001428 'section@0:image-pos': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001429
Simon Glass3ab95982018-08-01 15:22:37 -06001430 'section@1/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001431 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001432 'section@1/u-boot:image-pos': 16,
Simon Glass3ab95982018-08-01 15:22:37 -06001433 'section@1:offset': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001434 'section@1:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001435 'section@1:image-pos': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001436 'size': 40
1437 }, props)
1438
1439 def testUpdateFdtBad(self):
1440 """Test that we detect when ProcessFdt never completes"""
1441 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001442 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001443 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glass16287932020-04-17 18:09:03 -06001444 '[<binman.etype._testing.Entry__testing',
1445 str(e.exception))
Simon Glass5c890232018-07-06 10:27:19 -06001446
Simon Glass53af22a2018-07-17 13:25:32 -06001447 def testEntryArgs(self):
1448 """Test passing arguments to entries from the command line"""
1449 entry_args = {
1450 'test-str-arg': 'test1',
1451 'test-int-arg': '456',
1452 }
Simon Glass741f2d62018-10-01 12:22:30 -06001453 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001454 self.assertIn('image', control.images)
1455 entry = control.images['image'].GetEntries()['_testing']
1456 self.assertEqual('test0', entry.test_str_fdt)
1457 self.assertEqual('test1', entry.test_str_arg)
1458 self.assertEqual(123, entry.test_int_fdt)
1459 self.assertEqual(456, entry.test_int_arg)
1460
1461 def testEntryArgsMissing(self):
1462 """Test missing arguments and properties"""
1463 entry_args = {
1464 'test-int-arg': '456',
1465 }
Simon Glass741f2d62018-10-01 12:22:30 -06001466 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001467 entry = control.images['image'].GetEntries()['_testing']
1468 self.assertEqual('test0', entry.test_str_fdt)
1469 self.assertEqual(None, entry.test_str_arg)
1470 self.assertEqual(None, entry.test_int_fdt)
1471 self.assertEqual(456, entry.test_int_arg)
1472
1473 def testEntryArgsRequired(self):
1474 """Test missing arguments and properties"""
1475 entry_args = {
1476 'test-int-arg': '456',
1477 }
1478 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001479 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass3decfa32020-09-01 05:13:54 -06001480 self.assertIn("Node '/binman/_testing': "
1481 'Missing required properties/entry args: test-str-arg, '
1482 'test-int-fdt, test-int-arg',
Simon Glass53af22a2018-07-17 13:25:32 -06001483 str(e.exception))
1484
1485 def testEntryArgsInvalidFormat(self):
1486 """Test that an invalid entry-argument format is detected"""
Simon Glass53cd5d92019-07-08 14:25:29 -06001487 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1488 '-ano-value']
Simon Glass53af22a2018-07-17 13:25:32 -06001489 with self.assertRaises(ValueError) as e:
1490 self._DoBinman(*args)
1491 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1492
1493 def testEntryArgsInvalidInteger(self):
1494 """Test that an invalid entry-argument integer is detected"""
1495 entry_args = {
1496 'test-int-arg': 'abc',
1497 }
1498 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001499 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001500 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1501 "'test-int-arg' (value 'abc') to integer",
1502 str(e.exception))
1503
1504 def testEntryArgsInvalidDatatype(self):
1505 """Test that an invalid entry-argument datatype is detected
1506
1507 This test could be written in entry_test.py except that it needs
1508 access to control.entry_args, which seems more than that module should
1509 be able to see.
1510 """
1511 entry_args = {
1512 'test-bad-datatype-arg': '12',
1513 }
1514 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001515 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass53af22a2018-07-17 13:25:32 -06001516 entry_args=entry_args)
1517 self.assertIn('GetArg() internal error: Unknown data type ',
1518 str(e.exception))
1519
Simon Glassbb748372018-07-17 13:25:33 -06001520 def testText(self):
1521 """Test for a text entry type"""
1522 entry_args = {
1523 'test-id': TEXT_DATA,
1524 'test-id2': TEXT_DATA2,
1525 'test-id3': TEXT_DATA3,
1526 }
Simon Glass741f2d62018-10-01 12:22:30 -06001527 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glassbb748372018-07-17 13:25:33 -06001528 entry_args=entry_args)
Simon Glassc6c10e72019-05-17 22:00:46 -06001529 expected = (tools.ToBytes(TEXT_DATA) +
1530 tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1531 tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
Simon Glassaa88b502019-07-08 13:18:40 -06001532 b'some text' + b'more text')
Simon Glassbb748372018-07-17 13:25:33 -06001533 self.assertEqual(expected, data)
1534
Simon Glassfd8d1f72018-07-17 13:25:36 -06001535 def testEntryDocs(self):
1536 """Test for creation of entry documentation"""
1537 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass87d43322020-08-05 13:27:46 -06001538 control.WriteEntryDocs(control.GetEntryModules())
Simon Glassfd8d1f72018-07-17 13:25:36 -06001539 self.assertTrue(len(stdout.getvalue()) > 0)
1540
1541 def testEntryDocsMissing(self):
1542 """Test handling of missing entry documentation"""
1543 with self.assertRaises(ValueError) as e:
1544 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass87d43322020-08-05 13:27:46 -06001545 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glassfd8d1f72018-07-17 13:25:36 -06001546 self.assertIn('Documentation is missing for modules: u_boot',
1547 str(e.exception))
1548
Simon Glass11e36cc2018-07-17 13:25:38 -06001549 def testFmap(self):
1550 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001551 data = self._DoReadFile('067_fmap.dts')
Simon Glass11e36cc2018-07-17 13:25:38 -06001552 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc6c10e72019-05-17 22:00:46 -06001553 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1554 U_BOOT_DATA + tools.GetBytes(ord('a'), 12))
Simon Glass11e36cc2018-07-17 13:25:38 -06001555 self.assertEqual(expected, data[:32])
Simon Glassc6c10e72019-05-17 22:00:46 -06001556 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass11e36cc2018-07-17 13:25:38 -06001557 self.assertEqual(1, fhdr.ver_major)
1558 self.assertEqual(0, fhdr.ver_minor)
1559 self.assertEqual(0, fhdr.base)
1560 self.assertEqual(16 + 16 +
1561 fmap_util.FMAP_HEADER_LEN +
1562 fmap_util.FMAP_AREA_LEN * 3, fhdr.image_size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001563 self.assertEqual(b'FMAP', fhdr.name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001564 self.assertEqual(3, fhdr.nareas)
1565 for fentry in fentries:
1566 self.assertEqual(0, fentry.flags)
1567
1568 self.assertEqual(0, fentries[0].offset)
1569 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001570 self.assertEqual(b'RO_U_BOOT', fentries[0].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001571
1572 self.assertEqual(16, fentries[1].offset)
1573 self.assertEqual(4, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001574 self.assertEqual(b'RW_U_BOOT', fentries[1].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001575
1576 self.assertEqual(32, fentries[2].offset)
1577 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1578 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001579 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001580
Simon Glassec127af2018-07-17 13:25:39 -06001581 def testBlobNamedByArg(self):
1582 """Test we can add a blob with the filename coming from an entry arg"""
1583 entry_args = {
1584 'cros-ec-rw-path': 'ecrw.bin',
1585 }
Simon Glass3decfa32020-09-01 05:13:54 -06001586 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassec127af2018-07-17 13:25:39 -06001587
Simon Glass3af8e492018-07-17 13:25:40 -06001588 def testFill(self):
1589 """Test for an fill entry type"""
Simon Glass741f2d62018-10-01 12:22:30 -06001590 data = self._DoReadFile('069_fill.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001591 expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
Simon Glass3af8e492018-07-17 13:25:40 -06001592 self.assertEqual(expected, data)
1593
1594 def testFillNoSize(self):
1595 """Test for an fill entry type with no size"""
1596 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001597 self._DoReadFile('070_fill_no_size.dts')
Simon Glass3af8e492018-07-17 13:25:40 -06001598 self.assertIn("'fill' entry must have a size property",
1599 str(e.exception))
1600
Simon Glass0ef87aa2018-07-17 13:25:44 -06001601 def _HandleGbbCommand(self, pipe_list):
1602 """Fake calls to the futility utility"""
1603 if pipe_list[0][0] == 'futility':
1604 fname = pipe_list[0][-1]
1605 # Append our GBB data to the file, which will happen every time the
1606 # futility command is called.
Simon Glass1d0ebf72019-05-14 15:53:42 -06001607 with open(fname, 'ab') as fd:
Simon Glass0ef87aa2018-07-17 13:25:44 -06001608 fd.write(GBB_DATA)
1609 return command.CommandResult()
1610
1611 def testGbb(self):
1612 """Test for the Chromium OS Google Binary Block"""
1613 command.test_result = self._HandleGbbCommand
1614 entry_args = {
1615 'keydir': 'devkeys',
1616 'bmpblk': 'bmpblk.bin',
1617 }
Simon Glass741f2d62018-10-01 12:22:30 -06001618 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glass0ef87aa2018-07-17 13:25:44 -06001619
1620 # Since futility
Simon Glasse6d85ff2019-05-14 15:53:47 -06001621 expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1622 tools.GetBytes(0, 0x2180 - 16))
Simon Glass0ef87aa2018-07-17 13:25:44 -06001623 self.assertEqual(expected, data)
1624
1625 def testGbbTooSmall(self):
1626 """Test for the Chromium OS Google Binary Block being large enough"""
1627 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001628 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001629 self.assertIn("Node '/binman/gbb': GBB is too small",
1630 str(e.exception))
1631
1632 def testGbbNoSize(self):
1633 """Test for the Chromium OS Google Binary Block having a size"""
1634 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001635 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001636 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1637 str(e.exception))
1638
Simon Glass24d0d3c2018-07-17 13:25:47 -06001639 def _HandleVblockCommand(self, pipe_list):
1640 """Fake calls to the futility utility"""
1641 if pipe_list[0][0] == 'futility':
1642 fname = pipe_list[0][3]
Simon Glassa326b492018-09-14 04:57:11 -06001643 with open(fname, 'wb') as fd:
Simon Glass24d0d3c2018-07-17 13:25:47 -06001644 fd.write(VBLOCK_DATA)
1645 return command.CommandResult()
1646
1647 def testVblock(self):
1648 """Test for the Chromium OS Verified Boot Block"""
1649 command.test_result = self._HandleVblockCommand
1650 entry_args = {
1651 'keydir': 'devkeys',
1652 }
Simon Glass741f2d62018-10-01 12:22:30 -06001653 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass24d0d3c2018-07-17 13:25:47 -06001654 entry_args=entry_args)
1655 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1656 self.assertEqual(expected, data)
1657
1658 def testVblockNoContent(self):
1659 """Test we detect a vblock which has no content to sign"""
1660 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001661 self._DoReadFile('075_vblock_no_content.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001662 self.assertIn("Node '/binman/vblock': Vblock must have a 'content' "
1663 'property', str(e.exception))
1664
1665 def testVblockBadPhandle(self):
1666 """Test that we detect a vblock with an invalid phandle in contents"""
1667 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001668 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001669 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1670 '1000', str(e.exception))
1671
1672 def testVblockBadEntry(self):
1673 """Test that we detect an entry that points to a non-entry"""
1674 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001675 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001676 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1677 "'other'", str(e.exception))
1678
Simon Glassb8ef5b62018-07-17 13:25:48 -06001679 def testTpl(self):
Simon Glass2090f1e2019-08-24 07:23:00 -06001680 """Test that an image with TPL and its device tree can be created"""
Simon Glassb8ef5b62018-07-17 13:25:48 -06001681 # ELF file with a '__bss_size' symbol
Simon Glass2090f1e2019-08-24 07:23:00 -06001682 self._SetupTplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001683 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glassb8ef5b62018-07-17 13:25:48 -06001684 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1685
Simon Glass15a587c2018-07-17 13:25:51 -06001686 def testUsesPos(self):
1687 """Test that the 'pos' property cannot be used anymore"""
1688 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001689 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass15a587c2018-07-17 13:25:51 -06001690 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1691 "'pos'", str(e.exception))
1692
Simon Glassd178eab2018-09-14 04:57:08 -06001693 def testFillZero(self):
1694 """Test for an fill entry type with a size of 0"""
Simon Glass741f2d62018-10-01 12:22:30 -06001695 data = self._DoReadFile('080_fill_empty.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001696 self.assertEqual(tools.GetBytes(0, 16), data)
Simon Glassd178eab2018-09-14 04:57:08 -06001697
Simon Glass0b489362018-09-14 04:57:09 -06001698 def testTextMissing(self):
1699 """Test for a text entry type where there is no text"""
1700 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001701 self._DoReadFileDtb('066_text.dts',)
Simon Glass0b489362018-09-14 04:57:09 -06001702 self.assertIn("Node '/binman/text': No value provided for text label "
1703 "'test-id'", str(e.exception))
1704
Simon Glass35b384c2018-09-14 04:57:10 -06001705 def testPackStart16Tpl(self):
1706 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001707 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glass35b384c2018-09-14 04:57:10 -06001708 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1709
Simon Glass0bfa7b02018-09-14 04:57:12 -06001710 def testSelectImage(self):
1711 """Test that we can select which images to build"""
Simon Glasseb833d82019-04-25 21:58:34 -06001712 expected = 'Skipping images: image1'
Simon Glass0bfa7b02018-09-14 04:57:12 -06001713
Simon Glasseb833d82019-04-25 21:58:34 -06001714 # We should only get the expected message in verbose mode
Simon Glassee0c9a72019-07-08 13:18:48 -06001715 for verbosity in (0, 2):
Simon Glasseb833d82019-04-25 21:58:34 -06001716 with test_util.capture_sys_output() as (stdout, stderr):
1717 retcode = self._DoTestFile('006_dual_image.dts',
1718 verbosity=verbosity,
1719 images=['image2'])
1720 self.assertEqual(0, retcode)
1721 if verbosity:
1722 self.assertIn(expected, stdout.getvalue())
1723 else:
1724 self.assertNotIn(expected, stdout.getvalue())
1725
1726 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1727 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
Simon Glassf86a7362019-07-20 12:24:10 -06001728 self._CleanupOutputDir()
Simon Glass0bfa7b02018-09-14 04:57:12 -06001729
Simon Glass6ed45ba2018-09-14 04:57:24 -06001730 def testUpdateFdtAll(self):
1731 """Test that all device trees are updated with offset/size info"""
Simon Glass3c081312019-07-08 14:25:26 -06001732 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glass6ed45ba2018-09-14 04:57:24 -06001733
1734 base_expected = {
1735 'section:image-pos': 0,
1736 'u-boot-tpl-dtb:size': 513,
1737 'u-boot-spl-dtb:size': 513,
1738 'u-boot-spl-dtb:offset': 493,
1739 'image-pos': 0,
1740 'section/u-boot-dtb:image-pos': 0,
1741 'u-boot-spl-dtb:image-pos': 493,
1742 'section/u-boot-dtb:size': 493,
1743 'u-boot-tpl-dtb:image-pos': 1006,
1744 'section/u-boot-dtb:offset': 0,
1745 'section:size': 493,
1746 'offset': 0,
1747 'section:offset': 0,
1748 'u-boot-tpl-dtb:offset': 1006,
1749 'size': 1519
1750 }
1751
1752 # We expect three device-tree files in the output, one after the other.
1753 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1754 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1755 # main U-Boot tree. All three should have the same postions and offset.
1756 start = 0
1757 for item in ['', 'spl', 'tpl']:
1758 dtb = fdt.Fdt.FromData(data[start:])
1759 dtb.Scan()
Simon Glass12bb1a92019-07-20 12:23:51 -06001760 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
1761 ['spl', 'tpl'])
Simon Glass6ed45ba2018-09-14 04:57:24 -06001762 expected = dict(base_expected)
1763 if item:
1764 expected[item] = 0
1765 self.assertEqual(expected, props)
1766 start += dtb._fdt_obj.totalsize()
1767
1768 def testUpdateFdtOutput(self):
1769 """Test that output DTB files are updated"""
1770 try:
Simon Glass741f2d62018-10-01 12:22:30 -06001771 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glass6ed45ba2018-09-14 04:57:24 -06001772 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1773
1774 # Unfortunately, compiling a source file always results in a file
1775 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass741f2d62018-10-01 12:22:30 -06001776 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glass6ed45ba2018-09-14 04:57:24 -06001777 # binman as a file called u-boot.dtb. To fix this, copy the file
1778 # over to the expected place.
Simon Glass6ed45ba2018-09-14 04:57:24 -06001779 start = 0
1780 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1781 'tpl/u-boot-tpl.dtb.out']:
1782 dtb = fdt.Fdt.FromData(data[start:])
1783 size = dtb._fdt_obj.totalsize()
1784 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1785 outdata = tools.ReadFile(pathname)
1786 name = os.path.split(fname)[0]
1787
1788 if name:
1789 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1790 else:
1791 orig_indata = dtb_data
1792 self.assertNotEqual(outdata, orig_indata,
1793 "Expected output file '%s' be updated" % pathname)
1794 self.assertEqual(outdata, data[start:start + size],
1795 "Expected output file '%s' to match output image" %
1796 pathname)
1797 start += size
1798 finally:
1799 self._ResetDtbs()
1800
Simon Glass83d73c22018-09-14 04:57:26 -06001801 def _decompress(self, data):
Simon Glassff5c7e32019-07-08 13:18:42 -06001802 return tools.Decompress(data, 'lz4')
Simon Glass83d73c22018-09-14 04:57:26 -06001803
1804 def testCompress(self):
1805 """Test compression of blobs"""
Simon Glassac62fba2019-07-08 13:18:53 -06001806 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06001807 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass83d73c22018-09-14 04:57:26 -06001808 use_real_dtb=True, update_dtb=True)
1809 dtb = fdt.Fdt(out_dtb_fname)
1810 dtb.Scan()
1811 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1812 orig = self._decompress(data)
1813 self.assertEquals(COMPRESS_DATA, orig)
1814 expected = {
1815 'blob:uncomp-size': len(COMPRESS_DATA),
1816 'blob:size': len(data),
1817 'size': len(data),
1818 }
1819 self.assertEqual(expected, props)
1820
Simon Glass0a98b282018-09-14 04:57:28 -06001821 def testFiles(self):
1822 """Test bringing in multiple files"""
Simon Glass741f2d62018-10-01 12:22:30 -06001823 data = self._DoReadFile('084_files.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001824 self.assertEqual(FILES_DATA, data)
1825
1826 def testFilesCompress(self):
1827 """Test bringing in multiple files and compressing them"""
Simon Glassac62fba2019-07-08 13:18:53 -06001828 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06001829 data = self._DoReadFile('085_files_compress.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001830
1831 image = control.images['image']
1832 entries = image.GetEntries()
1833 files = entries['files']
Simon Glass8beb11e2019-07-08 14:25:47 -06001834 entries = files._entries
Simon Glass0a98b282018-09-14 04:57:28 -06001835
Simon Glassc6c10e72019-05-17 22:00:46 -06001836 orig = b''
Simon Glass0a98b282018-09-14 04:57:28 -06001837 for i in range(1, 3):
1838 key = '%d.dat' % i
1839 start = entries[key].image_pos
1840 len = entries[key].size
1841 chunk = data[start:start + len]
1842 orig += self._decompress(chunk)
1843
1844 self.assertEqual(FILES_DATA, orig)
1845
1846 def testFilesMissing(self):
1847 """Test missing files"""
1848 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001849 data = self._DoReadFile('086_files_none.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001850 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1851 'no files', str(e.exception))
1852
1853 def testFilesNoPattern(self):
1854 """Test missing files"""
1855 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001856 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001857 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1858 str(e.exception))
1859
Simon Glassba64a0b2018-09-14 04:57:29 -06001860 def testExpandSize(self):
1861 """Test an expanding entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001862 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
Simon Glassba64a0b2018-09-14 04:57:29 -06001863 map=True)
Simon Glassc6c10e72019-05-17 22:00:46 -06001864 expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA +
1865 MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA +
1866 tools.GetBytes(ord('c'), 8) + U_BOOT_DATA +
1867 tools.GetBytes(ord('d'), 8))
Simon Glassba64a0b2018-09-14 04:57:29 -06001868 self.assertEqual(expect, data)
1869 self.assertEqual('''ImagePos Offset Size Name
187000000000 00000000 00000028 main-section
187100000000 00000000 00000008 fill
187200000008 00000008 00000004 u-boot
18730000000c 0000000c 00000004 section
18740000000c 00000000 00000003 intel-mrc
187500000010 00000010 00000004 u-boot2
187600000014 00000014 0000000c section2
187700000014 00000000 00000008 fill
18780000001c 00000008 00000004 u-boot
187900000020 00000020 00000008 fill2
1880''', map_data)
1881
1882 def testExpandSizeBad(self):
1883 """Test an expanding entry which fails to provide contents"""
Simon Glass163ed6c2018-09-14 04:57:36 -06001884 with test_util.capture_sys_output() as (stdout, stderr):
1885 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001886 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
Simon Glassba64a0b2018-09-14 04:57:29 -06001887 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
1888 'expanding entry', str(e.exception))
1889
Simon Glasse0e5df92018-09-14 04:57:31 -06001890 def testHash(self):
1891 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001892 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06001893 use_real_dtb=True, update_dtb=True)
1894 dtb = fdt.Fdt(out_dtb_fname)
1895 dtb.Scan()
1896 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
1897 m = hashlib.sha256()
1898 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001899 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06001900
1901 def testHashNoAlgo(self):
1902 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001903 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06001904 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
1905 'hash node', str(e.exception))
1906
1907 def testHashBadAlgo(self):
1908 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001909 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06001910 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
1911 str(e.exception))
1912
1913 def testHashSection(self):
1914 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001915 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06001916 use_real_dtb=True, update_dtb=True)
1917 dtb = fdt.Fdt(out_dtb_fname)
1918 dtb.Scan()
1919 hash_node = dtb.GetNode('/binman/section/hash').props['value']
1920 m = hashlib.sha256()
1921 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001922 m.update(tools.GetBytes(ord('a'), 16))
1923 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06001924
Simon Glassf0253632018-09-14 04:57:32 -06001925 def testPackUBootTplMicrocode(self):
1926 """Test that x86 microcode can be handled correctly in TPL
1927
1928 We expect to see the following in the image, in order:
1929 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
1930 place
1931 u-boot-tpl.dtb with the microcode removed
1932 the microcode
1933 """
Simon Glass2090f1e2019-08-24 07:23:00 -06001934 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass741f2d62018-10-01 12:22:30 -06001935 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glassf0253632018-09-14 04:57:32 -06001936 U_BOOT_TPL_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001937 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
1938 b'ter somewhere in here', first)
Simon Glassf0253632018-09-14 04:57:32 -06001939
Simon Glassf8f8df62018-09-14 04:57:34 -06001940 def testFmapX86(self):
1941 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001942 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassf8f8df62018-09-14 04:57:34 -06001943 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc6c10e72019-05-17 22:00:46 -06001944 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06001945 self.assertEqual(expected, data[:32])
1946 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1947
1948 self.assertEqual(0x100, fhdr.image_size)
1949
1950 self.assertEqual(0, fentries[0].offset)
1951 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001952 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001953
1954 self.assertEqual(4, fentries[1].offset)
1955 self.assertEqual(3, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001956 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001957
1958 self.assertEqual(32, fentries[2].offset)
1959 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1960 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001961 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001962
1963 def testFmapX86Section(self):
1964 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001965 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glassc6c10e72019-05-17 22:00:46 -06001966 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06001967 self.assertEqual(expected, data[:32])
1968 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
1969
1970 self.assertEqual(0x100, fhdr.image_size)
1971
1972 self.assertEqual(0, fentries[0].offset)
1973 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001974 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001975
1976 self.assertEqual(4, fentries[1].offset)
1977 self.assertEqual(3, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001978 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001979
1980 self.assertEqual(36, fentries[2].offset)
1981 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1982 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001983 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001984
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001985 def testElf(self):
1986 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001987 self._SetupSplElf()
Simon Glass2090f1e2019-08-24 07:23:00 -06001988 self._SetupTplElf()
Simon Glass53e22bf2019-08-24 07:22:53 -06001989 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001990 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001991 data = self._DoReadFile('096_elf.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001992
Simon Glass093d1682019-07-08 13:18:25 -06001993 def testElfStrip(self):
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001994 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001995 self._SetupSplElf()
Simon Glass53e22bf2019-08-24 07:22:53 -06001996 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001997 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001998 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001999
Simon Glass163ed6c2018-09-14 04:57:36 -06002000 def testPackOverlapMap(self):
2001 """Test that overlapping regions are detected"""
2002 with test_util.capture_sys_output() as (stdout, stderr):
2003 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002004 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glass163ed6c2018-09-14 04:57:36 -06002005 map_fname = tools.GetOutputFilename('image.map')
2006 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2007 stdout.getvalue())
2008
2009 # We should not get an inmage, but there should be a map file
2010 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
2011 self.assertTrue(os.path.exists(map_fname))
Simon Glasseb546ac2019-05-17 22:00:51 -06002012 map_data = tools.ReadFile(map_fname, binary=False)
Simon Glass163ed6c2018-09-14 04:57:36 -06002013 self.assertEqual('''ImagePos Offset Size Name
2014<none> 00000000 00000007 main-section
2015<none> 00000000 00000004 u-boot
2016<none> 00000003 00000004 u-boot-align
2017''', map_data)
2018
Simon Glass093d1682019-07-08 13:18:25 -06002019 def testPackRefCode(self):
Simon Glass3ae192c2018-10-01 12:22:31 -06002020 """Test that an image with an Intel Reference code binary works"""
2021 data = self._DoReadFile('100_intel_refcode.dts')
2022 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2023
Simon Glass9481c802019-04-25 21:58:39 -06002024 def testSectionOffset(self):
2025 """Tests use of a section with an offset"""
2026 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2027 map=True)
2028 self.assertEqual('''ImagePos Offset Size Name
202900000000 00000000 00000038 main-section
203000000004 00000004 00000010 section@0
203100000004 00000000 00000004 u-boot
203200000018 00000018 00000010 section@1
203300000018 00000000 00000004 u-boot
20340000002c 0000002c 00000004 section@2
20350000002c 00000000 00000004 u-boot
2036''', map_data)
2037 self.assertEqual(data,
Simon Glasse6d85ff2019-05-14 15:53:47 -06002038 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2039 tools.GetBytes(0x21, 12) +
2040 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2041 tools.GetBytes(0x61, 12) +
2042 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2043 tools.GetBytes(0x26, 8))
Simon Glass9481c802019-04-25 21:58:39 -06002044
Simon Glassac62fba2019-07-08 13:18:53 -06002045 def testCbfsRaw(self):
2046 """Test base handling of a Coreboot Filesystem (CBFS)
2047
2048 The exact contents of the CBFS is verified by similar tests in
2049 cbfs_util_test.py. The tests here merely check that the files added to
2050 the CBFS can be found in the final image.
2051 """
2052 data = self._DoReadFile('102_cbfs_raw.dts')
2053 size = 0xb0
2054
2055 cbfs = cbfs_util.CbfsReader(data)
2056 self.assertEqual(size, cbfs.rom_size)
2057
2058 self.assertIn('u-boot-dtb', cbfs.files)
2059 cfile = cbfs.files['u-boot-dtb']
2060 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2061
2062 def testCbfsArch(self):
2063 """Test on non-x86 architecture"""
2064 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2065 size = 0x100
2066
2067 cbfs = cbfs_util.CbfsReader(data)
2068 self.assertEqual(size, cbfs.rom_size)
2069
2070 self.assertIn('u-boot-dtb', cbfs.files)
2071 cfile = cbfs.files['u-boot-dtb']
2072 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2073
2074 def testCbfsStage(self):
2075 """Tests handling of a Coreboot Filesystem (CBFS)"""
2076 if not elf.ELF_TOOLS:
2077 self.skipTest('Python elftools not available')
2078 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2079 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2080 size = 0xb0
2081
2082 data = self._DoReadFile('104_cbfs_stage.dts')
2083 cbfs = cbfs_util.CbfsReader(data)
2084 self.assertEqual(size, cbfs.rom_size)
2085
2086 self.assertIn('u-boot', cbfs.files)
2087 cfile = cbfs.files['u-boot']
2088 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2089
2090 def testCbfsRawCompress(self):
2091 """Test handling of compressing raw files"""
2092 self._CheckLz4()
2093 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2094 size = 0x140
2095
2096 cbfs = cbfs_util.CbfsReader(data)
2097 self.assertIn('u-boot', cbfs.files)
2098 cfile = cbfs.files['u-boot']
2099 self.assertEqual(COMPRESS_DATA, cfile.data)
2100
2101 def testCbfsBadArch(self):
2102 """Test handling of a bad architecture"""
2103 with self.assertRaises(ValueError) as e:
2104 self._DoReadFile('106_cbfs_bad_arch.dts')
2105 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2106
2107 def testCbfsNoSize(self):
2108 """Test handling of a missing size property"""
2109 with self.assertRaises(ValueError) as e:
2110 self._DoReadFile('107_cbfs_no_size.dts')
2111 self.assertIn('entry must have a size property', str(e.exception))
2112
2113 def testCbfsNoCOntents(self):
2114 """Test handling of a CBFS entry which does not provide contentsy"""
2115 with self.assertRaises(ValueError) as e:
2116 self._DoReadFile('108_cbfs_no_contents.dts')
2117 self.assertIn('Could not complete processing of contents',
2118 str(e.exception))
2119
2120 def testCbfsBadCompress(self):
2121 """Test handling of a bad architecture"""
2122 with self.assertRaises(ValueError) as e:
2123 self._DoReadFile('109_cbfs_bad_compress.dts')
2124 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2125 str(e.exception))
2126
2127 def testCbfsNamedEntries(self):
2128 """Test handling of named entries"""
2129 data = self._DoReadFile('110_cbfs_name.dts')
2130
2131 cbfs = cbfs_util.CbfsReader(data)
2132 self.assertIn('FRED', cbfs.files)
2133 cfile1 = cbfs.files['FRED']
2134 self.assertEqual(U_BOOT_DATA, cfile1.data)
2135
2136 self.assertIn('hello', cbfs.files)
2137 cfile2 = cbfs.files['hello']
2138 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2139
Simon Glassc5ac1382019-07-08 13:18:54 -06002140 def _SetupIfwi(self, fname):
2141 """Set up to run an IFWI test
2142
2143 Args:
2144 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2145 """
2146 self._SetupSplElf()
Simon Glass2090f1e2019-08-24 07:23:00 -06002147 self._SetupTplElf()
Simon Glassc5ac1382019-07-08 13:18:54 -06002148
2149 # Intel Integrated Firmware Image (IFWI) file
2150 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2151 data = fd.read()
2152 TestFunctional._MakeInputFile(fname,data)
2153
2154 def _CheckIfwi(self, data):
2155 """Check that an image with an IFWI contains the correct output
2156
2157 Args:
2158 data: Conents of output file
2159 """
2160 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
2161 if data[:0x1000] != expected_desc:
2162 self.fail('Expected descriptor binary at start of image')
2163
2164 # We expect to find the TPL wil in subpart IBBP entry IBBL
2165 image_fname = tools.GetOutputFilename('image.bin')
2166 tpl_fname = tools.GetOutputFilename('tpl.out')
2167 tools.RunIfwiTool(image_fname, tools.CMD_EXTRACT, fname=tpl_fname,
2168 subpart='IBBP', entry_name='IBBL')
2169
2170 tpl_data = tools.ReadFile(tpl_fname)
Simon Glasse95be632019-08-24 07:22:51 -06002171 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glassc5ac1382019-07-08 13:18:54 -06002172
2173 def testPackX86RomIfwi(self):
2174 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2175 self._SetupIfwi('fitimage.bin')
Simon Glass9255f3c2019-08-24 07:23:01 -06002176 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002177 self._CheckIfwi(data)
2178
2179 def testPackX86RomIfwiNoDesc(self):
2180 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2181 self._SetupIfwi('ifwi.bin')
Simon Glass9255f3c2019-08-24 07:23:01 -06002182 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002183 self._CheckIfwi(data)
2184
2185 def testPackX86RomIfwiNoData(self):
2186 """Test that an x86 ROM with IFWI handles missing data"""
2187 self._SetupIfwi('ifwi.bin')
2188 with self.assertRaises(ValueError) as e:
Simon Glass9255f3c2019-08-24 07:23:01 -06002189 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002190 self.assertIn('Could not complete processing of contents',
2191 str(e.exception))
Simon Glass53af22a2018-07-17 13:25:32 -06002192
Simon Glasse073d4e2019-07-08 13:18:56 -06002193 def testCbfsOffset(self):
2194 """Test a CBFS with files at particular offsets
2195
2196 Like all CFBS tests, this is just checking the logic that calls
2197 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2198 """
2199 data = self._DoReadFile('114_cbfs_offset.dts')
2200 size = 0x200
2201
2202 cbfs = cbfs_util.CbfsReader(data)
2203 self.assertEqual(size, cbfs.rom_size)
2204
2205 self.assertIn('u-boot', cbfs.files)
2206 cfile = cbfs.files['u-boot']
2207 self.assertEqual(U_BOOT_DATA, cfile.data)
2208 self.assertEqual(0x40, cfile.cbfs_offset)
2209
2210 self.assertIn('u-boot-dtb', cbfs.files)
2211 cfile2 = cbfs.files['u-boot-dtb']
2212 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2213 self.assertEqual(0x140, cfile2.cbfs_offset)
2214
Simon Glass086cec92019-07-08 14:25:27 -06002215 def testFdtmap(self):
2216 """Test an FDT map can be inserted in the image"""
2217 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2218 fdtmap_data = data[len(U_BOOT_DATA):]
2219 magic = fdtmap_data[:8]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002220 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass086cec92019-07-08 14:25:27 -06002221 self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
2222
2223 fdt_data = fdtmap_data[16:]
2224 dtb = fdt.Fdt.FromData(fdt_data)
2225 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002226 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass086cec92019-07-08 14:25:27 -06002227 self.assertEqual({
2228 'image-pos': 0,
2229 'offset': 0,
2230 'u-boot:offset': 0,
2231 'u-boot:size': len(U_BOOT_DATA),
2232 'u-boot:image-pos': 0,
2233 'fdtmap:image-pos': 4,
2234 'fdtmap:offset': 4,
2235 'fdtmap:size': len(fdtmap_data),
2236 'size': len(data),
2237 }, props)
2238
2239 def testFdtmapNoMatch(self):
2240 """Check handling of an FDT map when the section cannot be found"""
2241 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2242
2243 # Mangle the section name, which should cause a mismatch between the
2244 # correct FDT path and the one expected by the section
2245 image = control.images['image']
Simon Glasscf228942019-07-08 14:25:28 -06002246 image._node.path += '-suffix'
Simon Glass086cec92019-07-08 14:25:27 -06002247 entries = image.GetEntries()
2248 fdtmap = entries['fdtmap']
2249 with self.assertRaises(ValueError) as e:
2250 fdtmap._GetFdtmap()
2251 self.assertIn("Cannot locate node for path '/binman-suffix'",
2252 str(e.exception))
2253
Simon Glasscf228942019-07-08 14:25:28 -06002254 def testFdtmapHeader(self):
2255 """Test an FDT map and image header can be inserted in the image"""
2256 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2257 fdtmap_pos = len(U_BOOT_DATA)
2258 fdtmap_data = data[fdtmap_pos:]
2259 fdt_data = fdtmap_data[16:]
2260 dtb = fdt.Fdt.FromData(fdt_data)
2261 fdt_size = dtb.GetFdtObj().totalsize()
2262 hdr_data = data[-8:]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002263 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002264 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2265 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2266
2267 def testFdtmapHeaderStart(self):
2268 """Test an image header can be inserted at the image start"""
2269 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2270 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2271 hdr_data = data[:8]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002272 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002273 offset = struct.unpack('<I', hdr_data[4:])[0]
2274 self.assertEqual(fdtmap_pos, offset)
2275
2276 def testFdtmapHeaderPos(self):
2277 """Test an image header can be inserted at a chosen position"""
2278 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2279 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2280 hdr_data = data[0x80:0x88]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002281 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002282 offset = struct.unpack('<I', hdr_data[4:])[0]
2283 self.assertEqual(fdtmap_pos, offset)
2284
2285 def testHeaderMissingFdtmap(self):
2286 """Test an image header requires an fdtmap"""
2287 with self.assertRaises(ValueError) as e:
2288 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2289 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2290 str(e.exception))
2291
2292 def testHeaderNoLocation(self):
2293 """Test an image header with a no specified location is detected"""
2294 with self.assertRaises(ValueError) as e:
2295 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2296 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2297 str(e.exception))
2298
Simon Glassc52c9e72019-07-08 14:25:37 -06002299 def testEntryExpand(self):
2300 """Test expanding an entry after it is packed"""
2301 data = self._DoReadFile('121_entry_expand.dts')
Simon Glass79d3c582019-07-20 12:23:57 -06002302 self.assertEqual(b'aaa', data[:3])
2303 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2304 self.assertEqual(b'aaa', data[-3:])
Simon Glassc52c9e72019-07-08 14:25:37 -06002305
2306 def testEntryExpandBad(self):
2307 """Test expanding an entry after it is packed, twice"""
2308 with self.assertRaises(ValueError) as e:
2309 self._DoReadFile('122_entry_expand_twice.dts')
Simon Glass61ec04f2019-07-20 12:23:58 -06002310 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glassc52c9e72019-07-08 14:25:37 -06002311 str(e.exception))
2312
2313 def testEntryExpandSection(self):
2314 """Test expanding an entry within a section after it is packed"""
2315 data = self._DoReadFile('123_entry_expand_section.dts')
Simon Glass79d3c582019-07-20 12:23:57 -06002316 self.assertEqual(b'aaa', data[:3])
2317 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2318 self.assertEqual(b'aaa', data[-3:])
Simon Glassc52c9e72019-07-08 14:25:37 -06002319
Simon Glass6c223fd2019-07-08 14:25:38 -06002320 def testCompressDtb(self):
2321 """Test that compress of device-tree files is supported"""
2322 self._CheckLz4()
2323 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2324 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2325 comp_data = data[len(U_BOOT_DATA):]
2326 orig = self._decompress(comp_data)
2327 dtb = fdt.Fdt.FromData(orig)
2328 dtb.Scan()
2329 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2330 expected = {
2331 'u-boot:size': len(U_BOOT_DATA),
2332 'u-boot-dtb:uncomp-size': len(orig),
2333 'u-boot-dtb:size': len(comp_data),
2334 'size': len(data),
2335 }
2336 self.assertEqual(expected, props)
2337
Simon Glass69f7cb32019-07-08 14:25:41 -06002338 def testCbfsUpdateFdt(self):
2339 """Test that we can update the device tree with CBFS offset/size info"""
2340 self._CheckLz4()
2341 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2342 update_dtb=True)
2343 dtb = fdt.Fdt(out_dtb_fname)
2344 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002345 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass69f7cb32019-07-08 14:25:41 -06002346 del props['cbfs/u-boot:size']
2347 self.assertEqual({
2348 'offset': 0,
2349 'size': len(data),
2350 'image-pos': 0,
2351 'cbfs:offset': 0,
2352 'cbfs:size': len(data),
2353 'cbfs:image-pos': 0,
2354 'cbfs/u-boot:offset': 0x38,
2355 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2356 'cbfs/u-boot:image-pos': 0x38,
2357 'cbfs/u-boot-dtb:offset': 0xb8,
2358 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2359 'cbfs/u-boot-dtb:image-pos': 0xb8,
2360 }, props)
2361
Simon Glass8a1ad062019-07-08 14:25:42 -06002362 def testCbfsBadType(self):
2363 """Test an image header with a no specified location is detected"""
2364 with self.assertRaises(ValueError) as e:
2365 self._DoReadFile('126_cbfs_bad_type.dts')
2366 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2367
Simon Glass41b8ba02019-07-08 14:25:43 -06002368 def testList(self):
2369 """Test listing the files in an image"""
2370 self._CheckLz4()
2371 data = self._DoReadFile('127_list.dts')
2372 image = control.images['image']
2373 entries = image.BuildEntryList()
2374 self.assertEqual(7, len(entries))
2375
2376 ent = entries[0]
2377 self.assertEqual(0, ent.indent)
2378 self.assertEqual('main-section', ent.name)
2379 self.assertEqual('section', ent.etype)
2380 self.assertEqual(len(data), ent.size)
2381 self.assertEqual(0, ent.image_pos)
2382 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002383 self.assertEqual(0, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002384
2385 ent = entries[1]
2386 self.assertEqual(1, ent.indent)
2387 self.assertEqual('u-boot', ent.name)
2388 self.assertEqual('u-boot', ent.etype)
2389 self.assertEqual(len(U_BOOT_DATA), ent.size)
2390 self.assertEqual(0, ent.image_pos)
2391 self.assertEqual(None, ent.uncomp_size)
2392 self.assertEqual(0, ent.offset)
2393
2394 ent = entries[2]
2395 self.assertEqual(1, ent.indent)
2396 self.assertEqual('section', ent.name)
2397 self.assertEqual('section', ent.etype)
2398 section_size = ent.size
2399 self.assertEqual(0x100, ent.image_pos)
2400 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002401 self.assertEqual(0x100, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002402
2403 ent = entries[3]
2404 self.assertEqual(2, ent.indent)
2405 self.assertEqual('cbfs', ent.name)
2406 self.assertEqual('cbfs', ent.etype)
2407 self.assertEqual(0x400, ent.size)
2408 self.assertEqual(0x100, ent.image_pos)
2409 self.assertEqual(None, ent.uncomp_size)
2410 self.assertEqual(0, ent.offset)
2411
2412 ent = entries[4]
2413 self.assertEqual(3, ent.indent)
2414 self.assertEqual('u-boot', ent.name)
2415 self.assertEqual('u-boot', ent.etype)
2416 self.assertEqual(len(U_BOOT_DATA), ent.size)
2417 self.assertEqual(0x138, ent.image_pos)
2418 self.assertEqual(None, ent.uncomp_size)
2419 self.assertEqual(0x38, ent.offset)
2420
2421 ent = entries[5]
2422 self.assertEqual(3, ent.indent)
2423 self.assertEqual('u-boot-dtb', ent.name)
2424 self.assertEqual('text', ent.etype)
2425 self.assertGreater(len(COMPRESS_DATA), ent.size)
2426 self.assertEqual(0x178, ent.image_pos)
2427 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2428 self.assertEqual(0x78, ent.offset)
2429
2430 ent = entries[6]
2431 self.assertEqual(2, ent.indent)
2432 self.assertEqual('u-boot-dtb', ent.name)
2433 self.assertEqual('u-boot-dtb', ent.etype)
2434 self.assertEqual(0x500, ent.image_pos)
2435 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2436 dtb_size = ent.size
2437 # Compressing this data expands it since headers are added
2438 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2439 self.assertEqual(0x400, ent.offset)
2440
2441 self.assertEqual(len(data), 0x100 + section_size)
2442 self.assertEqual(section_size, 0x400 + dtb_size)
2443
Simon Glasse1925fa2019-07-08 14:25:44 -06002444 def testFindFdtmap(self):
2445 """Test locating an FDT map in an image"""
2446 self._CheckLz4()
2447 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2448 image = control.images['image']
2449 entries = image.GetEntries()
2450 entry = entries['fdtmap']
2451 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2452
2453 def testFindFdtmapMissing(self):
2454 """Test failing to locate an FDP map"""
2455 data = self._DoReadFile('005_simple.dts')
2456 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2457
Simon Glass2d260032019-07-08 14:25:45 -06002458 def testFindImageHeader(self):
2459 """Test locating a image header"""
2460 self._CheckLz4()
Simon Glassffded752019-07-08 14:25:46 -06002461 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002462 image = control.images['image']
2463 entries = image.GetEntries()
2464 entry = entries['fdtmap']
2465 # The header should point to the FDT map
2466 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2467
2468 def testFindImageHeaderStart(self):
2469 """Test locating a image header located at the start of an image"""
Simon Glassffded752019-07-08 14:25:46 -06002470 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002471 image = control.images['image']
2472 entries = image.GetEntries()
2473 entry = entries['fdtmap']
2474 # The header should point to the FDT map
2475 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2476
2477 def testFindImageHeaderMissing(self):
2478 """Test failing to locate an image header"""
2479 data = self._DoReadFile('005_simple.dts')
2480 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2481
Simon Glassffded752019-07-08 14:25:46 -06002482 def testReadImage(self):
2483 """Test reading an image and accessing its FDT map"""
2484 self._CheckLz4()
2485 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2486 image_fname = tools.GetOutputFilename('image.bin')
2487 orig_image = control.images['image']
2488 image = Image.FromFile(image_fname)
2489 self.assertEqual(orig_image.GetEntries().keys(),
2490 image.GetEntries().keys())
2491
2492 orig_entry = orig_image.GetEntries()['fdtmap']
2493 entry = image.GetEntries()['fdtmap']
2494 self.assertEquals(orig_entry.offset, entry.offset)
2495 self.assertEquals(orig_entry.size, entry.size)
2496 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2497
2498 def testReadImageNoHeader(self):
2499 """Test accessing an image's FDT map without an image header"""
2500 self._CheckLz4()
2501 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
2502 image_fname = tools.GetOutputFilename('image.bin')
2503 image = Image.FromFile(image_fname)
2504 self.assertTrue(isinstance(image, Image))
Simon Glass10f9d002019-07-20 12:23:50 -06002505 self.assertEqual('image', image.image_name[-5:])
Simon Glassffded752019-07-08 14:25:46 -06002506
2507 def testReadImageFail(self):
2508 """Test failing to read an image image's FDT map"""
2509 self._DoReadFile('005_simple.dts')
2510 image_fname = tools.GetOutputFilename('image.bin')
2511 with self.assertRaises(ValueError) as e:
2512 image = Image.FromFile(image_fname)
2513 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glasse073d4e2019-07-08 13:18:56 -06002514
Simon Glass61f564d2019-07-08 14:25:48 -06002515 def testListCmd(self):
2516 """Test listing the files in an image using an Fdtmap"""
2517 self._CheckLz4()
2518 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2519
2520 # lz4 compression size differs depending on the version
2521 image = control.images['image']
2522 entries = image.GetEntries()
2523 section_size = entries['section'].size
2524 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2525 fdtmap_offset = entries['fdtmap'].offset
2526
Simon Glassf86a7362019-07-20 12:24:10 -06002527 try:
2528 tmpdir, updated_fname = self._SetupImageInTmpdir()
2529 with test_util.capture_sys_output() as (stdout, stderr):
2530 self._DoBinman('ls', '-i', updated_fname)
2531 finally:
2532 shutil.rmtree(tmpdir)
Simon Glass61f564d2019-07-08 14:25:48 -06002533 lines = stdout.getvalue().splitlines()
2534 expected = [
2535'Name Image-pos Size Entry-type Offset Uncomp-size',
2536'----------------------------------------------------------------------',
2537'main-section 0 c00 section 0',
2538' u-boot 0 4 u-boot 0',
2539' section 100 %x section 100' % section_size,
2540' cbfs 100 400 cbfs 0',
2541' u-boot 138 4 u-boot 38',
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002542' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glass61f564d2019-07-08 14:25:48 -06002543' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002544' fdtmap %x 3bd fdtmap %x' %
Simon Glass61f564d2019-07-08 14:25:48 -06002545 (fdtmap_offset, fdtmap_offset),
2546' image-header bf8 8 image-header bf8',
2547 ]
2548 self.assertEqual(expected, lines)
2549
2550 def testListCmdFail(self):
2551 """Test failing to list an image"""
2552 self._DoReadFile('005_simple.dts')
Simon Glassf86a7362019-07-20 12:24:10 -06002553 try:
2554 tmpdir, updated_fname = self._SetupImageInTmpdir()
2555 with self.assertRaises(ValueError) as e:
2556 self._DoBinman('ls', '-i', updated_fname)
2557 finally:
2558 shutil.rmtree(tmpdir)
Simon Glass61f564d2019-07-08 14:25:48 -06002559 self.assertIn("Cannot find FDT map in image", str(e.exception))
2560
2561 def _RunListCmd(self, paths, expected):
2562 """List out entries and check the result
2563
2564 Args:
2565 paths: List of paths to pass to the list command
2566 expected: Expected list of filenames to be returned, in order
2567 """
2568 self._CheckLz4()
2569 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2570 image_fname = tools.GetOutputFilename('image.bin')
2571 image = Image.FromFile(image_fname)
2572 lines = image.GetListEntries(paths)[1]
2573 files = [line[0].strip() for line in lines[1:]]
2574 self.assertEqual(expected, files)
2575
2576 def testListCmdSection(self):
2577 """Test listing the files in a section"""
2578 self._RunListCmd(['section'],
2579 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2580
2581 def testListCmdFile(self):
2582 """Test listing a particular file"""
2583 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2584
2585 def testListCmdWildcard(self):
2586 """Test listing a wildcarded file"""
2587 self._RunListCmd(['*boot*'],
2588 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2589
2590 def testListCmdWildcardMulti(self):
2591 """Test listing a wildcarded file"""
2592 self._RunListCmd(['*cb*', '*head*'],
2593 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2594
2595 def testListCmdEmpty(self):
2596 """Test listing a wildcarded file"""
2597 self._RunListCmd(['nothing'], [])
2598
2599 def testListCmdPath(self):
2600 """Test listing the files in a sub-entry of a section"""
2601 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2602
Simon Glassf667e452019-07-08 14:25:50 -06002603 def _RunExtractCmd(self, entry_name, decomp=True):
2604 """Extract an entry from an image
2605
2606 Args:
2607 entry_name: Entry name to extract
2608 decomp: True to decompress the data if compressed, False to leave
2609 it in its raw uncompressed format
2610
2611 Returns:
2612 data from entry
2613 """
2614 self._CheckLz4()
2615 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2616 image_fname = tools.GetOutputFilename('image.bin')
2617 return control.ReadEntry(image_fname, entry_name, decomp)
2618
2619 def testExtractSimple(self):
2620 """Test extracting a single file"""
2621 data = self._RunExtractCmd('u-boot')
2622 self.assertEqual(U_BOOT_DATA, data)
2623
Simon Glass71ce0ba2019-07-08 14:25:52 -06002624 def testExtractSection(self):
2625 """Test extracting the files in a section"""
2626 data = self._RunExtractCmd('section')
2627 cbfs_data = data[:0x400]
2628 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002629 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass71ce0ba2019-07-08 14:25:52 -06002630 dtb_data = data[0x400:]
2631 dtb = self._decompress(dtb_data)
2632 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2633
2634 def testExtractCompressed(self):
2635 """Test extracting compressed data"""
2636 data = self._RunExtractCmd('section/u-boot-dtb')
2637 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2638
2639 def testExtractRaw(self):
2640 """Test extracting compressed data without decompressing it"""
2641 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2642 dtb = self._decompress(data)
2643 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2644
2645 def testExtractCbfs(self):
2646 """Test extracting CBFS data"""
2647 data = self._RunExtractCmd('section/cbfs/u-boot')
2648 self.assertEqual(U_BOOT_DATA, data)
2649
2650 def testExtractCbfsCompressed(self):
2651 """Test extracting CBFS compressed data"""
2652 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2653 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2654
2655 def testExtractCbfsRaw(self):
2656 """Test extracting CBFS compressed data without decompressing it"""
2657 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Simon Glasseb0f4a42019-07-20 12:24:06 -06002658 dtb = tools.Decompress(data, 'lzma', with_header=False)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002659 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2660
Simon Glassf667e452019-07-08 14:25:50 -06002661 def testExtractBadEntry(self):
2662 """Test extracting a bad section path"""
2663 with self.assertRaises(ValueError) as e:
2664 self._RunExtractCmd('section/does-not-exist')
2665 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2666 str(e.exception))
2667
2668 def testExtractMissingFile(self):
2669 """Test extracting file that does not exist"""
2670 with self.assertRaises(IOError) as e:
2671 control.ReadEntry('missing-file', 'name')
2672
2673 def testExtractBadFile(self):
2674 """Test extracting an invalid file"""
2675 fname = os.path.join(self._indir, 'badfile')
2676 tools.WriteFile(fname, b'')
2677 with self.assertRaises(ValueError) as e:
2678 control.ReadEntry(fname, 'name')
2679
Simon Glass71ce0ba2019-07-08 14:25:52 -06002680 def testExtractCmd(self):
2681 """Test extracting a file fron an image on the command line"""
2682 self._CheckLz4()
2683 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass71ce0ba2019-07-08 14:25:52 -06002684 fname = os.path.join(self._indir, 'output.extact')
Simon Glassf86a7362019-07-20 12:24:10 -06002685 try:
2686 tmpdir, updated_fname = self._SetupImageInTmpdir()
2687 with test_util.capture_sys_output() as (stdout, stderr):
2688 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2689 '-f', fname)
2690 finally:
2691 shutil.rmtree(tmpdir)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002692 data = tools.ReadFile(fname)
2693 self.assertEqual(U_BOOT_DATA, data)
2694
2695 def testExtractOneEntry(self):
2696 """Test extracting a single entry fron an image """
2697 self._CheckLz4()
2698 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2699 image_fname = tools.GetOutputFilename('image.bin')
2700 fname = os.path.join(self._indir, 'output.extact')
2701 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
2702 data = tools.ReadFile(fname)
2703 self.assertEqual(U_BOOT_DATA, data)
2704
2705 def _CheckExtractOutput(self, decomp):
2706 """Helper to test file output with and without decompression
2707
2708 Args:
2709 decomp: True to decompress entry data, False to output it raw
2710 """
2711 def _CheckPresent(entry_path, expect_data, expect_size=None):
2712 """Check and remove expected file
2713
2714 This checks the data/size of a file and removes the file both from
2715 the outfiles set and from the output directory. Once all files are
2716 processed, both the set and directory should be empty.
2717
2718 Args:
2719 entry_path: Entry path
2720 expect_data: Data to expect in file, or None to skip check
2721 expect_size: Size of data to expect in file, or None to skip
2722 """
2723 path = os.path.join(outdir, entry_path)
2724 data = tools.ReadFile(path)
2725 os.remove(path)
2726 if expect_data:
2727 self.assertEqual(expect_data, data)
2728 elif expect_size:
2729 self.assertEqual(expect_size, len(data))
2730 outfiles.remove(path)
2731
2732 def _CheckDirPresent(name):
2733 """Remove expected directory
2734
2735 This gives an error if the directory does not exist as expected
2736
2737 Args:
2738 name: Name of directory to remove
2739 """
2740 path = os.path.join(outdir, name)
2741 os.rmdir(path)
2742
2743 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2744 image_fname = tools.GetOutputFilename('image.bin')
2745 outdir = os.path.join(self._indir, 'extract')
2746 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2747
2748 # Create a set of all file that were output (should be 9)
2749 outfiles = set()
2750 for root, dirs, files in os.walk(outdir):
2751 outfiles |= set([os.path.join(root, fname) for fname in files])
2752 self.assertEqual(9, len(outfiles))
2753 self.assertEqual(9, len(einfos))
2754
2755 image = control.images['image']
2756 entries = image.GetEntries()
2757
2758 # Check the 9 files in various ways
2759 section = entries['section']
2760 section_entries = section.GetEntries()
2761 cbfs_entries = section_entries['cbfs'].GetEntries()
2762 _CheckPresent('u-boot', U_BOOT_DATA)
2763 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
2764 dtb_len = EXTRACT_DTB_SIZE
2765 if not decomp:
2766 dtb_len = cbfs_entries['u-boot-dtb'].size
2767 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
2768 if not decomp:
2769 dtb_len = section_entries['u-boot-dtb'].size
2770 _CheckPresent('section/u-boot-dtb', None, dtb_len)
2771
2772 fdtmap = entries['fdtmap']
2773 _CheckPresent('fdtmap', fdtmap.data)
2774 hdr = entries['image-header']
2775 _CheckPresent('image-header', hdr.data)
2776
2777 _CheckPresent('section/root', section.data)
2778 cbfs = section_entries['cbfs']
2779 _CheckPresent('section/cbfs/root', cbfs.data)
2780 data = tools.ReadFile(image_fname)
2781 _CheckPresent('root', data)
2782
2783 # There should be no files left. Remove all the directories to check.
2784 # If there are any files/dirs remaining, one of these checks will fail.
2785 self.assertEqual(0, len(outfiles))
2786 _CheckDirPresent('section/cbfs')
2787 _CheckDirPresent('section')
2788 _CheckDirPresent('')
2789 self.assertFalse(os.path.exists(outdir))
2790
2791 def testExtractAllEntries(self):
2792 """Test extracting all entries"""
2793 self._CheckLz4()
2794 self._CheckExtractOutput(decomp=True)
2795
2796 def testExtractAllEntriesRaw(self):
2797 """Test extracting all entries without decompressing them"""
2798 self._CheckLz4()
2799 self._CheckExtractOutput(decomp=False)
2800
2801 def testExtractSelectedEntries(self):
2802 """Test extracting some entries"""
2803 self._CheckLz4()
2804 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2805 image_fname = tools.GetOutputFilename('image.bin')
2806 outdir = os.path.join(self._indir, 'extract')
2807 einfos = control.ExtractEntries(image_fname, None, outdir,
2808 ['*cb*', '*head*'])
2809
2810 # File output is tested by testExtractAllEntries(), so just check that
2811 # the expected entries are selected
2812 names = [einfo.name for einfo in einfos]
2813 self.assertEqual(names,
2814 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2815
2816 def testExtractNoEntryPaths(self):
2817 """Test extracting some entries"""
2818 self._CheckLz4()
2819 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2820 image_fname = tools.GetOutputFilename('image.bin')
2821 with self.assertRaises(ValueError) as e:
2822 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassbb5edc12019-07-20 12:24:14 -06002823 self.assertIn('Must specify an entry path to write with -f',
Simon Glass71ce0ba2019-07-08 14:25:52 -06002824 str(e.exception))
2825
2826 def testExtractTooManyEntryPaths(self):
2827 """Test extracting some entries"""
2828 self._CheckLz4()
2829 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2830 image_fname = tools.GetOutputFilename('image.bin')
2831 with self.assertRaises(ValueError) as e:
2832 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassbb5edc12019-07-20 12:24:14 -06002833 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass71ce0ba2019-07-08 14:25:52 -06002834 str(e.exception))
2835
Simon Glasse2705fa2019-07-08 14:25:53 -06002836 def testPackAlignSection(self):
2837 """Test that sections can have alignment"""
2838 self._DoReadFile('131_pack_align_section.dts')
2839
2840 self.assertIn('image', control.images)
2841 image = control.images['image']
2842 entries = image.GetEntries()
2843 self.assertEqual(3, len(entries))
2844
2845 # First u-boot
2846 self.assertIn('u-boot', entries)
2847 entry = entries['u-boot']
2848 self.assertEqual(0, entry.offset)
2849 self.assertEqual(0, entry.image_pos)
2850 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2851 self.assertEqual(len(U_BOOT_DATA), entry.size)
2852
2853 # Section0
2854 self.assertIn('section0', entries)
2855 section0 = entries['section0']
2856 self.assertEqual(0x10, section0.offset)
2857 self.assertEqual(0x10, section0.image_pos)
2858 self.assertEqual(len(U_BOOT_DATA), section0.size)
2859
2860 # Second u-boot
2861 section_entries = section0.GetEntries()
2862 self.assertIn('u-boot', section_entries)
2863 entry = section_entries['u-boot']
2864 self.assertEqual(0, entry.offset)
2865 self.assertEqual(0x10, entry.image_pos)
2866 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2867 self.assertEqual(len(U_BOOT_DATA), entry.size)
2868
2869 # Section1
2870 self.assertIn('section1', entries)
2871 section1 = entries['section1']
2872 self.assertEqual(0x14, section1.offset)
2873 self.assertEqual(0x14, section1.image_pos)
2874 self.assertEqual(0x20, section1.size)
2875
2876 # Second u-boot
2877 section_entries = section1.GetEntries()
2878 self.assertIn('u-boot', section_entries)
2879 entry = section_entries['u-boot']
2880 self.assertEqual(0, entry.offset)
2881 self.assertEqual(0x14, entry.image_pos)
2882 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2883 self.assertEqual(len(U_BOOT_DATA), entry.size)
2884
2885 # Section2
2886 self.assertIn('section2', section_entries)
2887 section2 = section_entries['section2']
2888 self.assertEqual(0x4, section2.offset)
2889 self.assertEqual(0x18, section2.image_pos)
2890 self.assertEqual(4, section2.size)
2891
2892 # Third u-boot
2893 section_entries = section2.GetEntries()
2894 self.assertIn('u-boot', section_entries)
2895 entry = section_entries['u-boot']
2896 self.assertEqual(0, entry.offset)
2897 self.assertEqual(0x18, entry.image_pos)
2898 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2899 self.assertEqual(len(U_BOOT_DATA), entry.size)
2900
Simon Glass51014aa2019-07-20 12:23:56 -06002901 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
2902 dts='132_replace.dts'):
Simon Glass10f9d002019-07-20 12:23:50 -06002903 """Replace an entry in an image
2904
2905 This writes the entry data to update it, then opens the updated file and
2906 returns the value that it now finds there.
2907
2908 Args:
2909 entry_name: Entry name to replace
2910 data: Data to replace it with
2911 decomp: True to compress the data if needed, False if data is
2912 already compressed so should be used as is
Simon Glass51014aa2019-07-20 12:23:56 -06002913 allow_resize: True to allow entries to change size, False to raise
2914 an exception
Simon Glass10f9d002019-07-20 12:23:50 -06002915
2916 Returns:
2917 Tuple:
2918 data from entry
2919 data from fdtmap (excluding header)
Simon Glass51014aa2019-07-20 12:23:56 -06002920 Image object that was modified
Simon Glass10f9d002019-07-20 12:23:50 -06002921 """
Simon Glass51014aa2019-07-20 12:23:56 -06002922 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass10f9d002019-07-20 12:23:50 -06002923 update_dtb=True)[1]
2924
2925 self.assertIn('image', control.images)
2926 image = control.images['image']
2927 entries = image.GetEntries()
2928 orig_dtb_data = entries['u-boot-dtb'].data
2929 orig_fdtmap_data = entries['fdtmap'].data
2930
2931 image_fname = tools.GetOutputFilename('image.bin')
2932 updated_fname = tools.GetOutputFilename('image-updated.bin')
2933 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
Simon Glass51014aa2019-07-20 12:23:56 -06002934 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
2935 allow_resize)
Simon Glass10f9d002019-07-20 12:23:50 -06002936 data = control.ReadEntry(updated_fname, entry_name, decomp)
2937
Simon Glass51014aa2019-07-20 12:23:56 -06002938 # The DT data should not change unless resized:
2939 if not allow_resize:
2940 new_dtb_data = entries['u-boot-dtb'].data
2941 self.assertEqual(new_dtb_data, orig_dtb_data)
2942 new_fdtmap_data = entries['fdtmap'].data
2943 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass10f9d002019-07-20 12:23:50 -06002944
Simon Glass51014aa2019-07-20 12:23:56 -06002945 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass10f9d002019-07-20 12:23:50 -06002946
2947 def testReplaceSimple(self):
2948 """Test replacing a single file"""
2949 expected = b'x' * len(U_BOOT_DATA)
Simon Glass51014aa2019-07-20 12:23:56 -06002950 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
2951 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06002952 self.assertEqual(expected, data)
2953
2954 # Test that the state looks right. There should be an FDT for the fdtmap
2955 # that we jsut read back in, and it should match what we find in the
2956 # 'control' tables. Checking for an FDT that does not exist should
2957 # return None.
2958 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glass51014aa2019-07-20 12:23:56 -06002959 self.assertIsNotNone(path)
Simon Glass10f9d002019-07-20 12:23:50 -06002960 self.assertEqual(expected_fdtmap, fdtmap)
2961
2962 dtb = state.GetFdtForEtype('fdtmap')
2963 self.assertEqual(dtb.GetContents(), fdtmap)
2964
2965 missing_path, missing_fdtmap = state.GetFdtContents('missing')
2966 self.assertIsNone(missing_path)
2967 self.assertIsNone(missing_fdtmap)
2968
2969 missing_dtb = state.GetFdtForEtype('missing')
2970 self.assertIsNone(missing_dtb)
2971
2972 self.assertEqual('/binman', state.fdt_path_prefix)
2973
2974 def testReplaceResizeFail(self):
2975 """Test replacing a file by something larger"""
2976 expected = U_BOOT_DATA + b'x'
2977 with self.assertRaises(ValueError) as e:
Simon Glass51014aa2019-07-20 12:23:56 -06002978 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
2979 dts='139_replace_repack.dts')
Simon Glass10f9d002019-07-20 12:23:50 -06002980 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
2981 str(e.exception))
2982
2983 def testReplaceMulti(self):
2984 """Test replacing entry data where multiple images are generated"""
2985 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
2986 update_dtb=True)[0]
2987 expected = b'x' * len(U_BOOT_DATA)
2988 updated_fname = tools.GetOutputFilename('image-updated.bin')
2989 tools.WriteFile(updated_fname, data)
2990 entry_name = 'u-boot'
Simon Glass51014aa2019-07-20 12:23:56 -06002991 control.WriteEntry(updated_fname, entry_name, expected,
2992 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06002993 data = control.ReadEntry(updated_fname, entry_name)
2994 self.assertEqual(expected, data)
2995
2996 # Check the state looks right.
2997 self.assertEqual('/binman/image', state.fdt_path_prefix)
2998
2999 # Now check we can write the first image
3000 image_fname = tools.GetOutputFilename('first-image.bin')
3001 updated_fname = tools.GetOutputFilename('first-updated.bin')
3002 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
3003 entry_name = 'u-boot'
Simon Glass51014aa2019-07-20 12:23:56 -06003004 control.WriteEntry(updated_fname, entry_name, expected,
3005 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06003006 data = control.ReadEntry(updated_fname, entry_name)
3007 self.assertEqual(expected, data)
3008
3009 # Check the state looks right.
3010 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass8beb11e2019-07-08 14:25:47 -06003011
Simon Glass12bb1a92019-07-20 12:23:51 -06003012 def testUpdateFdtAllRepack(self):
3013 """Test that all device trees are updated with offset/size info"""
3014 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3015 SECTION_SIZE = 0x300
3016 DTB_SIZE = 602
3017 FDTMAP_SIZE = 608
3018 base_expected = {
3019 'offset': 0,
3020 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3021 'image-pos': 0,
3022 'section:offset': 0,
3023 'section:size': SECTION_SIZE,
3024 'section:image-pos': 0,
3025 'section/u-boot-dtb:offset': 4,
3026 'section/u-boot-dtb:size': 636,
3027 'section/u-boot-dtb:image-pos': 4,
3028 'u-boot-spl-dtb:offset': SECTION_SIZE,
3029 'u-boot-spl-dtb:size': DTB_SIZE,
3030 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3031 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3032 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3033 'u-boot-tpl-dtb:size': DTB_SIZE,
3034 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3035 'fdtmap:size': FDTMAP_SIZE,
3036 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3037 }
3038 main_expected = {
3039 'section:orig-size': SECTION_SIZE,
3040 'section/u-boot-dtb:orig-offset': 4,
3041 }
3042
3043 # We expect three device-tree files in the output, with the first one
3044 # within a fixed-size section.
3045 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3046 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3047 # main U-Boot tree. All three should have the same positions and offset
3048 # except that the main tree should include the main_expected properties
3049 start = 4
3050 for item in ['', 'spl', 'tpl', None]:
3051 if item is None:
3052 start += 16 # Move past fdtmap header
3053 dtb = fdt.Fdt.FromData(data[start:])
3054 dtb.Scan()
3055 props = self._GetPropTree(dtb,
3056 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3057 prefix='/' if item is None else '/binman/')
3058 expected = dict(base_expected)
3059 if item:
3060 expected[item] = 0
3061 else:
3062 # Main DTB and fdtdec should include the 'orig-' properties
3063 expected.update(main_expected)
3064 # Helpful for debugging:
3065 #for prop in sorted(props):
3066 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3067 self.assertEqual(expected, props)
3068 if item == '':
3069 start = SECTION_SIZE
3070 else:
3071 start += dtb._fdt_obj.totalsize()
3072
Simon Glasseba1f0c2019-07-20 12:23:55 -06003073 def testFdtmapHeaderMiddle(self):
3074 """Test an FDT map in the middle of an image when it should be at end"""
3075 with self.assertRaises(ValueError) as e:
3076 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3077 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3078 str(e.exception))
3079
3080 def testFdtmapHeaderStartBad(self):
3081 """Test an FDT map in middle of an image when it should be at start"""
3082 with self.assertRaises(ValueError) as e:
3083 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3084 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3085 str(e.exception))
3086
3087 def testFdtmapHeaderEndBad(self):
3088 """Test an FDT map at the start of an image when it should be at end"""
3089 with self.assertRaises(ValueError) as e:
3090 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3091 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3092 str(e.exception))
3093
3094 def testFdtmapHeaderNoSize(self):
3095 """Test an image header at the end of an image with undefined size"""
3096 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3097
Simon Glass51014aa2019-07-20 12:23:56 -06003098 def testReplaceResize(self):
3099 """Test replacing a single file in an entry with a larger file"""
3100 expected = U_BOOT_DATA + b'x'
3101 data, _, image = self._RunReplaceCmd('u-boot', expected,
3102 dts='139_replace_repack.dts')
3103 self.assertEqual(expected, data)
3104
3105 entries = image.GetEntries()
3106 dtb_data = entries['u-boot-dtb'].data
3107 dtb = fdt.Fdt.FromData(dtb_data)
3108 dtb.Scan()
3109
3110 # The u-boot section should now be larger in the dtb
3111 node = dtb.GetNode('/binman/u-boot')
3112 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3113
3114 # Same for the fdtmap
3115 fdata = entries['fdtmap'].data
3116 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3117 fdtb.Scan()
3118 fnode = fdtb.GetNode('/u-boot')
3119 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3120
3121 def testReplaceResizeNoRepack(self):
3122 """Test replacing an entry with a larger file when not allowed"""
3123 expected = U_BOOT_DATA + b'x'
3124 with self.assertRaises(ValueError) as e:
3125 self._RunReplaceCmd('u-boot', expected)
3126 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3127 str(e.exception))
3128
Simon Glass61ec04f2019-07-20 12:23:58 -06003129 def testEntryShrink(self):
3130 """Test contracting an entry after it is packed"""
3131 try:
3132 state.SetAllowEntryContraction(True)
3133 data = self._DoReadFileDtb('140_entry_shrink.dts',
3134 update_dtb=True)[0]
3135 finally:
3136 state.SetAllowEntryContraction(False)
3137 self.assertEqual(b'a', data[:1])
3138 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3139 self.assertEqual(b'a', data[-1:])
3140
3141 def testEntryShrinkFail(self):
3142 """Test not being allowed to contract an entry after it is packed"""
3143 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3144
3145 # In this case there is a spare byte at the end of the data. The size of
3146 # the contents is only 1 byte but we still have the size before it
3147 # shrunk.
3148 self.assertEqual(b'a\0', data[:2])
3149 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3150 self.assertEqual(b'a\0', data[-2:])
3151
Simon Glass27145fd2019-07-20 12:24:01 -06003152 def testDescriptorOffset(self):
3153 """Test that the Intel descriptor is always placed at at the start"""
3154 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3155 image = control.images['image']
3156 entries = image.GetEntries()
3157 desc = entries['intel-descriptor']
3158 self.assertEqual(0xff800000, desc.offset);
3159 self.assertEqual(0xff800000, desc.image_pos);
3160
Simon Glasseb0f4a42019-07-20 12:24:06 -06003161 def testReplaceCbfs(self):
3162 """Test replacing a single file in CBFS without changing the size"""
3163 self._CheckLz4()
3164 expected = b'x' * len(U_BOOT_DATA)
3165 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3166 updated_fname = tools.GetOutputFilename('image-updated.bin')
3167 tools.WriteFile(updated_fname, data)
3168 entry_name = 'section/cbfs/u-boot'
3169 control.WriteEntry(updated_fname, entry_name, expected,
3170 allow_resize=True)
3171 data = control.ReadEntry(updated_fname, entry_name)
3172 self.assertEqual(expected, data)
3173
3174 def testReplaceResizeCbfs(self):
3175 """Test replacing a single file in CBFS with one of a different size"""
3176 self._CheckLz4()
3177 expected = U_BOOT_DATA + b'x'
3178 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3179 updated_fname = tools.GetOutputFilename('image-updated.bin')
3180 tools.WriteFile(updated_fname, data)
3181 entry_name = 'section/cbfs/u-boot'
3182 control.WriteEntry(updated_fname, entry_name, expected,
3183 allow_resize=True)
3184 data = control.ReadEntry(updated_fname, entry_name)
3185 self.assertEqual(expected, data)
3186
Simon Glassa6cb9952019-07-20 12:24:15 -06003187 def _SetupForReplace(self):
3188 """Set up some files to use to replace entries
3189
3190 This generates an image, copies it to a new file, extracts all the files
3191 in it and updates some of them
3192
3193 Returns:
3194 List
3195 Image filename
3196 Output directory
3197 Expected values for updated entries, each a string
3198 """
3199 data = self._DoReadFileRealDtb('143_replace_all.dts')
3200
3201 updated_fname = tools.GetOutputFilename('image-updated.bin')
3202 tools.WriteFile(updated_fname, data)
3203
3204 outdir = os.path.join(self._indir, 'extract')
3205 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3206
3207 expected1 = b'x' + U_BOOT_DATA + b'y'
3208 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3209 tools.WriteFile(u_boot_fname1, expected1)
3210
3211 expected2 = b'a' + U_BOOT_DATA + b'b'
3212 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
3213 tools.WriteFile(u_boot_fname2, expected2)
3214
3215 expected_text = b'not the same text'
3216 text_fname = os.path.join(outdir, 'text')
3217 tools.WriteFile(text_fname, expected_text)
3218
3219 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3220 dtb = fdt.FdtScan(dtb_fname)
3221 node = dtb.GetNode('/binman/text')
3222 node.AddString('my-property', 'the value')
3223 dtb.Sync(auto_resize=True)
3224 dtb.Flush()
3225
3226 return updated_fname, outdir, expected1, expected2, expected_text
3227
3228 def _CheckReplaceMultiple(self, entry_paths):
3229 """Handle replacing the contents of multiple entries
3230
3231 Args:
3232 entry_paths: List of entry paths to replace
3233
3234 Returns:
3235 List
3236 Dict of entries in the image:
3237 key: Entry name
3238 Value: Entry object
3239 Expected values for updated entries, each a string
3240 """
3241 updated_fname, outdir, expected1, expected2, expected_text = (
3242 self._SetupForReplace())
3243 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3244
3245 image = Image.FromFile(updated_fname)
3246 image.LoadData()
3247 return image.GetEntries(), expected1, expected2, expected_text
3248
3249 def testReplaceAll(self):
3250 """Test replacing the contents of all entries"""
3251 entries, expected1, expected2, expected_text = (
3252 self._CheckReplaceMultiple([]))
3253 data = entries['u-boot'].data
3254 self.assertEqual(expected1, data)
3255
3256 data = entries['u-boot2'].data
3257 self.assertEqual(expected2, data)
3258
3259 data = entries['text'].data
3260 self.assertEqual(expected_text, data)
3261
3262 # Check that the device tree is updated
3263 data = entries['u-boot-dtb'].data
3264 dtb = fdt.Fdt.FromData(data)
3265 dtb.Scan()
3266 node = dtb.GetNode('/binman/text')
3267 self.assertEqual('the value', node.props['my-property'].value)
3268
3269 def testReplaceSome(self):
3270 """Test replacing the contents of a few entries"""
3271 entries, expected1, expected2, expected_text = (
3272 self._CheckReplaceMultiple(['u-boot2', 'text']))
3273
3274 # This one should not change
3275 data = entries['u-boot'].data
3276 self.assertEqual(U_BOOT_DATA, data)
3277
3278 data = entries['u-boot2'].data
3279 self.assertEqual(expected2, data)
3280
3281 data = entries['text'].data
3282 self.assertEqual(expected_text, data)
3283
3284 def testReplaceCmd(self):
3285 """Test replacing a file fron an image on the command line"""
3286 self._DoReadFileRealDtb('143_replace_all.dts')
3287
3288 try:
3289 tmpdir, updated_fname = self._SetupImageInTmpdir()
3290
3291 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3292 expected = b'x' * len(U_BOOT_DATA)
3293 tools.WriteFile(fname, expected)
3294
3295 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
3296 data = tools.ReadFile(updated_fname)
3297 self.assertEqual(expected, data[:len(expected)])
3298 map_fname = os.path.join(tmpdir, 'image-updated.map')
3299 self.assertFalse(os.path.exists(map_fname))
3300 finally:
3301 shutil.rmtree(tmpdir)
3302
3303 def testReplaceCmdSome(self):
3304 """Test replacing some files fron an image on the command line"""
3305 updated_fname, outdir, expected1, expected2, expected_text = (
3306 self._SetupForReplace())
3307
3308 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3309 'u-boot2', 'text')
3310
3311 tools.PrepareOutputDir(None)
3312 image = Image.FromFile(updated_fname)
3313 image.LoadData()
3314 entries = image.GetEntries()
3315
3316 # This one should not change
3317 data = entries['u-boot'].data
3318 self.assertEqual(U_BOOT_DATA, data)
3319
3320 data = entries['u-boot2'].data
3321 self.assertEqual(expected2, data)
3322
3323 data = entries['text'].data
3324 self.assertEqual(expected_text, data)
3325
3326 def testReplaceMissing(self):
3327 """Test replacing entries where the file is missing"""
3328 updated_fname, outdir, expected1, expected2, expected_text = (
3329 self._SetupForReplace())
3330
3331 # Remove one of the files, to generate a warning
3332 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3333 os.remove(u_boot_fname1)
3334
3335 with test_util.capture_sys_output() as (stdout, stderr):
3336 control.ReplaceEntries(updated_fname, None, outdir, [])
3337 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass38fdb4c2020-07-09 18:39:39 -06003338 stderr.getvalue())
Simon Glassa6cb9952019-07-20 12:24:15 -06003339
3340 def testReplaceCmdMap(self):
3341 """Test replacing a file fron an image on the command line"""
3342 self._DoReadFileRealDtb('143_replace_all.dts')
3343
3344 try:
3345 tmpdir, updated_fname = self._SetupImageInTmpdir()
3346
3347 fname = os.path.join(self._indir, 'update-u-boot.bin')
3348 expected = b'x' * len(U_BOOT_DATA)
3349 tools.WriteFile(fname, expected)
3350
3351 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3352 '-f', fname, '-m')
3353 map_fname = os.path.join(tmpdir, 'image-updated.map')
3354 self.assertTrue(os.path.exists(map_fname))
3355 finally:
3356 shutil.rmtree(tmpdir)
3357
3358 def testReplaceNoEntryPaths(self):
3359 """Test replacing an entry without an entry path"""
3360 self._DoReadFileRealDtb('143_replace_all.dts')
3361 image_fname = tools.GetOutputFilename('image.bin')
3362 with self.assertRaises(ValueError) as e:
3363 control.ReplaceEntries(image_fname, 'fname', None, [])
3364 self.assertIn('Must specify an entry path to read with -f',
3365 str(e.exception))
3366
3367 def testReplaceTooManyEntryPaths(self):
3368 """Test extracting some entries"""
3369 self._DoReadFileRealDtb('143_replace_all.dts')
3370 image_fname = tools.GetOutputFilename('image.bin')
3371 with self.assertRaises(ValueError) as e:
3372 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3373 self.assertIn('Must specify exactly one entry path to write with -f',
3374 str(e.exception))
3375
Simon Glass2250ee62019-08-24 07:22:48 -06003376 def testPackReset16(self):
3377 """Test that an image with an x86 reset16 region can be created"""
3378 data = self._DoReadFile('144_x86_reset16.dts')
3379 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3380
3381 def testPackReset16Spl(self):
3382 """Test that an image with an x86 reset16-spl region can be created"""
3383 data = self._DoReadFile('145_x86_reset16_spl.dts')
3384 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3385
3386 def testPackReset16Tpl(self):
3387 """Test that an image with an x86 reset16-tpl region can be created"""
3388 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3389 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3390
Simon Glass5af12072019-08-24 07:22:50 -06003391 def testPackIntelFit(self):
3392 """Test that an image with an Intel FIT and pointer can be created"""
3393 data = self._DoReadFile('147_intel_fit.dts')
3394 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3395 fit = data[16:32];
3396 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3397 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3398
3399 image = control.images['image']
3400 entries = image.GetEntries()
3401 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3402 self.assertEqual(expected_ptr, ptr)
3403
3404 def testPackIntelFitMissing(self):
3405 """Test detection of a FIT pointer with not FIT region"""
3406 with self.assertRaises(ValueError) as e:
3407 self._DoReadFile('148_intel_fit_missing.dts')
3408 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3409 str(e.exception))
3410
Simon Glass7c150132019-11-06 17:22:44 -07003411 def _CheckSymbolsTplSection(self, dts, expected_vals):
3412 data = self._DoReadFile(dts)
3413 sym_values = struct.pack('<LQLL', *expected_vals)
Simon Glass2090f1e2019-08-24 07:23:00 -06003414 upto1 = 4 + len(U_BOOT_SPL_DATA)
Simon Glassb87064c2019-08-24 07:23:05 -06003415 expected1 = tools.GetBytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[20:]
Simon Glass2090f1e2019-08-24 07:23:00 -06003416 self.assertEqual(expected1, data[:upto1])
3417
3418 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Simon Glassb87064c2019-08-24 07:23:05 -06003419 expected2 = tools.GetBytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[20:]
Simon Glass2090f1e2019-08-24 07:23:00 -06003420 self.assertEqual(expected2, data[upto1:upto2])
3421
Simon Glasseb0086f2019-08-24 07:23:04 -06003422 upto3 = 0x34 + len(U_BOOT_DATA)
3423 expected3 = tools.GetBytes(0xff, 1) + U_BOOT_DATA
Simon Glass2090f1e2019-08-24 07:23:00 -06003424 self.assertEqual(expected3, data[upto2:upto3])
3425
Simon Glassb87064c2019-08-24 07:23:05 -06003426 expected4 = sym_values + U_BOOT_TPL_DATA[20:]
Simon Glass7c150132019-11-06 17:22:44 -07003427 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3428
3429 def testSymbolsTplSection(self):
3430 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3431 self._SetupSplElf('u_boot_binman_syms')
3432 self._SetupTplElf('u_boot_binman_syms')
3433 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
3434 [0x04, 0x1c, 0x10 + 0x34, 0x04])
3435
3436 def testSymbolsTplSectionX86(self):
3437 """Test binman can assign symbols in a section with end-at-4gb"""
3438 self._SetupSplElf('u_boot_binman_syms_x86')
3439 self._SetupTplElf('u_boot_binman_syms_x86')
3440 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
3441 [0xffffff04, 0xffffff1c, 0xffffff34,
3442 0x04])
Simon Glass2090f1e2019-08-24 07:23:00 -06003443
Simon Glassbf4d0e22019-08-24 07:23:03 -06003444 def testPackX86RomIfwiSectiom(self):
3445 """Test that a section can be placed in an IFWI region"""
3446 self._SetupIfwi('fitimage.bin')
3447 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3448 self._CheckIfwi(data)
3449
Simon Glassea0fff92019-08-24 07:23:07 -06003450 def testPackFspM(self):
3451 """Test that an image with a FSP memory-init binary can be created"""
3452 data = self._DoReadFile('152_intel_fsp_m.dts')
3453 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3454
Simon Glassbc6a88f2019-10-20 21:31:35 -06003455 def testPackFspS(self):
3456 """Test that an image with a FSP silicon-init binary can be created"""
3457 data = self._DoReadFile('153_intel_fsp_s.dts')
3458 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassea0fff92019-08-24 07:23:07 -06003459
Simon Glass998d1482019-10-20 21:31:36 -06003460 def testPackFspT(self):
3461 """Test that an image with a FSP temp-ram-init binary can be created"""
3462 data = self._DoReadFile('154_intel_fsp_t.dts')
3463 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3464
Simon Glass0dc706f2020-07-09 18:39:31 -06003465 def testMkimage(self):
3466 """Test using mkimage to build an image"""
3467 data = self._DoReadFile('156_mkimage.dts')
3468
3469 # Just check that the data appears in the file somewhere
3470 self.assertIn(U_BOOT_SPL_DATA, data)
3471
Simon Glassce867ad2020-07-09 18:39:36 -06003472 def testExtblob(self):
3473 """Test an image with an external blob"""
3474 data = self._DoReadFile('157_blob_ext.dts')
3475 self.assertEqual(REFCODE_DATA, data)
3476
3477 def testExtblobMissing(self):
3478 """Test an image with a missing external blob"""
3479 with self.assertRaises(ValueError) as e:
3480 self._DoReadFile('158_blob_ext_missing.dts')
3481 self.assertIn("Filename 'missing-file' not found in input path",
3482 str(e.exception))
3483
Simon Glass4f9f1052020-07-09 18:39:38 -06003484 def testExtblobMissingOk(self):
3485 """Test an image with an missing external blob that is allowed"""
Simon Glassb1cca952020-07-09 18:39:40 -06003486 with test_util.capture_sys_output() as (stdout, stderr):
3487 self._DoTestFile('158_blob_ext_missing.dts', allow_missing=True)
3488 err = stderr.getvalue()
3489 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
3490
3491 def testExtblobMissingOkSect(self):
3492 """Test an image with an missing external blob that is allowed"""
3493 with test_util.capture_sys_output() as (stdout, stderr):
3494 self._DoTestFile('159_blob_ext_missing_sect.dts',
3495 allow_missing=True)
3496 err = stderr.getvalue()
3497 self.assertRegex(err, "Image 'main-section'.*missing.*: "
3498 "blob-ext blob-ext2")
Simon Glass4f9f1052020-07-09 18:39:38 -06003499
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003500 def testPackX86RomMeMissingDesc(self):
3501 """Test that an missing Intel descriptor entry is allowed"""
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003502 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass52b10dd2020-07-25 15:11:19 -06003503 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003504 err = stderr.getvalue()
3505 self.assertRegex(err,
3506 "Image 'main-section'.*missing.*: intel-descriptor")
3507
3508 def testPackX86RomMissingIfwi(self):
3509 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3510 self._SetupIfwi('fitimage.bin')
3511 pathname = os.path.join(self._indir, 'fitimage.bin')
3512 os.remove(pathname)
3513 with test_util.capture_sys_output() as (stdout, stderr):
3514 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3515 err = stderr.getvalue()
3516 self.assertRegex(err, "Image 'main-section'.*missing.*: intel-ifwi")
3517
Simon Glassb3295fd2020-07-09 18:39:42 -06003518 def testPackOverlap(self):
3519 """Test that zero-size overlapping regions are ignored"""
3520 self._DoTestFile('160_pack_overlap_zero.dts')
3521
Simon Glassfdc34362020-07-09 18:39:45 -06003522 def testSimpleFit(self):
3523 """Test an image with a FIT inside"""
3524 data = self._DoReadFile('161_fit.dts')
3525 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3526 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3527 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3528
3529 # The data should be inside the FIT
3530 dtb = fdt.Fdt.FromData(fit_data)
3531 dtb.Scan()
3532 fnode = dtb.GetNode('/images/kernel')
3533 self.assertIn('data', fnode.props)
3534
3535 fname = os.path.join(self._indir, 'fit_data.fit')
3536 tools.WriteFile(fname, fit_data)
3537 out = tools.Run('dumpimage', '-l', fname)
3538
3539 # Check a few features to make sure the plumbing works. We don't need
3540 # to test the operation of mkimage or dumpimage here. First convert the
3541 # output into a dict where the keys are the fields printed by dumpimage
3542 # and the values are a list of values for each field
3543 lines = out.splitlines()
3544
3545 # Converts "Compression: gzip compressed" into two groups:
3546 # 'Compression' and 'gzip compressed'
3547 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3548 vals = collections.defaultdict(list)
3549 for line in lines:
3550 mat = re_line.match(line)
3551 vals[mat.group(1)].append(mat.group(2))
3552
3553 self.assertEquals('FIT description: test-desc', lines[0])
3554 self.assertIn('Created:', lines[1])
3555 self.assertIn('Image 0 (kernel)', vals)
3556 self.assertIn('Hash value', vals)
3557 data_sizes = vals.get('Data Size')
3558 self.assertIsNotNone(data_sizes)
3559 self.assertEqual(2, len(data_sizes))
3560 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
3561 self.assertEqual(len(U_BOOT_DATA), int(data_sizes[0].split()[0]))
3562 self.assertEqual(len(U_BOOT_SPL_DTB_DATA), int(data_sizes[1].split()[0]))
3563
3564 def testFitExternal(self):
Simon Glasse9d336d2020-09-01 05:13:55 -06003565 """Test an image with an FIT with external images"""
Simon Glassfdc34362020-07-09 18:39:45 -06003566 data = self._DoReadFile('162_fit_external.dts')
3567 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3568
3569 # The data should be outside the FIT
3570 dtb = fdt.Fdt.FromData(fit_data)
3571 dtb.Scan()
3572 fnode = dtb.GetNode('/images/kernel')
3573 self.assertNotIn('data', fnode.props)
Simon Glass12bb1a92019-07-20 12:23:51 -06003574
Alper Nebi Yasak8001d0b2020-08-31 12:58:18 +03003575 def testSectionIgnoreHashSignature(self):
3576 """Test that sections ignore hash, signature nodes for its data"""
3577 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
3578 expected = (U_BOOT_DATA + U_BOOT_DATA)
3579 self.assertEqual(expected, data)
3580
Alper Nebi Yasak3fdeb142020-08-31 12:58:19 +03003581 def testPadInSections(self):
3582 """Test pad-before, pad-after for entries in sections"""
Simon Glassf90d9062020-10-26 17:40:09 -06003583 data, _, _, out_dtb_fname = self._DoReadFileDtb(
3584 '166_pad_in_sections.dts', update_dtb=True)
Alper Nebi Yasak3fdeb142020-08-31 12:58:19 +03003585 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
3586 U_BOOT_DATA + tools.GetBytes(ord('!'), 6) +
3587 U_BOOT_DATA)
3588 self.assertEqual(expected, data)
3589
Simon Glassf90d9062020-10-26 17:40:09 -06003590 dtb = fdt.Fdt(out_dtb_fname)
3591 dtb.Scan()
3592 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
3593 expected = {
3594 'image-pos': 0,
3595 'offset': 0,
3596 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
3597
3598 'section:image-pos': 0,
3599 'section:offset': 0,
3600 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
3601
3602 'section/before:image-pos': 0,
3603 'section/before:offset': 0,
3604 'section/before:size': len(U_BOOT_DATA),
3605
3606 'section/u-boot:image-pos': 4,
3607 'section/u-boot:offset': 4,
3608 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
3609
3610 'section/after:image-pos': 26,
3611 'section/after:offset': 26,
3612 'section/after:size': len(U_BOOT_DATA),
3613 }
3614 self.assertEqual(expected, props)
3615
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03003616 def testFitImageSubentryAlignment(self):
3617 """Test relative alignability of FIT image subentries"""
3618 entry_args = {
3619 'test-id': TEXT_DATA,
3620 }
3621 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
3622 entry_args=entry_args)
3623 dtb = fdt.Fdt.FromData(data)
3624 dtb.Scan()
3625
3626 node = dtb.GetNode('/images/kernel')
3627 data = dtb.GetProps(node)["data"].bytes
3628 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
3629 expected = (tools.GetBytes(0, 0x20) + U_BOOT_SPL_DATA +
3630 tools.GetBytes(0, align_pad) + U_BOOT_DATA)
3631 self.assertEqual(expected, data)
3632
3633 node = dtb.GetNode('/images/fdt-1')
3634 data = dtb.GetProps(node)["data"].bytes
3635 expected = (U_BOOT_SPL_DTB_DATA + tools.GetBytes(0, 20) +
3636 tools.ToBytes(TEXT_DATA) + tools.GetBytes(0, 30) +
3637 U_BOOT_DTB_DATA)
3638 self.assertEqual(expected, data)
3639
3640 def testFitExtblobMissingOk(self):
3641 """Test a FIT with a missing external blob that is allowed"""
3642 with test_util.capture_sys_output() as (stdout, stderr):
3643 self._DoTestFile('168_fit_missing_blob.dts',
3644 allow_missing=True)
3645 err = stderr.getvalue()
Simon Glassb2381432020-09-06 10:39:09 -06003646 self.assertRegex(err, "Image 'main-section'.*missing.*: atf-bl31")
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03003647
Simon Glass3decfa32020-09-01 05:13:54 -06003648 def testBlobNamedByArgMissing(self):
3649 """Test handling of a missing entry arg"""
3650 with self.assertRaises(ValueError) as e:
3651 self._DoReadFile('068_blob_named_by_arg.dts')
3652 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
3653 str(e.exception))
3654
Simon Glassdc2f81a2020-09-01 05:13:58 -06003655 def testPackBl31(self):
3656 """Test that an image with an ATF BL31 binary can be created"""
3657 data = self._DoReadFile('169_atf_bl31.dts')
3658 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
3659
Samuel Holland18bd4552020-10-21 21:12:15 -05003660 def testPackScp(self):
3661 """Test that an image with an SCP binary can be created"""
3662 data = self._DoReadFile('172_scp.dts')
3663 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
3664
Simon Glass6cf99532020-09-01 05:13:59 -06003665 def testFitFdt(self):
3666 """Test an image with an FIT with multiple FDT images"""
3667 def _CheckFdt(seq, expected_data):
3668 """Check the FDT nodes
3669
3670 Args:
3671 seq: Sequence number to check (0 or 1)
3672 expected_data: Expected contents of 'data' property
3673 """
3674 name = 'fdt-%d' % seq
3675 fnode = dtb.GetNode('/images/%s' % name)
3676 self.assertIsNotNone(fnode)
3677 self.assertEqual({'description','type', 'compression', 'data'},
3678 set(fnode.props.keys()))
3679 self.assertEqual(expected_data, fnode.props['data'].bytes)
3680 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
3681 fnode.props['description'].value)
3682
3683 def _CheckConfig(seq, expected_data):
3684 """Check the configuration nodes
3685
3686 Args:
3687 seq: Sequence number to check (0 or 1)
3688 expected_data: Expected contents of 'data' property
3689 """
3690 cnode = dtb.GetNode('/configurations')
3691 self.assertIn('default', cnode.props)
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003692 self.assertEqual('config-2', cnode.props['default'].value)
Simon Glass6cf99532020-09-01 05:13:59 -06003693
3694 name = 'config-%d' % seq
3695 fnode = dtb.GetNode('/configurations/%s' % name)
3696 self.assertIsNotNone(fnode)
3697 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
3698 set(fnode.props.keys()))
3699 self.assertEqual('conf-test-fdt%d.dtb' % seq,
3700 fnode.props['description'].value)
3701 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
3702
3703 entry_args = {
3704 'of-list': 'test-fdt1 test-fdt2',
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003705 'default-dt': 'test-fdt2',
Simon Glass6cf99532020-09-01 05:13:59 -06003706 }
3707 data = self._DoReadFileDtb(
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003708 '172_fit_fdt.dts',
Simon Glass6cf99532020-09-01 05:13:59 -06003709 entry_args=entry_args,
3710 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3711 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3712 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3713
3714 dtb = fdt.Fdt.FromData(fit_data)
3715 dtb.Scan()
3716 fnode = dtb.GetNode('/images/kernel')
3717 self.assertIn('data', fnode.props)
3718
3719 # Check all the properties in fdt-1 and fdt-2
3720 _CheckFdt(1, TEST_FDT1_DATA)
3721 _CheckFdt(2, TEST_FDT2_DATA)
3722
3723 # Check configurations
3724 _CheckConfig(1, TEST_FDT1_DATA)
3725 _CheckConfig(2, TEST_FDT2_DATA)
3726
3727 def testFitFdtMissingList(self):
3728 """Test handling of a missing 'of-list' entry arg"""
3729 with self.assertRaises(ValueError) as e:
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003730 self._DoReadFile('172_fit_fdt.dts')
Simon Glass6cf99532020-09-01 05:13:59 -06003731 self.assertIn("Generator node requires 'of-list' entry argument",
3732 str(e.exception))
3733
3734 def testFitFdtEmptyList(self):
3735 """Test handling of an empty 'of-list' entry arg"""
3736 entry_args = {
3737 'of-list': '',
3738 }
3739 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
3740
3741 def testFitFdtMissingProp(self):
3742 """Test handling of a missing 'fit,fdt-list' property"""
3743 with self.assertRaises(ValueError) as e:
3744 self._DoReadFile('171_fit_fdt_missing_prop.dts')
3745 self.assertIn("Generator node requires 'fit,fdt-list' property",
3746 str(e.exception))
Simon Glassdc2f81a2020-09-01 05:13:58 -06003747
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003748 def testFitFdtEmptyList(self):
3749 """Test handling of an empty 'of-list' entry arg"""
3750 entry_args = {
3751 'of-list': '',
3752 }
3753 data = self._DoReadFileDtb('172_fit_fdt.dts', entry_args=entry_args)[0]
3754
3755 def testFitFdtMissing(self):
3756 """Test handling of a missing 'default-dt' entry arg"""
3757 entry_args = {
3758 'of-list': 'test-fdt1 test-fdt2',
3759 }
3760 with self.assertRaises(ValueError) as e:
3761 self._DoReadFileDtb(
3762 '172_fit_fdt.dts',
3763 entry_args=entry_args,
3764 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3765 self.assertIn("Generated 'default' node requires default-dt entry argument",
3766 str(e.exception))
3767
3768 def testFitFdtNotInList(self):
3769 """Test handling of a default-dt that is not in the of-list"""
3770 entry_args = {
3771 'of-list': 'test-fdt1 test-fdt2',
3772 'default-dt': 'test-fdt3',
3773 }
3774 with self.assertRaises(ValueError) as e:
3775 self._DoReadFileDtb(
3776 '172_fit_fdt.dts',
3777 entry_args=entry_args,
3778 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3779 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
3780 str(e.exception))
3781
Simon Glassb2381432020-09-06 10:39:09 -06003782 def testFitExtblobMissingHelp(self):
3783 """Test display of help messages when an external blob is missing"""
3784 control.missing_blob_help = control._ReadMissingBlobHelp()
3785 control.missing_blob_help['wibble'] = 'Wibble test'
3786 control.missing_blob_help['another'] = 'Another test'
3787 with test_util.capture_sys_output() as (stdout, stderr):
3788 self._DoTestFile('168_fit_missing_blob.dts',
3789 allow_missing=True)
3790 err = stderr.getvalue()
3791
3792 # We can get the tag from the name, the type or the missing-msg
3793 # property. Check all three.
3794 self.assertIn('You may need to build ARM Trusted', err)
3795 self.assertIn('Wibble test', err)
3796 self.assertIn('Another test', err)
3797
Simon Glass204aa782020-09-06 10:35:32 -06003798 def testMissingBlob(self):
3799 """Test handling of a blob containing a missing file"""
3800 with self.assertRaises(ValueError) as e:
3801 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
3802 self.assertIn("Filename 'missing' not found in input path",
3803 str(e.exception))
3804
Simon Glassfb91d562020-09-06 10:35:33 -06003805 def testEnvironment(self):
3806 """Test adding a U-Boot environment"""
3807 data = self._DoReadFile('174_env.dts')
3808 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3809 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3810 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3811 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
3812 env)
3813
3814 def testEnvironmentNoSize(self):
3815 """Test that a missing 'size' property is detected"""
3816 with self.assertRaises(ValueError) as e:
Simon Glassa4dfe3e2020-10-26 17:40:00 -06003817 self._DoTestFile('175_env_no_size.dts')
Simon Glassfb91d562020-09-06 10:35:33 -06003818 self.assertIn("'u-boot-env' entry must have a size property",
3819 str(e.exception))
3820
3821 def testEnvironmentTooSmall(self):
3822 """Test handling of an environment that does not fit"""
3823 with self.assertRaises(ValueError) as e:
Simon Glassa4dfe3e2020-10-26 17:40:00 -06003824 self._DoTestFile('176_env_too_small.dts')
Simon Glassfb91d562020-09-06 10:35:33 -06003825
3826 # checksum, start byte, environment with \0 terminator, final \0
3827 need = 4 + 1 + len(ENV_DATA) + 1 + 1
3828 short = need - 0x8
3829 self.assertIn("too small to hold data (need %#x more bytes)" % short,
3830 str(e.exception))
3831
Simon Glassf2c0dd82020-10-26 17:40:01 -06003832 def testSkipAtStart(self):
3833 """Test handling of skip-at-start section"""
3834 data = self._DoReadFile('177_skip_at_start.dts')
3835 self.assertEqual(U_BOOT_DATA, data)
3836
3837 image = control.images['image']
3838 entries = image.GetEntries()
3839 section = entries['section']
3840 self.assertEqual(0, section.offset)
3841 self.assertEqual(len(U_BOOT_DATA), section.size)
3842 self.assertEqual(U_BOOT_DATA, section.GetData())
3843
3844 entry = section.GetEntries()['u-boot']
3845 self.assertEqual(16, entry.offset)
3846 self.assertEqual(len(U_BOOT_DATA), entry.size)
3847 self.assertEqual(U_BOOT_DATA, entry.data)
3848
3849 def testSkipAtStartPad(self):
3850 """Test handling of skip-at-start section with padded entry"""
3851 data = self._DoReadFile('178_skip_at_start_pad.dts')
3852 before = tools.GetBytes(0, 8)
3853 after = tools.GetBytes(0, 4)
3854 all = before + U_BOOT_DATA + after
3855 self.assertEqual(all, data)
3856
3857 image = control.images['image']
3858 entries = image.GetEntries()
3859 section = entries['section']
3860 self.assertEqual(0, section.offset)
3861 self.assertEqual(len(all), section.size)
3862 self.assertEqual(all, section.GetData())
3863
3864 entry = section.GetEntries()['u-boot']
3865 self.assertEqual(16, entry.offset)
3866 self.assertEqual(len(all), entry.size)
3867 self.assertEqual(U_BOOT_DATA, entry.data)
3868
3869 def testSkipAtStartSectionPad(self):
3870 """Test handling of skip-at-start section with padding"""
3871 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
3872 before = tools.GetBytes(0, 8)
3873 after = tools.GetBytes(0, 4)
3874 all = before + U_BOOT_DATA + after
3875
3876 # This is not correct, but it is what binman currently produces
Simon Glass17ea9f32020-10-26 17:40:11 -06003877 self.assertEqual(before + U_BOOT_DATA + tools.GetBytes(0, 16), data)
Simon Glassf2c0dd82020-10-26 17:40:01 -06003878
3879 image = control.images['image']
3880 entries = image.GetEntries()
3881 section = entries['section']
3882 self.assertEqual(0, section.offset)
3883 self.assertEqual(len(all), section.size)
3884 self.assertIsNone(section.data)
Simon Glassf2c0dd82020-10-26 17:40:01 -06003885
3886 entry = section.GetEntries()['u-boot']
3887 self.assertEqual(16, entry.offset)
3888 self.assertEqual(len(U_BOOT_DATA), entry.size)
3889 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassfb91d562020-09-06 10:35:33 -06003890
Simon Glass9fc60b42017-11-12 21:52:22 -07003891if __name__ == "__main__":
3892 unittest.main()