blob: 31e93c647fefe12d2d4d14fb17ac838e5ed4251c [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001# SPDX-License-Identifier: GPL-2.0+
Simon Glass4f443042016-11-25 20:15:52 -07002# Copyright (c) 2016 Google, Inc
3# Written by Simon Glass <sjg@chromium.org>
4#
Simon Glass4f443042016-11-25 20:15:52 -07005# To run a single test, change to this directory, and:
6#
7# python -m unittest func_test.TestFunctional.testHelp
8
Simon Glassfdc34362020-07-09 18:39:45 -06009import collections
Simon Glass16287932020-04-17 18:09:03 -060010import gzip
Simon Glasse0e5df92018-09-14 04:57:31 -060011import hashlib
Simon Glass4f443042016-11-25 20:15:52 -070012from optparse import OptionParser
13import os
Simon Glassfdc34362020-07-09 18:39:45 -060014import re
Simon Glass4f443042016-11-25 20:15:52 -070015import shutil
16import struct
17import sys
18import tempfile
19import unittest
20
Simon Glass16287932020-04-17 18:09:03 -060021from binman import cbfs_util
22from binman import cmdline
23from binman import control
24from binman import elf
25from binman import elf_test
26from binman import fmap_util
Simon Glass16287932020-04-17 18:09:03 -060027from binman import state
28from dtoc import fdt
29from dtoc import fdt_util
30from binman.etype import fdtmap
31from binman.etype import image_header
Simon Glass07237982020-08-05 13:27:47 -060032from binman.image import Image
Simon Glassbf776672020-04-17 18:09:04 -060033from patman import command
34from patman import test_util
35from patman import tools
36from patman import tout
Simon Glass4f443042016-11-25 20:15:52 -070037
38# Contents of test files, corresponding to different entry types
Simon Glassc6c10e72019-05-17 22:00:46 -060039U_BOOT_DATA = b'1234'
40U_BOOT_IMG_DATA = b'img'
Simon Glasseb0086f2019-08-24 07:23:04 -060041U_BOOT_SPL_DATA = b'56780123456789abcdefghi'
42U_BOOT_TPL_DATA = b'tpl9876543210fedcbazyw'
Simon Glassc6c10e72019-05-17 22:00:46 -060043BLOB_DATA = b'89'
44ME_DATA = b'0abcd'
45VGA_DATA = b'vga'
46U_BOOT_DTB_DATA = b'udtb'
47U_BOOT_SPL_DTB_DATA = b'spldtb'
48U_BOOT_TPL_DTB_DATA = b'tpldtb'
49X86_START16_DATA = b'start16'
50X86_START16_SPL_DATA = b'start16spl'
51X86_START16_TPL_DATA = b'start16tpl'
Simon Glass2250ee62019-08-24 07:22:48 -060052X86_RESET16_DATA = b'reset16'
53X86_RESET16_SPL_DATA = b'reset16spl'
54X86_RESET16_TPL_DATA = b'reset16tpl'
Simon Glassc6c10e72019-05-17 22:00:46 -060055PPC_MPC85XX_BR_DATA = b'ppcmpc85xxbr'
56U_BOOT_NODTB_DATA = b'nodtb with microcode pointer somewhere in here'
57U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here'
58U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here'
59FSP_DATA = b'fsp'
60CMC_DATA = b'cmc'
61VBT_DATA = b'vbt'
62MRC_DATA = b'mrc'
Simon Glassbb748372018-07-17 13:25:33 -060063TEXT_DATA = 'text'
64TEXT_DATA2 = 'text2'
65TEXT_DATA3 = 'text3'
Simon Glassc6c10e72019-05-17 22:00:46 -060066CROS_EC_RW_DATA = b'ecrw'
67GBB_DATA = b'gbbd'
68BMPBLK_DATA = b'bmp'
69VBLOCK_DATA = b'vblk'
70FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
71 b"sorry you're alive\n")
Simon Glassff5c7e32019-07-08 13:18:42 -060072COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
Simon Glassc6c10e72019-05-17 22:00:46 -060073REFCODE_DATA = b'refcode'
Simon Glassea0fff92019-08-24 07:23:07 -060074FSP_M_DATA = b'fsp_m'
Simon Glassbc6a88f2019-10-20 21:31:35 -060075FSP_S_DATA = b'fsp_s'
Simon Glass998d1482019-10-20 21:31:36 -060076FSP_T_DATA = b'fsp_t'
Simon Glassdc2f81a2020-09-01 05:13:58 -060077ATF_BL31_DATA = b'bl31'
Samuel Holland18bd4552020-10-21 21:12:15 -050078SCP_DATA = b'scp'
Simon Glass6cf99532020-09-01 05:13:59 -060079TEST_FDT1_DATA = b'fdt1'
80TEST_FDT2_DATA = b'test-fdt2'
Simon Glassfb91d562020-09-06 10:35:33 -060081ENV_DATA = b'var1=1\nvar2="2"'
Simon Glass6cf99532020-09-01 05:13:59 -060082
83# Subdirectory of the input dir to use to put test FDTs
84TEST_FDT_SUBDIR = 'fdts'
Simon Glassec127af2018-07-17 13:25:39 -060085
Simon Glass6ccbfcd2019-07-20 12:23:47 -060086# The expected size for the device tree in some tests
Simon Glassf667e452019-07-08 14:25:50 -060087EXTRACT_DTB_SIZE = 0x3c9
88
Simon Glass6ccbfcd2019-07-20 12:23:47 -060089# Properties expected to be in the device tree when update_dtb is used
90BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
91
Simon Glass12bb1a92019-07-20 12:23:51 -060092# Extra properties expected to be in the device tree when allow-repack is used
93REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
94
Simon Glass4f443042016-11-25 20:15:52 -070095
96class TestFunctional(unittest.TestCase):
97 """Functional tests for binman
98
99 Most of these use a sample .dts file to build an image and then check
100 that it looks correct. The sample files are in the test/ subdirectory
101 and are numbered.
102
103 For each entry type a very small test file is created using fixed
104 string contents. This makes it easy to test that things look right, and
105 debug problems.
106
107 In some cases a 'real' file must be used - these are also supplied in
108 the test/ diurectory.
109 """
110 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600111 def setUpClass(cls):
Simon Glass4d5994f2017-11-12 21:52:20 -0700112 global entry
Simon Glass16287932020-04-17 18:09:03 -0600113 from binman import entry
Simon Glass4d5994f2017-11-12 21:52:20 -0700114
Simon Glass4f443042016-11-25 20:15:52 -0700115 # Handle the case where argv[0] is 'python'
Simon Glassb986b3b2019-08-24 07:22:43 -0600116 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
117 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
Simon Glass4f443042016-11-25 20:15:52 -0700118
119 # Create a temporary directory for input files
Simon Glassb986b3b2019-08-24 07:22:43 -0600120 cls._indir = tempfile.mkdtemp(prefix='binmant.')
Simon Glass4f443042016-11-25 20:15:52 -0700121
122 # Create some test files
123 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
124 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
125 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glassb8ef5b62018-07-17 13:25:48 -0600126 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700127 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -0700128 TestFunctional._MakeInputFile('me.bin', ME_DATA)
129 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glassb986b3b2019-08-24 07:22:43 -0600130 cls._ResetDtbs()
Simon Glass2250ee62019-08-24 07:22:48 -0600131
Jagdish Gediya9d368f32018-09-03 21:35:08 +0530132 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glass2250ee62019-08-24 07:22:48 -0600133
Simon Glass5e239182019-08-24 07:22:49 -0600134 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
135 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
Simon Glass87722132017-11-12 21:52:26 -0700136 X86_START16_SPL_DATA)
Simon Glass5e239182019-08-24 07:22:49 -0600137 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
Simon Glass35b384c2018-09-14 04:57:10 -0600138 X86_START16_TPL_DATA)
Simon Glass2250ee62019-08-24 07:22:48 -0600139
140 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
141 X86_RESET16_DATA)
142 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
143 X86_RESET16_SPL_DATA)
144 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
145 X86_RESET16_TPL_DATA)
146
Simon Glass4f443042016-11-25 20:15:52 -0700147 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass6b187df2017-11-12 21:52:27 -0700148 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
149 U_BOOT_SPL_NODTB_DATA)
Simon Glassf0253632018-09-14 04:57:32 -0600150 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
151 U_BOOT_TPL_NODTB_DATA)
Simon Glassda229092016-11-25 20:15:56 -0700152 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
153 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Meng59ea8c22017-08-15 22:41:54 -0700154 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassca4f4ff2017-11-12 21:52:28 -0700155 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassec127af2018-07-17 13:25:39 -0600156 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glass0ef87aa2018-07-17 13:25:44 -0600157 TestFunctional._MakeInputDir('devkeys')
158 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass3ae192c2018-10-01 12:22:31 -0600159 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glassea0fff92019-08-24 07:23:07 -0600160 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
Simon Glassbc6a88f2019-10-20 21:31:35 -0600161 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
Simon Glass998d1482019-10-20 21:31:36 -0600162 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700163
Simon Glass53e22bf2019-08-24 07:22:53 -0600164 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
165 elf_test.BuildElfTestFiles(cls._elf_testdir)
166
Simon Glasse0ff8552016-11-25 20:15:53 -0700167 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glassf514d8f2019-08-24 07:22:54 -0600168 TestFunctional._MakeInputFile('u-boot',
169 tools.ReadFile(cls.ElfTestFile('u_boot_ucode_ptr')))
Simon Glasse0ff8552016-11-25 20:15:53 -0700170
171 # Intel flash descriptor file
Simon Glass0ba4b3d2020-07-09 18:39:41 -0600172 cls._SetupDescriptor()
Simon Glasse0ff8552016-11-25 20:15:53 -0700173
Simon Glassb986b3b2019-08-24 07:22:43 -0600174 shutil.copytree(cls.TestFile('files'),
175 os.path.join(cls._indir, 'files'))
Simon Glass0a98b282018-09-14 04:57:28 -0600176
Simon Glass83d73c22018-09-14 04:57:26 -0600177 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
Simon Glassdc2f81a2020-09-01 05:13:58 -0600178 TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
Samuel Holland18bd4552020-10-21 21:12:15 -0500179 TestFunctional._MakeInputFile('scp.bin', SCP_DATA)
Simon Glass83d73c22018-09-14 04:57:26 -0600180
Simon Glass6cf99532020-09-01 05:13:59 -0600181 # Add a few .dtb files for testing
182 TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR,
183 TEST_FDT1_DATA)
184 TestFunctional._MakeInputFile('%s/test-fdt2.dtb' % TEST_FDT_SUBDIR,
185 TEST_FDT2_DATA)
186
Simon Glassfb91d562020-09-06 10:35:33 -0600187 TestFunctional._MakeInputFile('env.txt', ENV_DATA)
188
Simon Glassac62fba2019-07-08 13:18:53 -0600189 # Travis-CI may have an old lz4
Simon Glassb986b3b2019-08-24 07:22:43 -0600190 cls.have_lz4 = True
Simon Glassac62fba2019-07-08 13:18:53 -0600191 try:
192 tools.Run('lz4', '--no-frame-crc', '-c',
Simon Glass3b3e3c02019-10-31 07:42:50 -0600193 os.path.join(cls._indir, 'u-boot.bin'), binary=True)
Simon Glassac62fba2019-07-08 13:18:53 -0600194 except:
Simon Glassb986b3b2019-08-24 07:22:43 -0600195 cls.have_lz4 = False
Simon Glassac62fba2019-07-08 13:18:53 -0600196
Simon Glass4f443042016-11-25 20:15:52 -0700197 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600198 def tearDownClass(cls):
Simon Glass4f443042016-11-25 20:15:52 -0700199 """Remove the temporary input directory and its contents"""
Simon Glassb986b3b2019-08-24 07:22:43 -0600200 if cls.preserve_indir:
201 print('Preserving input dir: %s' % cls._indir)
Simon Glassd5164a72019-07-08 13:18:49 -0600202 else:
Simon Glassb986b3b2019-08-24 07:22:43 -0600203 if cls._indir:
204 shutil.rmtree(cls._indir)
205 cls._indir = None
Simon Glass4f443042016-11-25 20:15:52 -0700206
Simon Glassd5164a72019-07-08 13:18:49 -0600207 @classmethod
Simon Glass8acce602019-07-08 13:18:50 -0600208 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
Simon Glass53cd5d92019-07-08 14:25:29 -0600209 toolpath=None, verbosity=None):
Simon Glassd5164a72019-07-08 13:18:49 -0600210 """Accept arguments controlling test execution
211
212 Args:
213 preserve_indir: Preserve the shared input directory used by all
214 tests in this class.
215 preserve_outdir: Preserve the output directories used by tests. Each
216 test has its own, so this is normally only useful when running a
217 single test.
Simon Glass8acce602019-07-08 13:18:50 -0600218 toolpath: ist of paths to use for tools
Simon Glassd5164a72019-07-08 13:18:49 -0600219 """
220 cls.preserve_indir = preserve_indir
221 cls.preserve_outdirs = preserve_outdirs
Simon Glass8acce602019-07-08 13:18:50 -0600222 cls.toolpath = toolpath
Simon Glass53cd5d92019-07-08 14:25:29 -0600223 cls.verbosity = verbosity
Simon Glassd5164a72019-07-08 13:18:49 -0600224
Simon Glassac62fba2019-07-08 13:18:53 -0600225 def _CheckLz4(self):
226 if not self.have_lz4:
227 self.skipTest('lz4 --no-frame-crc not available')
228
Simon Glassbf574f12019-07-20 12:24:09 -0600229 def _CleanupOutputDir(self):
230 """Remove the temporary output directory"""
231 if self.preserve_outdirs:
232 print('Preserving output dir: %s' % tools.outdir)
233 else:
234 tools._FinaliseForTest()
235
Simon Glass4f443042016-11-25 20:15:52 -0700236 def setUp(self):
237 # Enable this to turn on debugging output
238 # tout.Init(tout.DEBUG)
239 command.test_result = None
240
241 def tearDown(self):
242 """Remove the temporary output directory"""
Simon Glassbf574f12019-07-20 12:24:09 -0600243 self._CleanupOutputDir()
Simon Glass4f443042016-11-25 20:15:52 -0700244
Simon Glassf86a7362019-07-20 12:24:10 -0600245 def _SetupImageInTmpdir(self):
246 """Set up the output image in a new temporary directory
247
248 This is used when an image has been generated in the output directory,
249 but we want to run binman again. This will create a new output
250 directory and fail to delete the original one.
251
252 This creates a new temporary directory, copies the image to it (with a
253 new name) and removes the old output directory.
254
255 Returns:
256 Tuple:
257 Temporary directory to use
258 New image filename
259 """
260 image_fname = tools.GetOutputFilename('image.bin')
261 tmpdir = tempfile.mkdtemp(prefix='binman.')
262 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
263 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
264 self._CleanupOutputDir()
265 return tmpdir, updated_fname
266
Simon Glassb8ef5b62018-07-17 13:25:48 -0600267 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600268 def _ResetDtbs(cls):
Simon Glassb8ef5b62018-07-17 13:25:48 -0600269 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
270 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
271 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
272
Simon Glass4f443042016-11-25 20:15:52 -0700273 def _RunBinman(self, *args, **kwargs):
274 """Run binman using the command line
275
276 Args:
277 Arguments to pass, as a list of strings
278 kwargs: Arguments to pass to Command.RunPipe()
279 """
280 result = command.RunPipe([[self._binman_pathname] + list(args)],
281 capture=True, capture_stderr=True, raise_on_error=False)
282 if result.return_code and kwargs.get('raise_on_error', True):
283 raise Exception("Error running '%s': %s" % (' '.join(args),
284 result.stdout + result.stderr))
285 return result
286
Simon Glass53cd5d92019-07-08 14:25:29 -0600287 def _DoBinman(self, *argv):
Simon Glass4f443042016-11-25 20:15:52 -0700288 """Run binman using directly (in the same process)
289
290 Args:
291 Arguments to pass, as a list of strings
292 Returns:
293 Return value (0 for success)
294 """
Simon Glass53cd5d92019-07-08 14:25:29 -0600295 argv = list(argv)
296 args = cmdline.ParseArgs(argv)
297 args.pager = 'binman-invalid-pager'
298 args.build_dir = self._indir
Simon Glass4f443042016-11-25 20:15:52 -0700299
300 # For testing, you can force an increase in verbosity here
Simon Glass53cd5d92019-07-08 14:25:29 -0600301 # args.verbosity = tout.DEBUG
302 return control.Binman(args)
Simon Glass4f443042016-11-25 20:15:52 -0700303
Simon Glass53af22a2018-07-17 13:25:32 -0600304 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glasseb833d82019-04-25 21:58:34 -0600305 entry_args=None, images=None, use_real_dtb=False,
Simon Glass6cf99532020-09-01 05:13:59 -0600306 verbosity=None, allow_missing=False, extra_indirs=None):
Simon Glass4f443042016-11-25 20:15:52 -0700307 """Run binman with a given test file
308
309 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600310 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600311 debug: True to enable debugging output
Simon Glass3b0c3822018-06-01 09:38:20 -0600312 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600313 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600314 tree before packing it into the image
Simon Glass0bfa7b02018-09-14 04:57:12 -0600315 entry_args: Dict of entry args to supply to binman
316 key: arg name
317 value: value of that arg
318 images: List of image names to build
Simon Glasse9d336d2020-09-01 05:13:55 -0600319 use_real_dtb: True to use the test file as the contents of
320 the u-boot-dtb entry. Normally this is not needed and the
321 test contents (the U_BOOT_DTB_DATA string) can be used.
322 But in some test we need the real contents.
323 verbosity: Verbosity level to use (0-3, None=don't set it)
324 allow_missing: Set the '--allow-missing' flag so that missing
325 external binaries just produce a warning instead of an error
Simon Glass6cf99532020-09-01 05:13:59 -0600326 extra_indirs: Extra input directories to add using -I
Simon Glass4f443042016-11-25 20:15:52 -0700327 """
Simon Glass53cd5d92019-07-08 14:25:29 -0600328 args = []
Simon Glass7fe91732017-11-13 18:55:00 -0700329 if debug:
330 args.append('-D')
Simon Glass53cd5d92019-07-08 14:25:29 -0600331 if verbosity is not None:
332 args.append('-v%d' % verbosity)
333 elif self.verbosity:
334 args.append('-v%d' % self.verbosity)
335 if self.toolpath:
336 for path in self.toolpath:
337 args += ['--toolpath', path]
338 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass3b0c3822018-06-01 09:38:20 -0600339 if map:
340 args.append('-m')
Simon Glass16b8d6b2018-07-06 10:27:42 -0600341 if update_dtb:
Simon Glass2569e102019-07-08 13:18:47 -0600342 args.append('-u')
Simon Glass93d17412018-09-14 04:57:23 -0600343 if not use_real_dtb:
344 args.append('--fake-dtb')
Simon Glass53af22a2018-07-17 13:25:32 -0600345 if entry_args:
Simon Glass50979152019-05-14 15:53:41 -0600346 for arg, value in entry_args.items():
Simon Glass53af22a2018-07-17 13:25:32 -0600347 args.append('-a%s=%s' % (arg, value))
Simon Glass4f9f1052020-07-09 18:39:38 -0600348 if allow_missing:
349 args.append('-M')
Simon Glass0bfa7b02018-09-14 04:57:12 -0600350 if images:
351 for image in images:
352 args += ['-i', image]
Simon Glass6cf99532020-09-01 05:13:59 -0600353 if extra_indirs:
354 for indir in extra_indirs:
355 args += ['-I', indir]
Simon Glass7fe91732017-11-13 18:55:00 -0700356 return self._DoBinman(*args)
Simon Glass4f443042016-11-25 20:15:52 -0700357
358 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glasse0ff8552016-11-25 20:15:53 -0700359 """Set up a new test device-tree file
360
361 The given file is compiled and set up as the device tree to be used
362 for ths test.
363
364 Args:
365 fname: Filename of .dts file to read
Simon Glass7ae5f312018-06-01 09:38:19 -0600366 outfile: Output filename for compiled device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700367
368 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600369 Contents of device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700370 """
Simon Glassa004f292019-07-20 12:23:49 -0600371 tmpdir = tempfile.mkdtemp(prefix='binmant.')
372 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
Simon Glass1d0ebf72019-05-14 15:53:42 -0600373 with open(dtb, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700374 data = fd.read()
375 TestFunctional._MakeInputFile(outfile, data)
Simon Glassa004f292019-07-20 12:23:49 -0600376 shutil.rmtree(tmpdir)
Simon Glasse0e62752018-10-01 21:12:41 -0600377 return data
Simon Glass4f443042016-11-25 20:15:52 -0700378
Simon Glass6ed45ba2018-09-14 04:57:24 -0600379 def _GetDtbContentsForSplTpl(self, dtb_data, name):
380 """Create a version of the main DTB for SPL or SPL
381
382 For testing we don't actually have different versions of the DTB. With
383 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
384 we don't normally have any unwanted nodes.
385
386 We still want the DTBs for SPL and TPL to be different though, since
387 otherwise it is confusing to know which one we are looking at. So add
388 an 'spl' or 'tpl' property to the top-level node.
Simon Glasse9d336d2020-09-01 05:13:55 -0600389
390 Args:
391 dtb_data: dtb data to modify (this should be a value devicetree)
392 name: Name of a new property to add
393
394 Returns:
395 New dtb data with the property added
Simon Glass6ed45ba2018-09-14 04:57:24 -0600396 """
397 dtb = fdt.Fdt.FromData(dtb_data)
398 dtb.Scan()
399 dtb.GetNode('/binman').AddZeroProp(name)
400 dtb.Sync(auto_resize=True)
401 dtb.Pack()
402 return dtb.GetContents()
403
Simon Glass16b8d6b2018-07-06 10:27:42 -0600404 def _DoReadFileDtb(self, fname, use_real_dtb=False, map=False,
Simon Glass6cf99532020-09-01 05:13:59 -0600405 update_dtb=False, entry_args=None, reset_dtbs=True,
406 extra_indirs=None):
Simon Glass4f443042016-11-25 20:15:52 -0700407 """Run binman and return the resulting image
408
409 This runs binman with a given test file and then reads the resulting
410 output file. It is a shortcut function since most tests need to do
411 these steps.
412
413 Raises an assertion failure if binman returns a non-zero exit code.
414
415 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600416 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass4f443042016-11-25 20:15:52 -0700417 use_real_dtb: True to use the test file as the contents of
418 the u-boot-dtb entry. Normally this is not needed and the
419 test contents (the U_BOOT_DTB_DATA string) can be used.
420 But in some test we need the real contents.
Simon Glass3b0c3822018-06-01 09:38:20 -0600421 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600422 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600423 tree before packing it into the image
Simon Glasse9d336d2020-09-01 05:13:55 -0600424 entry_args: Dict of entry args to supply to binman
425 key: arg name
426 value: value of that arg
427 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
428 function. If reset_dtbs is True, then the original test dtb
429 is written back before this function finishes
Simon Glass6cf99532020-09-01 05:13:59 -0600430 extra_indirs: Extra input directories to add using -I
Simon Glasse0ff8552016-11-25 20:15:53 -0700431
432 Returns:
433 Tuple:
434 Resulting image contents
435 Device tree contents
Simon Glass3b0c3822018-06-01 09:38:20 -0600436 Map data showing contents of image (or None if none)
Simon Glassea6922e2018-07-17 13:25:27 -0600437 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass4f443042016-11-25 20:15:52 -0700438 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700439 dtb_data = None
Simon Glass4f443042016-11-25 20:15:52 -0700440 # Use the compiled test file as the u-boot-dtb input
441 if use_real_dtb:
Simon Glasse0ff8552016-11-25 20:15:53 -0700442 dtb_data = self._SetupDtb(fname)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600443
444 # For testing purposes, make a copy of the DT for SPL and TPL. Add
445 # a node indicating which it is, so aid verification.
446 for name in ['spl', 'tpl']:
447 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
448 outfile = os.path.join(self._indir, dtb_fname)
449 TestFunctional._MakeInputFile(dtb_fname,
450 self._GetDtbContentsForSplTpl(dtb_data, name))
Simon Glass4f443042016-11-25 20:15:52 -0700451
452 try:
Simon Glass53af22a2018-07-17 13:25:32 -0600453 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glass6cf99532020-09-01 05:13:59 -0600454 entry_args=entry_args, use_real_dtb=use_real_dtb,
455 extra_indirs=extra_indirs)
Simon Glass4f443042016-11-25 20:15:52 -0700456 self.assertEqual(0, retcode)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600457 out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
Simon Glass4f443042016-11-25 20:15:52 -0700458
459 # Find the (only) image, read it and return its contents
460 image = control.images['image']
Simon Glass16b8d6b2018-07-06 10:27:42 -0600461 image_fname = tools.GetOutputFilename('image.bin')
462 self.assertTrue(os.path.exists(image_fname))
Simon Glass3b0c3822018-06-01 09:38:20 -0600463 if map:
464 map_fname = tools.GetOutputFilename('image.map')
465 with open(map_fname) as fd:
466 map_data = fd.read()
467 else:
468 map_data = None
Simon Glass1d0ebf72019-05-14 15:53:42 -0600469 with open(image_fname, 'rb') as fd:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600470 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass4f443042016-11-25 20:15:52 -0700471 finally:
472 # Put the test file back
Simon Glass6ed45ba2018-09-14 04:57:24 -0600473 if reset_dtbs and use_real_dtb:
Simon Glassb8ef5b62018-07-17 13:25:48 -0600474 self._ResetDtbs()
Simon Glass4f443042016-11-25 20:15:52 -0700475
Simon Glass3c081312019-07-08 14:25:26 -0600476 def _DoReadFileRealDtb(self, fname):
477 """Run binman with a real .dtb file and return the resulting data
478
479 Args:
480 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
481
482 Returns:
483 Resulting image contents
484 """
485 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
486
Simon Glasse0ff8552016-11-25 20:15:53 -0700487 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass7ae5f312018-06-01 09:38:19 -0600488 """Helper function which discards the device-tree binary
489
490 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600491 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600492 use_real_dtb: True to use the test file as the contents of
493 the u-boot-dtb entry. Normally this is not needed and the
494 test contents (the U_BOOT_DTB_DATA string) can be used.
495 But in some test we need the real contents.
Simon Glassea6922e2018-07-17 13:25:27 -0600496
497 Returns:
498 Resulting image contents
Simon Glass7ae5f312018-06-01 09:38:19 -0600499 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700500 return self._DoReadFileDtb(fname, use_real_dtb)[0]
501
Simon Glass4f443042016-11-25 20:15:52 -0700502 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600503 def _MakeInputFile(cls, fname, contents):
Simon Glass4f443042016-11-25 20:15:52 -0700504 """Create a new test input file, creating directories as needed
505
506 Args:
Simon Glass3ab95982018-08-01 15:22:37 -0600507 fname: Filename to create
Simon Glass4f443042016-11-25 20:15:52 -0700508 contents: File contents to write in to the file
509 Returns:
510 Full pathname of file created
511 """
Simon Glassb986b3b2019-08-24 07:22:43 -0600512 pathname = os.path.join(cls._indir, fname)
Simon Glass4f443042016-11-25 20:15:52 -0700513 dirname = os.path.dirname(pathname)
514 if dirname and not os.path.exists(dirname):
515 os.makedirs(dirname)
516 with open(pathname, 'wb') as fd:
517 fd.write(contents)
518 return pathname
519
520 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600521 def _MakeInputDir(cls, dirname):
Simon Glass0ef87aa2018-07-17 13:25:44 -0600522 """Create a new test input directory, creating directories as needed
523
524 Args:
525 dirname: Directory name to create
526
527 Returns:
528 Full pathname of directory created
529 """
Simon Glassb986b3b2019-08-24 07:22:43 -0600530 pathname = os.path.join(cls._indir, dirname)
Simon Glass0ef87aa2018-07-17 13:25:44 -0600531 if not os.path.exists(pathname):
532 os.makedirs(pathname)
533 return pathname
534
535 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600536 def _SetupSplElf(cls, src_fname='bss_data'):
Simon Glass11ae93e2018-10-01 21:12:47 -0600537 """Set up an ELF file with a '_dt_ucode_base_size' symbol
538
539 Args:
540 Filename of ELF file to use as SPL
541 """
Simon Glassc9a0b272019-08-24 07:22:59 -0600542 TestFunctional._MakeInputFile('spl/u-boot-spl',
543 tools.ReadFile(cls.ElfTestFile(src_fname)))
Simon Glass11ae93e2018-10-01 21:12:47 -0600544
545 @classmethod
Simon Glass2090f1e2019-08-24 07:23:00 -0600546 def _SetupTplElf(cls, src_fname='bss_data'):
547 """Set up an ELF file with a '_dt_ucode_base_size' symbol
548
549 Args:
550 Filename of ELF file to use as TPL
551 """
552 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
553 tools.ReadFile(cls.ElfTestFile(src_fname)))
554
555 @classmethod
Simon Glass0ba4b3d2020-07-09 18:39:41 -0600556 def _SetupDescriptor(cls):
557 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
558 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
559
560 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600561 def TestFile(cls, fname):
562 return os.path.join(cls._binman_dir, 'test', fname)
Simon Glass4f443042016-11-25 20:15:52 -0700563
Simon Glass53e22bf2019-08-24 07:22:53 -0600564 @classmethod
565 def ElfTestFile(cls, fname):
566 return os.path.join(cls._elf_testdir, fname)
567
Simon Glass4f443042016-11-25 20:15:52 -0700568 def AssertInList(self, grep_list, target):
569 """Assert that at least one of a list of things is in a target
570
571 Args:
572 grep_list: List of strings to check
573 target: Target string
574 """
575 for grep in grep_list:
576 if grep in target:
577 return
Simon Glass1fc62de2019-05-17 22:00:50 -0600578 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass4f443042016-11-25 20:15:52 -0700579
580 def CheckNoGaps(self, entries):
581 """Check that all entries fit together without gaps
582
583 Args:
584 entries: List of entries to check
585 """
Simon Glass3ab95982018-08-01 15:22:37 -0600586 offset = 0
Simon Glass4f443042016-11-25 20:15:52 -0700587 for entry in entries.values():
Simon Glass3ab95982018-08-01 15:22:37 -0600588 self.assertEqual(offset, entry.offset)
589 offset += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700590
Simon Glasse0ff8552016-11-25 20:15:53 -0700591 def GetFdtLen(self, dtb):
Simon Glass7ae5f312018-06-01 09:38:19 -0600592 """Get the totalsize field from a device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700593
594 Args:
Simon Glass7ae5f312018-06-01 09:38:19 -0600595 dtb: Device-tree binary contents
Simon Glasse0ff8552016-11-25 20:15:53 -0700596
597 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600598 Total size of device-tree binary, from the header
Simon Glasse0ff8552016-11-25 20:15:53 -0700599 """
600 return struct.unpack('>L', dtb[4:8])[0]
601
Simon Glass086cec92019-07-08 14:25:27 -0600602 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glass16b8d6b2018-07-06 10:27:42 -0600603 def AddNode(node, path):
604 if node.name != '/':
605 path += '/' + node.name
Simon Glass086cec92019-07-08 14:25:27 -0600606 for prop in node.props.values():
607 if prop.name in prop_names:
608 prop_path = path + ':' + prop.name
609 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
610 prop.value)
Simon Glass16b8d6b2018-07-06 10:27:42 -0600611 for subnode in node.subnodes:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600612 AddNode(subnode, path)
613
614 tree = {}
Simon Glass16b8d6b2018-07-06 10:27:42 -0600615 AddNode(dtb.GetRoot(), '')
616 return tree
617
Simon Glass4f443042016-11-25 20:15:52 -0700618 def testRun(self):
619 """Test a basic run with valid args"""
620 result = self._RunBinman('-h')
621
622 def testFullHelp(self):
623 """Test that the full help is displayed with -H"""
624 result = self._RunBinman('-H')
625 help_file = os.path.join(self._binman_dir, 'README')
Tom Rini3759df02018-01-16 15:29:50 -0500626 # Remove possible extraneous strings
627 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
628 gothelp = result.stdout.replace(extra, '')
629 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass4f443042016-11-25 20:15:52 -0700630 self.assertEqual(0, len(result.stderr))
631 self.assertEqual(0, result.return_code)
632
633 def testFullHelpInternal(self):
634 """Test that the full help is displayed with -H"""
635 try:
636 command.test_result = command.CommandResult()
637 result = self._DoBinman('-H')
638 help_file = os.path.join(self._binman_dir, 'README')
639 finally:
640 command.test_result = None
641
642 def testHelp(self):
643 """Test that the basic help is displayed with -h"""
644 result = self._RunBinman('-h')
645 self.assertTrue(len(result.stdout) > 200)
646 self.assertEqual(0, len(result.stderr))
647 self.assertEqual(0, result.return_code)
648
Simon Glass4f443042016-11-25 20:15:52 -0700649 def testBoard(self):
650 """Test that we can run it with a specific board"""
Simon Glass741f2d62018-10-01 12:22:30 -0600651 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass4f443042016-11-25 20:15:52 -0700652 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glass53cd5d92019-07-08 14:25:29 -0600653 result = self._DoBinman('build', '-b', 'sandbox')
Simon Glass4f443042016-11-25 20:15:52 -0700654 self.assertEqual(0, result)
655
656 def testNeedBoard(self):
657 """Test that we get an error when no board ius supplied"""
658 with self.assertRaises(ValueError) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600659 result = self._DoBinman('build')
Simon Glass4f443042016-11-25 20:15:52 -0700660 self.assertIn("Must provide a board to process (use -b <board>)",
661 str(e.exception))
662
663 def testMissingDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600664 """Test that an invalid device-tree file generates an error"""
Simon Glass4f443042016-11-25 20:15:52 -0700665 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600666 self._RunBinman('build', '-d', 'missing_file')
Simon Glass4f443042016-11-25 20:15:52 -0700667 # We get one error from libfdt, and a different one from fdtget.
668 self.AssertInList(["Couldn't open blob from 'missing_file'",
669 'No such file or directory'], str(e.exception))
670
671 def testBrokenDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600672 """Test that an invalid device-tree source file generates an error
Simon Glass4f443042016-11-25 20:15:52 -0700673
674 Since this is a source file it should be compiled and the error
675 will come from the device-tree compiler (dtc).
676 """
677 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600678 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700679 self.assertIn("FATAL ERROR: Unable to parse input tree",
680 str(e.exception))
681
682 def testMissingNode(self):
683 """Test that a device tree without a 'binman' node generates an error"""
684 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600685 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700686 self.assertIn("does not have a 'binman' node", str(e.exception))
687
688 def testEmpty(self):
689 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glass53cd5d92019-07-08 14:25:29 -0600690 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700691 self.assertEqual(0, len(result.stderr))
692 self.assertEqual(0, result.return_code)
693
694 def testInvalidEntry(self):
695 """Test that an invalid entry is flagged"""
696 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600697 result = self._RunBinman('build', '-d',
Simon Glass741f2d62018-10-01 12:22:30 -0600698 self.TestFile('004_invalid_entry.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700699 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
700 "'/binman/not-a-valid-type'", str(e.exception))
701
702 def testSimple(self):
703 """Test a simple binman with a single file"""
Simon Glass741f2d62018-10-01 12:22:30 -0600704 data = self._DoReadFile('005_simple.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700705 self.assertEqual(U_BOOT_DATA, data)
706
Simon Glass7fe91732017-11-13 18:55:00 -0700707 def testSimpleDebug(self):
708 """Test a simple binman run with debugging enabled"""
Simon Glasse2705fa2019-07-08 14:25:53 -0600709 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass7fe91732017-11-13 18:55:00 -0700710
Simon Glass4f443042016-11-25 20:15:52 -0700711 def testDual(self):
712 """Test that we can handle creating two images
713
714 This also tests image padding.
715 """
Simon Glass741f2d62018-10-01 12:22:30 -0600716 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700717 self.assertEqual(0, retcode)
718
719 image = control.images['image1']
Simon Glass8beb11e2019-07-08 14:25:47 -0600720 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700721 fname = tools.GetOutputFilename('image1.bin')
722 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600723 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700724 data = fd.read()
725 self.assertEqual(U_BOOT_DATA, data)
726
727 image = control.images['image2']
Simon Glass8beb11e2019-07-08 14:25:47 -0600728 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700729 fname = tools.GetOutputFilename('image2.bin')
730 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600731 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700732 data = fd.read()
733 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glasse6d85ff2019-05-14 15:53:47 -0600734 self.assertEqual(tools.GetBytes(0, 3), data[:3])
735 self.assertEqual(tools.GetBytes(0, 5), data[7:])
Simon Glass4f443042016-11-25 20:15:52 -0700736
737 def testBadAlign(self):
738 """Test that an invalid alignment value is detected"""
739 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600740 self._DoTestFile('007_bad_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700741 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
742 "of two", str(e.exception))
743
744 def testPackSimple(self):
745 """Test that packing works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600746 retcode = self._DoTestFile('008_pack.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700747 self.assertEqual(0, retcode)
748 self.assertIn('image', control.images)
749 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600750 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700751 self.assertEqual(5, len(entries))
752
753 # First u-boot
754 self.assertIn('u-boot', entries)
755 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600756 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700757 self.assertEqual(len(U_BOOT_DATA), entry.size)
758
759 # Second u-boot, aligned to 16-byte boundary
760 self.assertIn('u-boot-align', entries)
761 entry = entries['u-boot-align']
Simon Glass3ab95982018-08-01 15:22:37 -0600762 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700763 self.assertEqual(len(U_BOOT_DATA), entry.size)
764
765 # Third u-boot, size 23 bytes
766 self.assertIn('u-boot-size', entries)
767 entry = entries['u-boot-size']
Simon Glass3ab95982018-08-01 15:22:37 -0600768 self.assertEqual(20, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700769 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
770 self.assertEqual(23, entry.size)
771
772 # Fourth u-boot, placed immediate after the above
773 self.assertIn('u-boot-next', entries)
774 entry = entries['u-boot-next']
Simon Glass3ab95982018-08-01 15:22:37 -0600775 self.assertEqual(43, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700776 self.assertEqual(len(U_BOOT_DATA), entry.size)
777
Simon Glass3ab95982018-08-01 15:22:37 -0600778 # Fifth u-boot, placed at a fixed offset
Simon Glass4f443042016-11-25 20:15:52 -0700779 self.assertIn('u-boot-fixed', entries)
780 entry = entries['u-boot-fixed']
Simon Glass3ab95982018-08-01 15:22:37 -0600781 self.assertEqual(61, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700782 self.assertEqual(len(U_BOOT_DATA), entry.size)
783
Simon Glass8beb11e2019-07-08 14:25:47 -0600784 self.assertEqual(65, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700785
786 def testPackExtra(self):
787 """Test that extra packing feature works as expected"""
Simon Glass4eec34c2020-10-26 17:40:10 -0600788 data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
789 update_dtb=True)
Simon Glass4f443042016-11-25 20:15:52 -0700790
Simon Glass4f443042016-11-25 20:15:52 -0700791 self.assertIn('image', control.images)
792 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600793 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700794 self.assertEqual(5, len(entries))
795
796 # First u-boot with padding before and after
797 self.assertIn('u-boot', entries)
798 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600799 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700800 self.assertEqual(3, entry.pad_before)
801 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600802 self.assertEqual(U_BOOT_DATA, entry.data)
803 self.assertEqual(tools.GetBytes(0, 3) + U_BOOT_DATA +
804 tools.GetBytes(0, 5), data[:entry.size])
805 pos = entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700806
807 # Second u-boot has an aligned size, but it has no effect
808 self.assertIn('u-boot-align-size-nop', entries)
809 entry = entries['u-boot-align-size-nop']
Simon Glassef439ed2020-10-26 17:40:08 -0600810 self.assertEqual(pos, entry.offset)
811 self.assertEqual(len(U_BOOT_DATA), entry.size)
812 self.assertEqual(U_BOOT_DATA, entry.data)
813 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
814 pos += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700815
816 # Third u-boot has an aligned size too
817 self.assertIn('u-boot-align-size', entries)
818 entry = entries['u-boot-align-size']
Simon Glassef439ed2020-10-26 17:40:08 -0600819 self.assertEqual(pos, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700820 self.assertEqual(32, entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600821 self.assertEqual(U_BOOT_DATA, entry.data)
822 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 32 - len(U_BOOT_DATA)),
823 data[pos:pos + entry.size])
824 pos += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700825
826 # Fourth u-boot has an aligned end
827 self.assertIn('u-boot-align-end', entries)
828 entry = entries['u-boot-align-end']
Simon Glass3ab95982018-08-01 15:22:37 -0600829 self.assertEqual(48, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700830 self.assertEqual(16, entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600831 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
832 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 16 - len(U_BOOT_DATA)),
833 data[pos:pos + entry.size])
834 pos += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700835
836 # Fifth u-boot immediately afterwards
837 self.assertIn('u-boot-align-both', entries)
838 entry = entries['u-boot-align-both']
Simon Glass3ab95982018-08-01 15:22:37 -0600839 self.assertEqual(64, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700840 self.assertEqual(64, entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600841 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
842 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 64 - len(U_BOOT_DATA)),
843 data[pos:pos + entry.size])
Simon Glass4f443042016-11-25 20:15:52 -0700844
845 self.CheckNoGaps(entries)
Simon Glass8beb11e2019-07-08 14:25:47 -0600846 self.assertEqual(128, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700847
Simon Glass4eec34c2020-10-26 17:40:10 -0600848 dtb = fdt.Fdt(out_dtb_fname)
849 dtb.Scan()
850 props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
851 expected = {
852 'image-pos': 0,
853 'offset': 0,
854 'size': 128,
855
856 'u-boot:image-pos': 0,
857 'u-boot:offset': 0,
858 'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
859
860 'u-boot-align-size-nop:image-pos': 12,
861 'u-boot-align-size-nop:offset': 12,
862 'u-boot-align-size-nop:size': 4,
863
864 'u-boot-align-size:image-pos': 16,
865 'u-boot-align-size:offset': 16,
866 'u-boot-align-size:size': 32,
867
868 'u-boot-align-end:image-pos': 48,
869 'u-boot-align-end:offset': 48,
870 'u-boot-align-end:size': 16,
871
872 'u-boot-align-both:image-pos': 64,
873 'u-boot-align-both:offset': 64,
874 'u-boot-align-both:size': 64,
875 }
876 self.assertEqual(expected, props)
877
Simon Glass4f443042016-11-25 20:15:52 -0700878 def testPackAlignPowerOf2(self):
879 """Test that invalid entry alignment is detected"""
880 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600881 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700882 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
883 "of two", str(e.exception))
884
885 def testPackAlignSizePowerOf2(self):
886 """Test that invalid entry size alignment is detected"""
887 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600888 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700889 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
890 "power of two", str(e.exception))
891
892 def testPackInvalidAlign(self):
Simon Glass3ab95982018-08-01 15:22:37 -0600893 """Test detection of an offset that does not match its alignment"""
Simon Glass4f443042016-11-25 20:15:52 -0700894 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600895 self._DoTestFile('012_pack_inv_align.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600896 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700897 "align 0x4 (4)", str(e.exception))
898
899 def testPackInvalidSizeAlign(self):
900 """Test that invalid entry size alignment is detected"""
901 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600902 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700903 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
904 "align-size 0x4 (4)", str(e.exception))
905
906 def testPackOverlap(self):
907 """Test that overlapping regions are detected"""
908 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600909 self._DoTestFile('014_pack_overlap.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600910 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -0700911 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
912 str(e.exception))
913
914 def testPackEntryOverflow(self):
915 """Test that entries that overflow their size are detected"""
916 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600917 self._DoTestFile('015_pack_overflow.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700918 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
919 "but entry size is 0x3 (3)", str(e.exception))
920
921 def testPackImageOverflow(self):
922 """Test that entries which overflow the image size are detected"""
923 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600924 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600925 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass4f443042016-11-25 20:15:52 -0700926 "size 0x3 (3)", str(e.exception))
927
928 def testPackImageSize(self):
929 """Test that the image size can be set"""
Simon Glass741f2d62018-10-01 12:22:30 -0600930 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700931 self.assertEqual(0, retcode)
932 self.assertIn('image', control.images)
933 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -0600934 self.assertEqual(7, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700935
936 def testPackImageSizeAlign(self):
937 """Test that image size alignemnt works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600938 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700939 self.assertEqual(0, retcode)
940 self.assertIn('image', control.images)
941 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -0600942 self.assertEqual(16, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700943
944 def testPackInvalidImageAlign(self):
945 """Test that invalid image alignment is detected"""
946 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600947 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600948 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700949 "align-size 0x8 (8)", str(e.exception))
950
951 def testPackAlignPowerOf2(self):
952 """Test that invalid image alignment is detected"""
953 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600954 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -0600955 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass4f443042016-11-25 20:15:52 -0700956 "two", str(e.exception))
957
958 def testImagePadByte(self):
959 """Test that the image pad byte can be specified"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600960 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600961 data = self._DoReadFile('021_image_pad.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -0600962 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0xff, 1) +
963 U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -0700964
965 def testImageName(self):
966 """Test that image files can be named"""
Simon Glass741f2d62018-10-01 12:22:30 -0600967 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700968 self.assertEqual(0, retcode)
969 image = control.images['image1']
970 fname = tools.GetOutputFilename('test-name')
971 self.assertTrue(os.path.exists(fname))
972
973 image = control.images['image2']
974 fname = tools.GetOutputFilename('test-name.xx')
975 self.assertTrue(os.path.exists(fname))
976
977 def testBlobFilename(self):
978 """Test that generic blobs can be provided by filename"""
Simon Glass741f2d62018-10-01 12:22:30 -0600979 data = self._DoReadFile('023_blob.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700980 self.assertEqual(BLOB_DATA, data)
981
982 def testPackSorted(self):
983 """Test that entries can be sorted"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600984 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600985 data = self._DoReadFile('024_sorted.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -0600986 self.assertEqual(tools.GetBytes(0, 1) + U_BOOT_SPL_DATA +
987 tools.GetBytes(0, 2) + U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -0700988
Simon Glass3ab95982018-08-01 15:22:37 -0600989 def testPackZeroOffset(self):
990 """Test that an entry at offset 0 is not given a new offset"""
Simon Glass4f443042016-11-25 20:15:52 -0700991 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600992 self._DoTestFile('025_pack_zero_size.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600993 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -0700994 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
995 str(e.exception))
996
997 def testPackUbootDtb(self):
998 """Test that a device tree can be added to U-Boot"""
Simon Glass741f2d62018-10-01 12:22:30 -0600999 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001000 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glasse0ff8552016-11-25 20:15:53 -07001001
1002 def testPackX86RomNoSize(self):
1003 """Test that the end-at-4gb property requires a size property"""
1004 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001005 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -06001006 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glasse0ff8552016-11-25 20:15:53 -07001007 "using end-at-4gb", str(e.exception))
1008
Jagdish Gediya94b57db2018-09-03 21:35:07 +05301009 def test4gbAndSkipAtStartTogether(self):
1010 """Test that the end-at-4gb and skip-at-size property can't be used
1011 together"""
1012 with self.assertRaises(ValueError) as e:
Simon Glassdfdd2b62019-08-24 07:23:02 -06001013 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -06001014 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya94b57db2018-09-03 21:35:07 +05301015 "'skip-at-start'", str(e.exception))
1016
Simon Glasse0ff8552016-11-25 20:15:53 -07001017 def testPackX86RomOutside(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001018 """Test that the end-at-4gb property checks for offset boundaries"""
Simon Glasse0ff8552016-11-25 20:15:53 -07001019 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001020 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glasse6bed4f2020-10-26 17:40:05 -06001021 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
1022 "is outside the section '/binman' starting at "
1023 '0xffffffe0 (4294967264) of size 0x20 (32)',
Simon Glasse0ff8552016-11-25 20:15:53 -07001024 str(e.exception))
1025
1026 def testPackX86Rom(self):
1027 """Test that a basic x86 ROM can be created"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001028 self._SetupSplElf()
Simon Glass9255f3c2019-08-24 07:23:01 -06001029 data = self._DoReadFile('029_x86_rom.dts')
Simon Glasseb0086f2019-08-24 07:23:04 -06001030 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 3) + U_BOOT_SPL_DATA +
Simon Glasse6d85ff2019-05-14 15:53:47 -06001031 tools.GetBytes(0, 2), data)
Simon Glasse0ff8552016-11-25 20:15:53 -07001032
1033 def testPackX86RomMeNoDesc(self):
1034 """Test that an invalid Intel descriptor entry is detected"""
Simon Glass0ba4b3d2020-07-09 18:39:41 -06001035 try:
Simon Glass52b10dd2020-07-25 15:11:19 -06001036 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
Simon Glass0ba4b3d2020-07-09 18:39:41 -06001037 with self.assertRaises(ValueError) as e:
Simon Glass52b10dd2020-07-25 15:11:19 -06001038 self._DoTestFile('163_x86_rom_me_empty.dts')
Simon Glass0ba4b3d2020-07-09 18:39:41 -06001039 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1040 str(e.exception))
1041 finally:
1042 self._SetupDescriptor()
Simon Glasse0ff8552016-11-25 20:15:53 -07001043
1044 def testPackX86RomBadDesc(self):
1045 """Test that the Intel requires a descriptor entry"""
1046 with self.assertRaises(ValueError) as e:
Simon Glass9255f3c2019-08-24 07:23:01 -06001047 self._DoTestFile('030_x86_rom_me_no_desc.dts')
Simon Glass3ab95982018-08-01 15:22:37 -06001048 self.assertIn("Node '/binman/intel-me': No offset set with "
1049 "offset-unset: should another entry provide this correct "
1050 "offset?", str(e.exception))
Simon Glasse0ff8552016-11-25 20:15:53 -07001051
1052 def testPackX86RomMe(self):
1053 """Test that an x86 ROM with an ME region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001054 data = self._DoReadFile('031_x86_rom_me.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06001055 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
1056 if data[:0x1000] != expected_desc:
1057 self.fail('Expected descriptor binary at start of image')
Simon Glasse0ff8552016-11-25 20:15:53 -07001058 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1059
1060 def testPackVga(self):
1061 """Test that an image with a VGA binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001062 data = self._DoReadFile('032_intel_vga.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -07001063 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1064
1065 def testPackStart16(self):
1066 """Test that an image with an x86 start16 region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001067 data = self._DoReadFile('033_x86_start16.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -07001068 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1069
Jagdish Gediya9d368f32018-09-03 21:35:08 +05301070 def testPackPowerpcMpc85xxBootpgResetvec(self):
1071 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1072 created"""
Simon Glassdfdd2b62019-08-24 07:23:02 -06001073 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
Jagdish Gediya9d368f32018-09-03 21:35:08 +05301074 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1075
Simon Glass736bb0a2018-07-06 10:27:17 -06001076 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glassadc57012018-07-06 10:27:16 -06001077 """Handle running a test for insertion of microcode
1078
1079 Args:
1080 dts_fname: Name of test .dts file
1081 nodtb_data: Data that we expect in the first section
Simon Glass736bb0a2018-07-06 10:27:17 -06001082 ucode_second: True if the microsecond entry is second instead of
1083 third
Simon Glassadc57012018-07-06 10:27:16 -06001084
1085 Returns:
1086 Tuple:
1087 Contents of first region (U-Boot or SPL)
Simon Glass3ab95982018-08-01 15:22:37 -06001088 Offset and size components of microcode pointer, as inserted
Simon Glassadc57012018-07-06 10:27:16 -06001089 in the above (two 4-byte words)
1090 """
Simon Glass6b187df2017-11-12 21:52:27 -07001091 data = self._DoReadFile(dts_fname, True)
Simon Glasse0ff8552016-11-25 20:15:53 -07001092
1093 # Now check the device tree has no microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001094 if ucode_second:
1095 ucode_content = data[len(nodtb_data):]
1096 ucode_pos = len(nodtb_data)
1097 dtb_with_ucode = ucode_content[16:]
1098 fdt_len = self.GetFdtLen(dtb_with_ucode)
1099 else:
1100 dtb_with_ucode = data[len(nodtb_data):]
1101 fdt_len = self.GetFdtLen(dtb_with_ucode)
1102 ucode_content = dtb_with_ucode[fdt_len:]
1103 ucode_pos = len(nodtb_data) + fdt_len
Simon Glasse0ff8552016-11-25 20:15:53 -07001104 fname = tools.GetOutputFilename('test.dtb')
1105 with open(fname, 'wb') as fd:
Simon Glassadc57012018-07-06 10:27:16 -06001106 fd.write(dtb_with_ucode)
Simon Glassec3f3782017-05-27 07:38:29 -06001107 dtb = fdt.FdtScan(fname)
1108 ucode = dtb.GetNode('/microcode')
Simon Glasse0ff8552016-11-25 20:15:53 -07001109 self.assertTrue(ucode)
1110 for node in ucode.subnodes:
1111 self.assertFalse(node.props.get('data'))
1112
Simon Glasse0ff8552016-11-25 20:15:53 -07001113 # Check that the microcode appears immediately after the Fdt
1114 # This matches the concatenation of the data properties in
Simon Glass87722132017-11-12 21:52:26 -07001115 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glasse0ff8552016-11-25 20:15:53 -07001116 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1117 0x78235609)
Simon Glassadc57012018-07-06 10:27:16 -06001118 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glasse0ff8552016-11-25 20:15:53 -07001119
1120 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -06001121 # expected offset and size
Simon Glasse0ff8552016-11-25 20:15:53 -07001122 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1123 len(ucode_data))
Simon Glass736bb0a2018-07-06 10:27:17 -06001124 u_boot = data[:len(nodtb_data)]
1125 return u_boot, pos_and_size
Simon Glass6b187df2017-11-12 21:52:27 -07001126
1127 def testPackUbootMicrocode(self):
1128 """Test that x86 microcode can be handled correctly
1129
1130 We expect to see the following in the image, in order:
1131 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1132 place
1133 u-boot.dtb with the microcode removed
1134 the microcode
1135 """
Simon Glass741f2d62018-10-01 12:22:30 -06001136 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass6b187df2017-11-12 21:52:27 -07001137 U_BOOT_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001138 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1139 b' somewhere in here', first)
Simon Glasse0ff8552016-11-25 20:15:53 -07001140
Simon Glass160a7662017-05-27 07:38:26 -06001141 def _RunPackUbootSingleMicrocode(self):
Simon Glasse0ff8552016-11-25 20:15:53 -07001142 """Test that x86 microcode can be handled correctly
1143
1144 We expect to see the following in the image, in order:
1145 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1146 place
1147 u-boot.dtb with the microcode
1148 an empty microcode region
1149 """
1150 # We need the libfdt library to run this test since only that allows
1151 # finding the offset of a property. This is required by
1152 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass741f2d62018-10-01 12:22:30 -06001153 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glasse0ff8552016-11-25 20:15:53 -07001154
1155 second = data[len(U_BOOT_NODTB_DATA):]
1156
1157 fdt_len = self.GetFdtLen(second)
1158 third = second[fdt_len:]
1159 second = second[:fdt_len]
1160
Simon Glass160a7662017-05-27 07:38:26 -06001161 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1162 self.assertIn(ucode_data, second)
1163 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -07001164
Simon Glass160a7662017-05-27 07:38:26 -06001165 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -06001166 # expected offset and size
Simon Glass160a7662017-05-27 07:38:26 -06001167 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1168 len(ucode_data))
1169 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glassc6c10e72019-05-17 22:00:46 -06001170 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1171 b' somewhere in here', first)
Simon Glassc49deb82016-11-25 20:15:54 -07001172
Simon Glass75db0862016-11-25 20:15:55 -07001173 def testPackUbootSingleMicrocode(self):
1174 """Test that x86 microcode can be handled correctly with fdt_normal.
1175 """
Simon Glass160a7662017-05-27 07:38:26 -06001176 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001177
Simon Glassc49deb82016-11-25 20:15:54 -07001178 def testUBootImg(self):
1179 """Test that u-boot.img can be put in a file"""
Simon Glass741f2d62018-10-01 12:22:30 -06001180 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glassc49deb82016-11-25 20:15:54 -07001181 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glass75db0862016-11-25 20:15:55 -07001182
1183 def testNoMicrocode(self):
1184 """Test that a missing microcode region is detected"""
1185 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001186 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001187 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1188 "node found in ", str(e.exception))
1189
1190 def testMicrocodeWithoutNode(self):
1191 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1192 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001193 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001194 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1195 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1196
1197 def testMicrocodeWithoutNode2(self):
1198 """Test that a missing u-boot-ucode node is detected"""
1199 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001200 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001201 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1202 "microcode region u-boot-ucode", str(e.exception))
1203
1204 def testMicrocodeWithoutPtrInElf(self):
1205 """Test that a U-Boot binary without the microcode symbol is detected"""
1206 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glass75db0862016-11-25 20:15:55 -07001207 try:
Simon Glassbccd91d2019-08-24 07:22:55 -06001208 TestFunctional._MakeInputFile('u-boot',
1209 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass75db0862016-11-25 20:15:55 -07001210
1211 with self.assertRaises(ValueError) as e:
Simon Glass160a7662017-05-27 07:38:26 -06001212 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001213 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1214 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1215
1216 finally:
1217 # Put the original file back
Simon Glassf514d8f2019-08-24 07:22:54 -06001218 TestFunctional._MakeInputFile('u-boot',
1219 tools.ReadFile(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glass75db0862016-11-25 20:15:55 -07001220
1221 def testMicrocodeNotInImage(self):
1222 """Test that microcode must be placed within the image"""
1223 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001224 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001225 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1226 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glass25ac0e62018-06-01 09:38:14 -06001227 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glass75db0862016-11-25 20:15:55 -07001228
1229 def testWithoutMicrocode(self):
1230 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glassbccd91d2019-08-24 07:22:55 -06001231 TestFunctional._MakeInputFile('u-boot',
1232 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass741f2d62018-10-01 12:22:30 -06001233 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001234
1235 # Now check the device tree has no microcode
1236 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1237 second = data[len(U_BOOT_NODTB_DATA):]
1238
1239 fdt_len = self.GetFdtLen(second)
1240 self.assertEqual(dtb, second[:fdt_len])
1241
1242 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1243 third = data[used_len:]
Simon Glasse6d85ff2019-05-14 15:53:47 -06001244 self.assertEqual(tools.GetBytes(0, 0x200 - used_len), third)
Simon Glass75db0862016-11-25 20:15:55 -07001245
1246 def testUnknownPosSize(self):
1247 """Test that microcode must be placed within the image"""
1248 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001249 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glass3ab95982018-08-01 15:22:37 -06001250 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glass75db0862016-11-25 20:15:55 -07001251 "entry 'invalid-entry'", str(e.exception))
Simon Glassda229092016-11-25 20:15:56 -07001252
1253 def testPackFsp(self):
1254 """Test that an image with a FSP binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001255 data = self._DoReadFile('042_intel_fsp.dts')
Simon Glassda229092016-11-25 20:15:56 -07001256 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1257
1258 def testPackCmc(self):
Bin Meng59ea8c22017-08-15 22:41:54 -07001259 """Test that an image with a CMC binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001260 data = self._DoReadFile('043_intel_cmc.dts')
Simon Glassda229092016-11-25 20:15:56 -07001261 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Meng59ea8c22017-08-15 22:41:54 -07001262
1263 def testPackVbt(self):
1264 """Test that an image with a VBT binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001265 data = self._DoReadFile('046_intel_vbt.dts')
Bin Meng59ea8c22017-08-15 22:41:54 -07001266 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glass9fc60b42017-11-12 21:52:22 -07001267
Simon Glass56509842017-11-12 21:52:25 -07001268 def testSplBssPad(self):
1269 """Test that we can pad SPL's BSS with zeros"""
Simon Glass6b187df2017-11-12 21:52:27 -07001270 # ELF file with a '__bss_size' symbol
Simon Glass11ae93e2018-10-01 21:12:47 -06001271 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001272 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001273 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
1274 data)
Simon Glass56509842017-11-12 21:52:25 -07001275
Simon Glass86af5112018-10-01 21:12:42 -06001276 def testSplBssPadMissing(self):
1277 """Test that a missing symbol is detected"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001278 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glassb50e5612017-11-13 18:54:54 -07001279 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001280 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassb50e5612017-11-13 18:54:54 -07001281 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1282 str(e.exception))
1283
Simon Glass87722132017-11-12 21:52:26 -07001284 def testPackStart16Spl(self):
Simon Glass35b384c2018-09-14 04:57:10 -06001285 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001286 data = self._DoReadFile('048_x86_start16_spl.dts')
Simon Glass87722132017-11-12 21:52:26 -07001287 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1288
Simon Glass736bb0a2018-07-06 10:27:17 -06001289 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1290 """Helper function for microcode tests
Simon Glass6b187df2017-11-12 21:52:27 -07001291
1292 We expect to see the following in the image, in order:
1293 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1294 correct place
1295 u-boot.dtb with the microcode removed
1296 the microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001297
1298 Args:
1299 dts: Device tree file to use for test
1300 ucode_second: True if the microsecond entry is second instead of
1301 third
Simon Glass6b187df2017-11-12 21:52:27 -07001302 """
Simon Glass11ae93e2018-10-01 21:12:47 -06001303 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass736bb0a2018-07-06 10:27:17 -06001304 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1305 ucode_second=ucode_second)
Simon Glassc6c10e72019-05-17 22:00:46 -06001306 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1307 b'ter somewhere in here', first)
Simon Glass6b187df2017-11-12 21:52:27 -07001308
Simon Glass736bb0a2018-07-06 10:27:17 -06001309 def testPackUbootSplMicrocode(self):
1310 """Test that x86 microcode can be handled correctly in SPL"""
Simon Glass741f2d62018-10-01 12:22:30 -06001311 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass736bb0a2018-07-06 10:27:17 -06001312
1313 def testPackUbootSplMicrocodeReorder(self):
1314 """Test that order doesn't matter for microcode entries
1315
1316 This is the same as testPackUbootSplMicrocode but when we process the
1317 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1318 entry, so we reply on binman to try later.
1319 """
Simon Glass741f2d62018-10-01 12:22:30 -06001320 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass736bb0a2018-07-06 10:27:17 -06001321 ucode_second=True)
1322
Simon Glassca4f4ff2017-11-12 21:52:28 -07001323 def testPackMrc(self):
1324 """Test that an image with an MRC binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001325 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassca4f4ff2017-11-12 21:52:28 -07001326 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1327
Simon Glass47419ea2017-11-13 18:54:55 -07001328 def testSplDtb(self):
1329 """Test that an image with spl/u-boot-spl.dtb can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001330 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass47419ea2017-11-13 18:54:55 -07001331 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1332
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001333 def testSplNoDtb(self):
1334 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001335 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001336 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1337
Simon Glass19790632017-11-13 18:55:01 -07001338 def testSymbols(self):
1339 """Test binman can assign symbols embedded in U-Boot"""
Simon Glass1542c8b2019-08-24 07:22:56 -06001340 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass19790632017-11-13 18:55:01 -07001341 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1342 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Simon Glass3ab95982018-08-01 15:22:37 -06001343 self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr)
Simon Glass19790632017-11-13 18:55:01 -07001344
Simon Glass11ae93e2018-10-01 21:12:47 -06001345 self._SetupSplElf('u_boot_binman_syms')
Simon Glass741f2d62018-10-01 12:22:30 -06001346 data = self._DoReadFile('053_symbols.dts')
Simon Glass7c150132019-11-06 17:22:44 -07001347 sym_values = struct.pack('<LQLL', 0x00, 0x1c, 0x28, 0x04)
Simon Glassb87064c2019-08-24 07:23:05 -06001348 expected = (sym_values + U_BOOT_SPL_DATA[20:] +
Simon Glasse6d85ff2019-05-14 15:53:47 -06001349 tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
Simon Glassb87064c2019-08-24 07:23:05 -06001350 U_BOOT_SPL_DATA[20:])
Simon Glass19790632017-11-13 18:55:01 -07001351 self.assertEqual(expected, data)
1352
Simon Glassdd57c132018-06-01 09:38:11 -06001353 def testPackUnitAddress(self):
1354 """Test that we support multiple binaries with the same name"""
Simon Glass741f2d62018-10-01 12:22:30 -06001355 data = self._DoReadFile('054_unit_address.dts')
Simon Glassdd57c132018-06-01 09:38:11 -06001356 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1357
Simon Glass18546952018-06-01 09:38:16 -06001358 def testSections(self):
1359 """Basic test of sections"""
Simon Glass741f2d62018-10-01 12:22:30 -06001360 data = self._DoReadFile('055_sections.dts')
Simon Glassc6c10e72019-05-17 22:00:46 -06001361 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1362 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
1363 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
Simon Glass18546952018-06-01 09:38:16 -06001364 self.assertEqual(expected, data)
Simon Glass9fc60b42017-11-12 21:52:22 -07001365
Simon Glass3b0c3822018-06-01 09:38:20 -06001366 def testMap(self):
1367 """Tests outputting a map of the images"""
Simon Glass741f2d62018-10-01 12:22:30 -06001368 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001369 self.assertEqual('''ImagePos Offset Size Name
137000000000 00000000 00000028 main-section
137100000000 00000000 00000010 section@0
137200000000 00000000 00000004 u-boot
137300000010 00000010 00000010 section@1
137400000010 00000000 00000004 u-boot
137500000020 00000020 00000004 section@2
137600000020 00000000 00000004 u-boot
Simon Glass3b0c3822018-06-01 09:38:20 -06001377''', map_data)
1378
Simon Glassc8d48ef2018-06-01 09:38:21 -06001379 def testNamePrefix(self):
1380 """Tests that name prefixes are used"""
Simon Glass741f2d62018-10-01 12:22:30 -06001381 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001382 self.assertEqual('''ImagePos Offset Size Name
138300000000 00000000 00000028 main-section
138400000000 00000000 00000010 section@0
138500000000 00000000 00000004 ro-u-boot
138600000010 00000010 00000010 section@1
138700000010 00000000 00000004 rw-u-boot
Simon Glassc8d48ef2018-06-01 09:38:21 -06001388''', map_data)
1389
Simon Glass736bb0a2018-07-06 10:27:17 -06001390 def testUnknownContents(self):
1391 """Test that obtaining the contents works as expected"""
1392 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001393 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass8beb11e2019-07-08 14:25:47 -06001394 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glass16287932020-04-17 18:09:03 -06001395 "processing of contents: remaining ["
1396 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass736bb0a2018-07-06 10:27:17 -06001397
Simon Glass5c890232018-07-06 10:27:19 -06001398 def testBadChangeSize(self):
1399 """Test that trying to change the size of an entry fails"""
Simon Glassc52c9e72019-07-08 14:25:37 -06001400 try:
1401 state.SetAllowEntryExpansion(False)
1402 with self.assertRaises(ValueError) as e:
1403 self._DoReadFile('059_change_size.dts', True)
Simon Glass79d3c582019-07-20 12:23:57 -06001404 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glassc52c9e72019-07-08 14:25:37 -06001405 str(e.exception))
1406 finally:
1407 state.SetAllowEntryExpansion(True)
Simon Glass5c890232018-07-06 10:27:19 -06001408
Simon Glass16b8d6b2018-07-06 10:27:42 -06001409 def testUpdateFdt(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001410 """Test that we can update the device tree with offset/size info"""
Simon Glass741f2d62018-10-01 12:22:30 -06001411 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glass16b8d6b2018-07-06 10:27:42 -06001412 update_dtb=True)
Simon Glasscee02e62018-07-17 13:25:52 -06001413 dtb = fdt.Fdt(out_dtb_fname)
1414 dtb.Scan()
Simon Glass12bb1a92019-07-20 12:23:51 -06001415 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001416 self.assertEqual({
Simon Glassdbf6be92018-08-01 15:22:42 -06001417 'image-pos': 0,
Simon Glass8122f392018-07-17 13:25:28 -06001418 'offset': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001419 '_testing:offset': 32,
Simon Glass79d3c582019-07-20 12:23:57 -06001420 '_testing:size': 2,
Simon Glassdbf6be92018-08-01 15:22:42 -06001421 '_testing:image-pos': 32,
Simon Glass3ab95982018-08-01 15:22:37 -06001422 'section@0/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001423 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001424 'section@0/u-boot:image-pos': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001425 'section@0:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001426 'section@0:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001427 'section@0:image-pos': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001428
Simon Glass3ab95982018-08-01 15:22:37 -06001429 'section@1/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001430 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001431 'section@1/u-boot:image-pos': 16,
Simon Glass3ab95982018-08-01 15:22:37 -06001432 'section@1:offset': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001433 'section@1:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001434 'section@1:image-pos': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001435 'size': 40
1436 }, props)
1437
1438 def testUpdateFdtBad(self):
1439 """Test that we detect when ProcessFdt never completes"""
1440 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001441 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001442 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glass16287932020-04-17 18:09:03 -06001443 '[<binman.etype._testing.Entry__testing',
1444 str(e.exception))
Simon Glass5c890232018-07-06 10:27:19 -06001445
Simon Glass53af22a2018-07-17 13:25:32 -06001446 def testEntryArgs(self):
1447 """Test passing arguments to entries from the command line"""
1448 entry_args = {
1449 'test-str-arg': 'test1',
1450 'test-int-arg': '456',
1451 }
Simon Glass741f2d62018-10-01 12:22:30 -06001452 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001453 self.assertIn('image', control.images)
1454 entry = control.images['image'].GetEntries()['_testing']
1455 self.assertEqual('test0', entry.test_str_fdt)
1456 self.assertEqual('test1', entry.test_str_arg)
1457 self.assertEqual(123, entry.test_int_fdt)
1458 self.assertEqual(456, entry.test_int_arg)
1459
1460 def testEntryArgsMissing(self):
1461 """Test missing arguments and properties"""
1462 entry_args = {
1463 'test-int-arg': '456',
1464 }
Simon Glass741f2d62018-10-01 12:22:30 -06001465 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001466 entry = control.images['image'].GetEntries()['_testing']
1467 self.assertEqual('test0', entry.test_str_fdt)
1468 self.assertEqual(None, entry.test_str_arg)
1469 self.assertEqual(None, entry.test_int_fdt)
1470 self.assertEqual(456, entry.test_int_arg)
1471
1472 def testEntryArgsRequired(self):
1473 """Test missing arguments and properties"""
1474 entry_args = {
1475 'test-int-arg': '456',
1476 }
1477 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001478 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass3decfa32020-09-01 05:13:54 -06001479 self.assertIn("Node '/binman/_testing': "
1480 'Missing required properties/entry args: test-str-arg, '
1481 'test-int-fdt, test-int-arg',
Simon Glass53af22a2018-07-17 13:25:32 -06001482 str(e.exception))
1483
1484 def testEntryArgsInvalidFormat(self):
1485 """Test that an invalid entry-argument format is detected"""
Simon Glass53cd5d92019-07-08 14:25:29 -06001486 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1487 '-ano-value']
Simon Glass53af22a2018-07-17 13:25:32 -06001488 with self.assertRaises(ValueError) as e:
1489 self._DoBinman(*args)
1490 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1491
1492 def testEntryArgsInvalidInteger(self):
1493 """Test that an invalid entry-argument integer is detected"""
1494 entry_args = {
1495 'test-int-arg': 'abc',
1496 }
1497 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001498 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001499 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1500 "'test-int-arg' (value 'abc') to integer",
1501 str(e.exception))
1502
1503 def testEntryArgsInvalidDatatype(self):
1504 """Test that an invalid entry-argument datatype is detected
1505
1506 This test could be written in entry_test.py except that it needs
1507 access to control.entry_args, which seems more than that module should
1508 be able to see.
1509 """
1510 entry_args = {
1511 'test-bad-datatype-arg': '12',
1512 }
1513 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001514 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass53af22a2018-07-17 13:25:32 -06001515 entry_args=entry_args)
1516 self.assertIn('GetArg() internal error: Unknown data type ',
1517 str(e.exception))
1518
Simon Glassbb748372018-07-17 13:25:33 -06001519 def testText(self):
1520 """Test for a text entry type"""
1521 entry_args = {
1522 'test-id': TEXT_DATA,
1523 'test-id2': TEXT_DATA2,
1524 'test-id3': TEXT_DATA3,
1525 }
Simon Glass741f2d62018-10-01 12:22:30 -06001526 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glassbb748372018-07-17 13:25:33 -06001527 entry_args=entry_args)
Simon Glassc6c10e72019-05-17 22:00:46 -06001528 expected = (tools.ToBytes(TEXT_DATA) +
1529 tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1530 tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
Simon Glassaa88b502019-07-08 13:18:40 -06001531 b'some text' + b'more text')
Simon Glassbb748372018-07-17 13:25:33 -06001532 self.assertEqual(expected, data)
1533
Simon Glassfd8d1f72018-07-17 13:25:36 -06001534 def testEntryDocs(self):
1535 """Test for creation of entry documentation"""
1536 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass87d43322020-08-05 13:27:46 -06001537 control.WriteEntryDocs(control.GetEntryModules())
Simon Glassfd8d1f72018-07-17 13:25:36 -06001538 self.assertTrue(len(stdout.getvalue()) > 0)
1539
1540 def testEntryDocsMissing(self):
1541 """Test handling of missing entry documentation"""
1542 with self.assertRaises(ValueError) as e:
1543 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass87d43322020-08-05 13:27:46 -06001544 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glassfd8d1f72018-07-17 13:25:36 -06001545 self.assertIn('Documentation is missing for modules: u_boot',
1546 str(e.exception))
1547
Simon Glass11e36cc2018-07-17 13:25:38 -06001548 def testFmap(self):
1549 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001550 data = self._DoReadFile('067_fmap.dts')
Simon Glass11e36cc2018-07-17 13:25:38 -06001551 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc6c10e72019-05-17 22:00:46 -06001552 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1553 U_BOOT_DATA + tools.GetBytes(ord('a'), 12))
Simon Glass11e36cc2018-07-17 13:25:38 -06001554 self.assertEqual(expected, data[:32])
Simon Glassc6c10e72019-05-17 22:00:46 -06001555 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass11e36cc2018-07-17 13:25:38 -06001556 self.assertEqual(1, fhdr.ver_major)
1557 self.assertEqual(0, fhdr.ver_minor)
1558 self.assertEqual(0, fhdr.base)
1559 self.assertEqual(16 + 16 +
1560 fmap_util.FMAP_HEADER_LEN +
1561 fmap_util.FMAP_AREA_LEN * 3, fhdr.image_size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001562 self.assertEqual(b'FMAP', fhdr.name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001563 self.assertEqual(3, fhdr.nareas)
1564 for fentry in fentries:
1565 self.assertEqual(0, fentry.flags)
1566
1567 self.assertEqual(0, fentries[0].offset)
1568 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001569 self.assertEqual(b'RO_U_BOOT', fentries[0].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001570
1571 self.assertEqual(16, fentries[1].offset)
1572 self.assertEqual(4, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001573 self.assertEqual(b'RW_U_BOOT', fentries[1].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001574
1575 self.assertEqual(32, fentries[2].offset)
1576 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1577 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001578 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001579
Simon Glassec127af2018-07-17 13:25:39 -06001580 def testBlobNamedByArg(self):
1581 """Test we can add a blob with the filename coming from an entry arg"""
1582 entry_args = {
1583 'cros-ec-rw-path': 'ecrw.bin',
1584 }
Simon Glass3decfa32020-09-01 05:13:54 -06001585 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassec127af2018-07-17 13:25:39 -06001586
Simon Glass3af8e492018-07-17 13:25:40 -06001587 def testFill(self):
1588 """Test for an fill entry type"""
Simon Glass741f2d62018-10-01 12:22:30 -06001589 data = self._DoReadFile('069_fill.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001590 expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
Simon Glass3af8e492018-07-17 13:25:40 -06001591 self.assertEqual(expected, data)
1592
1593 def testFillNoSize(self):
1594 """Test for an fill entry type with no size"""
1595 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001596 self._DoReadFile('070_fill_no_size.dts')
Simon Glass3af8e492018-07-17 13:25:40 -06001597 self.assertIn("'fill' entry must have a size property",
1598 str(e.exception))
1599
Simon Glass0ef87aa2018-07-17 13:25:44 -06001600 def _HandleGbbCommand(self, pipe_list):
1601 """Fake calls to the futility utility"""
1602 if pipe_list[0][0] == 'futility':
1603 fname = pipe_list[0][-1]
1604 # Append our GBB data to the file, which will happen every time the
1605 # futility command is called.
Simon Glass1d0ebf72019-05-14 15:53:42 -06001606 with open(fname, 'ab') as fd:
Simon Glass0ef87aa2018-07-17 13:25:44 -06001607 fd.write(GBB_DATA)
1608 return command.CommandResult()
1609
1610 def testGbb(self):
1611 """Test for the Chromium OS Google Binary Block"""
1612 command.test_result = self._HandleGbbCommand
1613 entry_args = {
1614 'keydir': 'devkeys',
1615 'bmpblk': 'bmpblk.bin',
1616 }
Simon Glass741f2d62018-10-01 12:22:30 -06001617 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glass0ef87aa2018-07-17 13:25:44 -06001618
1619 # Since futility
Simon Glasse6d85ff2019-05-14 15:53:47 -06001620 expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1621 tools.GetBytes(0, 0x2180 - 16))
Simon Glass0ef87aa2018-07-17 13:25:44 -06001622 self.assertEqual(expected, data)
1623
1624 def testGbbTooSmall(self):
1625 """Test for the Chromium OS Google Binary Block being large enough"""
1626 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001627 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001628 self.assertIn("Node '/binman/gbb': GBB is too small",
1629 str(e.exception))
1630
1631 def testGbbNoSize(self):
1632 """Test for the Chromium OS Google Binary Block having a size"""
1633 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001634 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001635 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1636 str(e.exception))
1637
Simon Glass24d0d3c2018-07-17 13:25:47 -06001638 def _HandleVblockCommand(self, pipe_list):
1639 """Fake calls to the futility utility"""
1640 if pipe_list[0][0] == 'futility':
1641 fname = pipe_list[0][3]
Simon Glassa326b492018-09-14 04:57:11 -06001642 with open(fname, 'wb') as fd:
Simon Glass24d0d3c2018-07-17 13:25:47 -06001643 fd.write(VBLOCK_DATA)
1644 return command.CommandResult()
1645
1646 def testVblock(self):
1647 """Test for the Chromium OS Verified Boot Block"""
1648 command.test_result = self._HandleVblockCommand
1649 entry_args = {
1650 'keydir': 'devkeys',
1651 }
Simon Glass741f2d62018-10-01 12:22:30 -06001652 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass24d0d3c2018-07-17 13:25:47 -06001653 entry_args=entry_args)
1654 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1655 self.assertEqual(expected, data)
1656
1657 def testVblockNoContent(self):
1658 """Test we detect a vblock which has no content to sign"""
1659 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001660 self._DoReadFile('075_vblock_no_content.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001661 self.assertIn("Node '/binman/vblock': Vblock must have a 'content' "
1662 'property', str(e.exception))
1663
1664 def testVblockBadPhandle(self):
1665 """Test that we detect a vblock with an invalid phandle in contents"""
1666 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001667 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001668 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1669 '1000', str(e.exception))
1670
1671 def testVblockBadEntry(self):
1672 """Test that we detect an entry that points to a non-entry"""
1673 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001674 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001675 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1676 "'other'", str(e.exception))
1677
Simon Glassb8ef5b62018-07-17 13:25:48 -06001678 def testTpl(self):
Simon Glass2090f1e2019-08-24 07:23:00 -06001679 """Test that an image with TPL and its device tree can be created"""
Simon Glassb8ef5b62018-07-17 13:25:48 -06001680 # ELF file with a '__bss_size' symbol
Simon Glass2090f1e2019-08-24 07:23:00 -06001681 self._SetupTplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001682 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glassb8ef5b62018-07-17 13:25:48 -06001683 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1684
Simon Glass15a587c2018-07-17 13:25:51 -06001685 def testUsesPos(self):
1686 """Test that the 'pos' property cannot be used anymore"""
1687 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001688 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass15a587c2018-07-17 13:25:51 -06001689 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1690 "'pos'", str(e.exception))
1691
Simon Glassd178eab2018-09-14 04:57:08 -06001692 def testFillZero(self):
1693 """Test for an fill entry type with a size of 0"""
Simon Glass741f2d62018-10-01 12:22:30 -06001694 data = self._DoReadFile('080_fill_empty.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001695 self.assertEqual(tools.GetBytes(0, 16), data)
Simon Glassd178eab2018-09-14 04:57:08 -06001696
Simon Glass0b489362018-09-14 04:57:09 -06001697 def testTextMissing(self):
1698 """Test for a text entry type where there is no text"""
1699 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001700 self._DoReadFileDtb('066_text.dts',)
Simon Glass0b489362018-09-14 04:57:09 -06001701 self.assertIn("Node '/binman/text': No value provided for text label "
1702 "'test-id'", str(e.exception))
1703
Simon Glass35b384c2018-09-14 04:57:10 -06001704 def testPackStart16Tpl(self):
1705 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001706 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glass35b384c2018-09-14 04:57:10 -06001707 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1708
Simon Glass0bfa7b02018-09-14 04:57:12 -06001709 def testSelectImage(self):
1710 """Test that we can select which images to build"""
Simon Glasseb833d82019-04-25 21:58:34 -06001711 expected = 'Skipping images: image1'
Simon Glass0bfa7b02018-09-14 04:57:12 -06001712
Simon Glasseb833d82019-04-25 21:58:34 -06001713 # We should only get the expected message in verbose mode
Simon Glassee0c9a72019-07-08 13:18:48 -06001714 for verbosity in (0, 2):
Simon Glasseb833d82019-04-25 21:58:34 -06001715 with test_util.capture_sys_output() as (stdout, stderr):
1716 retcode = self._DoTestFile('006_dual_image.dts',
1717 verbosity=verbosity,
1718 images=['image2'])
1719 self.assertEqual(0, retcode)
1720 if verbosity:
1721 self.assertIn(expected, stdout.getvalue())
1722 else:
1723 self.assertNotIn(expected, stdout.getvalue())
1724
1725 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1726 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
Simon Glassf86a7362019-07-20 12:24:10 -06001727 self._CleanupOutputDir()
Simon Glass0bfa7b02018-09-14 04:57:12 -06001728
Simon Glass6ed45ba2018-09-14 04:57:24 -06001729 def testUpdateFdtAll(self):
1730 """Test that all device trees are updated with offset/size info"""
Simon Glass3c081312019-07-08 14:25:26 -06001731 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glass6ed45ba2018-09-14 04:57:24 -06001732
1733 base_expected = {
1734 'section:image-pos': 0,
1735 'u-boot-tpl-dtb:size': 513,
1736 'u-boot-spl-dtb:size': 513,
1737 'u-boot-spl-dtb:offset': 493,
1738 'image-pos': 0,
1739 'section/u-boot-dtb:image-pos': 0,
1740 'u-boot-spl-dtb:image-pos': 493,
1741 'section/u-boot-dtb:size': 493,
1742 'u-boot-tpl-dtb:image-pos': 1006,
1743 'section/u-boot-dtb:offset': 0,
1744 'section:size': 493,
1745 'offset': 0,
1746 'section:offset': 0,
1747 'u-boot-tpl-dtb:offset': 1006,
1748 'size': 1519
1749 }
1750
1751 # We expect three device-tree files in the output, one after the other.
1752 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1753 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1754 # main U-Boot tree. All three should have the same postions and offset.
1755 start = 0
1756 for item in ['', 'spl', 'tpl']:
1757 dtb = fdt.Fdt.FromData(data[start:])
1758 dtb.Scan()
Simon Glass12bb1a92019-07-20 12:23:51 -06001759 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
1760 ['spl', 'tpl'])
Simon Glass6ed45ba2018-09-14 04:57:24 -06001761 expected = dict(base_expected)
1762 if item:
1763 expected[item] = 0
1764 self.assertEqual(expected, props)
1765 start += dtb._fdt_obj.totalsize()
1766
1767 def testUpdateFdtOutput(self):
1768 """Test that output DTB files are updated"""
1769 try:
Simon Glass741f2d62018-10-01 12:22:30 -06001770 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glass6ed45ba2018-09-14 04:57:24 -06001771 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1772
1773 # Unfortunately, compiling a source file always results in a file
1774 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass741f2d62018-10-01 12:22:30 -06001775 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glass6ed45ba2018-09-14 04:57:24 -06001776 # binman as a file called u-boot.dtb. To fix this, copy the file
1777 # over to the expected place.
Simon Glass6ed45ba2018-09-14 04:57:24 -06001778 start = 0
1779 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1780 'tpl/u-boot-tpl.dtb.out']:
1781 dtb = fdt.Fdt.FromData(data[start:])
1782 size = dtb._fdt_obj.totalsize()
1783 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1784 outdata = tools.ReadFile(pathname)
1785 name = os.path.split(fname)[0]
1786
1787 if name:
1788 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1789 else:
1790 orig_indata = dtb_data
1791 self.assertNotEqual(outdata, orig_indata,
1792 "Expected output file '%s' be updated" % pathname)
1793 self.assertEqual(outdata, data[start:start + size],
1794 "Expected output file '%s' to match output image" %
1795 pathname)
1796 start += size
1797 finally:
1798 self._ResetDtbs()
1799
Simon Glass83d73c22018-09-14 04:57:26 -06001800 def _decompress(self, data):
Simon Glassff5c7e32019-07-08 13:18:42 -06001801 return tools.Decompress(data, 'lz4')
Simon Glass83d73c22018-09-14 04:57:26 -06001802
1803 def testCompress(self):
1804 """Test compression of blobs"""
Simon Glassac62fba2019-07-08 13:18:53 -06001805 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06001806 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass83d73c22018-09-14 04:57:26 -06001807 use_real_dtb=True, update_dtb=True)
1808 dtb = fdt.Fdt(out_dtb_fname)
1809 dtb.Scan()
1810 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1811 orig = self._decompress(data)
1812 self.assertEquals(COMPRESS_DATA, orig)
1813 expected = {
1814 'blob:uncomp-size': len(COMPRESS_DATA),
1815 'blob:size': len(data),
1816 'size': len(data),
1817 }
1818 self.assertEqual(expected, props)
1819
Simon Glass0a98b282018-09-14 04:57:28 -06001820 def testFiles(self):
1821 """Test bringing in multiple files"""
Simon Glass741f2d62018-10-01 12:22:30 -06001822 data = self._DoReadFile('084_files.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001823 self.assertEqual(FILES_DATA, data)
1824
1825 def testFilesCompress(self):
1826 """Test bringing in multiple files and compressing them"""
Simon Glassac62fba2019-07-08 13:18:53 -06001827 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06001828 data = self._DoReadFile('085_files_compress.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001829
1830 image = control.images['image']
1831 entries = image.GetEntries()
1832 files = entries['files']
Simon Glass8beb11e2019-07-08 14:25:47 -06001833 entries = files._entries
Simon Glass0a98b282018-09-14 04:57:28 -06001834
Simon Glassc6c10e72019-05-17 22:00:46 -06001835 orig = b''
Simon Glass0a98b282018-09-14 04:57:28 -06001836 for i in range(1, 3):
1837 key = '%d.dat' % i
1838 start = entries[key].image_pos
1839 len = entries[key].size
1840 chunk = data[start:start + len]
1841 orig += self._decompress(chunk)
1842
1843 self.assertEqual(FILES_DATA, orig)
1844
1845 def testFilesMissing(self):
1846 """Test missing files"""
1847 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001848 data = self._DoReadFile('086_files_none.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001849 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1850 'no files', str(e.exception))
1851
1852 def testFilesNoPattern(self):
1853 """Test missing files"""
1854 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001855 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001856 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1857 str(e.exception))
1858
Simon Glassba64a0b2018-09-14 04:57:29 -06001859 def testExpandSize(self):
1860 """Test an expanding entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001861 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
Simon Glassba64a0b2018-09-14 04:57:29 -06001862 map=True)
Simon Glassc6c10e72019-05-17 22:00:46 -06001863 expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA +
1864 MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA +
1865 tools.GetBytes(ord('c'), 8) + U_BOOT_DATA +
1866 tools.GetBytes(ord('d'), 8))
Simon Glassba64a0b2018-09-14 04:57:29 -06001867 self.assertEqual(expect, data)
1868 self.assertEqual('''ImagePos Offset Size Name
186900000000 00000000 00000028 main-section
187000000000 00000000 00000008 fill
187100000008 00000008 00000004 u-boot
18720000000c 0000000c 00000004 section
18730000000c 00000000 00000003 intel-mrc
187400000010 00000010 00000004 u-boot2
187500000014 00000014 0000000c section2
187600000014 00000000 00000008 fill
18770000001c 00000008 00000004 u-boot
187800000020 00000020 00000008 fill2
1879''', map_data)
1880
1881 def testExpandSizeBad(self):
1882 """Test an expanding entry which fails to provide contents"""
Simon Glass163ed6c2018-09-14 04:57:36 -06001883 with test_util.capture_sys_output() as (stdout, stderr):
1884 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001885 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
Simon Glassba64a0b2018-09-14 04:57:29 -06001886 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
1887 'expanding entry', str(e.exception))
1888
Simon Glasse0e5df92018-09-14 04:57:31 -06001889 def testHash(self):
1890 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001891 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06001892 use_real_dtb=True, update_dtb=True)
1893 dtb = fdt.Fdt(out_dtb_fname)
1894 dtb.Scan()
1895 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
1896 m = hashlib.sha256()
1897 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001898 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06001899
1900 def testHashNoAlgo(self):
1901 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001902 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06001903 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
1904 'hash node', str(e.exception))
1905
1906 def testHashBadAlgo(self):
1907 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001908 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06001909 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
1910 str(e.exception))
1911
1912 def testHashSection(self):
1913 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001914 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06001915 use_real_dtb=True, update_dtb=True)
1916 dtb = fdt.Fdt(out_dtb_fname)
1917 dtb.Scan()
1918 hash_node = dtb.GetNode('/binman/section/hash').props['value']
1919 m = hashlib.sha256()
1920 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001921 m.update(tools.GetBytes(ord('a'), 16))
1922 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06001923
Simon Glassf0253632018-09-14 04:57:32 -06001924 def testPackUBootTplMicrocode(self):
1925 """Test that x86 microcode can be handled correctly in TPL
1926
1927 We expect to see the following in the image, in order:
1928 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
1929 place
1930 u-boot-tpl.dtb with the microcode removed
1931 the microcode
1932 """
Simon Glass2090f1e2019-08-24 07:23:00 -06001933 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass741f2d62018-10-01 12:22:30 -06001934 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glassf0253632018-09-14 04:57:32 -06001935 U_BOOT_TPL_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001936 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
1937 b'ter somewhere in here', first)
Simon Glassf0253632018-09-14 04:57:32 -06001938
Simon Glassf8f8df62018-09-14 04:57:34 -06001939 def testFmapX86(self):
1940 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001941 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassf8f8df62018-09-14 04:57:34 -06001942 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc6c10e72019-05-17 22:00:46 -06001943 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06001944 self.assertEqual(expected, data[:32])
1945 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1946
1947 self.assertEqual(0x100, fhdr.image_size)
1948
1949 self.assertEqual(0, fentries[0].offset)
1950 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001951 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001952
1953 self.assertEqual(4, fentries[1].offset)
1954 self.assertEqual(3, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001955 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001956
1957 self.assertEqual(32, fentries[2].offset)
1958 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1959 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001960 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001961
1962 def testFmapX86Section(self):
1963 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001964 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glassc6c10e72019-05-17 22:00:46 -06001965 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06001966 self.assertEqual(expected, data[:32])
1967 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
1968
1969 self.assertEqual(0x100, fhdr.image_size)
1970
1971 self.assertEqual(0, fentries[0].offset)
1972 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001973 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001974
1975 self.assertEqual(4, fentries[1].offset)
1976 self.assertEqual(3, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001977 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001978
1979 self.assertEqual(36, fentries[2].offset)
1980 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1981 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001982 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001983
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001984 def testElf(self):
1985 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001986 self._SetupSplElf()
Simon Glass2090f1e2019-08-24 07:23:00 -06001987 self._SetupTplElf()
Simon Glass53e22bf2019-08-24 07:22:53 -06001988 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001989 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001990 data = self._DoReadFile('096_elf.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001991
Simon Glass093d1682019-07-08 13:18:25 -06001992 def testElfStrip(self):
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001993 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001994 self._SetupSplElf()
Simon Glass53e22bf2019-08-24 07:22:53 -06001995 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001996 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001997 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001998
Simon Glass163ed6c2018-09-14 04:57:36 -06001999 def testPackOverlapMap(self):
2000 """Test that overlapping regions are detected"""
2001 with test_util.capture_sys_output() as (stdout, stderr):
2002 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002003 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glass163ed6c2018-09-14 04:57:36 -06002004 map_fname = tools.GetOutputFilename('image.map')
2005 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2006 stdout.getvalue())
2007
2008 # We should not get an inmage, but there should be a map file
2009 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
2010 self.assertTrue(os.path.exists(map_fname))
Simon Glasseb546ac2019-05-17 22:00:51 -06002011 map_data = tools.ReadFile(map_fname, binary=False)
Simon Glass163ed6c2018-09-14 04:57:36 -06002012 self.assertEqual('''ImagePos Offset Size Name
2013<none> 00000000 00000007 main-section
2014<none> 00000000 00000004 u-boot
2015<none> 00000003 00000004 u-boot-align
2016''', map_data)
2017
Simon Glass093d1682019-07-08 13:18:25 -06002018 def testPackRefCode(self):
Simon Glass3ae192c2018-10-01 12:22:31 -06002019 """Test that an image with an Intel Reference code binary works"""
2020 data = self._DoReadFile('100_intel_refcode.dts')
2021 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2022
Simon Glass9481c802019-04-25 21:58:39 -06002023 def testSectionOffset(self):
2024 """Tests use of a section with an offset"""
2025 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2026 map=True)
2027 self.assertEqual('''ImagePos Offset Size Name
202800000000 00000000 00000038 main-section
202900000004 00000004 00000010 section@0
203000000004 00000000 00000004 u-boot
203100000018 00000018 00000010 section@1
203200000018 00000000 00000004 u-boot
20330000002c 0000002c 00000004 section@2
20340000002c 00000000 00000004 u-boot
2035''', map_data)
2036 self.assertEqual(data,
Simon Glasse6d85ff2019-05-14 15:53:47 -06002037 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2038 tools.GetBytes(0x21, 12) +
2039 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2040 tools.GetBytes(0x61, 12) +
2041 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2042 tools.GetBytes(0x26, 8))
Simon Glass9481c802019-04-25 21:58:39 -06002043
Simon Glassac62fba2019-07-08 13:18:53 -06002044 def testCbfsRaw(self):
2045 """Test base handling of a Coreboot Filesystem (CBFS)
2046
2047 The exact contents of the CBFS is verified by similar tests in
2048 cbfs_util_test.py. The tests here merely check that the files added to
2049 the CBFS can be found in the final image.
2050 """
2051 data = self._DoReadFile('102_cbfs_raw.dts')
2052 size = 0xb0
2053
2054 cbfs = cbfs_util.CbfsReader(data)
2055 self.assertEqual(size, cbfs.rom_size)
2056
2057 self.assertIn('u-boot-dtb', cbfs.files)
2058 cfile = cbfs.files['u-boot-dtb']
2059 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2060
2061 def testCbfsArch(self):
2062 """Test on non-x86 architecture"""
2063 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2064 size = 0x100
2065
2066 cbfs = cbfs_util.CbfsReader(data)
2067 self.assertEqual(size, cbfs.rom_size)
2068
2069 self.assertIn('u-boot-dtb', cbfs.files)
2070 cfile = cbfs.files['u-boot-dtb']
2071 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2072
2073 def testCbfsStage(self):
2074 """Tests handling of a Coreboot Filesystem (CBFS)"""
2075 if not elf.ELF_TOOLS:
2076 self.skipTest('Python elftools not available')
2077 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2078 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2079 size = 0xb0
2080
2081 data = self._DoReadFile('104_cbfs_stage.dts')
2082 cbfs = cbfs_util.CbfsReader(data)
2083 self.assertEqual(size, cbfs.rom_size)
2084
2085 self.assertIn('u-boot', cbfs.files)
2086 cfile = cbfs.files['u-boot']
2087 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2088
2089 def testCbfsRawCompress(self):
2090 """Test handling of compressing raw files"""
2091 self._CheckLz4()
2092 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2093 size = 0x140
2094
2095 cbfs = cbfs_util.CbfsReader(data)
2096 self.assertIn('u-boot', cbfs.files)
2097 cfile = cbfs.files['u-boot']
2098 self.assertEqual(COMPRESS_DATA, cfile.data)
2099
2100 def testCbfsBadArch(self):
2101 """Test handling of a bad architecture"""
2102 with self.assertRaises(ValueError) as e:
2103 self._DoReadFile('106_cbfs_bad_arch.dts')
2104 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2105
2106 def testCbfsNoSize(self):
2107 """Test handling of a missing size property"""
2108 with self.assertRaises(ValueError) as e:
2109 self._DoReadFile('107_cbfs_no_size.dts')
2110 self.assertIn('entry must have a size property', str(e.exception))
2111
2112 def testCbfsNoCOntents(self):
2113 """Test handling of a CBFS entry which does not provide contentsy"""
2114 with self.assertRaises(ValueError) as e:
2115 self._DoReadFile('108_cbfs_no_contents.dts')
2116 self.assertIn('Could not complete processing of contents',
2117 str(e.exception))
2118
2119 def testCbfsBadCompress(self):
2120 """Test handling of a bad architecture"""
2121 with self.assertRaises(ValueError) as e:
2122 self._DoReadFile('109_cbfs_bad_compress.dts')
2123 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2124 str(e.exception))
2125
2126 def testCbfsNamedEntries(self):
2127 """Test handling of named entries"""
2128 data = self._DoReadFile('110_cbfs_name.dts')
2129
2130 cbfs = cbfs_util.CbfsReader(data)
2131 self.assertIn('FRED', cbfs.files)
2132 cfile1 = cbfs.files['FRED']
2133 self.assertEqual(U_BOOT_DATA, cfile1.data)
2134
2135 self.assertIn('hello', cbfs.files)
2136 cfile2 = cbfs.files['hello']
2137 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2138
Simon Glassc5ac1382019-07-08 13:18:54 -06002139 def _SetupIfwi(self, fname):
2140 """Set up to run an IFWI test
2141
2142 Args:
2143 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2144 """
2145 self._SetupSplElf()
Simon Glass2090f1e2019-08-24 07:23:00 -06002146 self._SetupTplElf()
Simon Glassc5ac1382019-07-08 13:18:54 -06002147
2148 # Intel Integrated Firmware Image (IFWI) file
2149 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2150 data = fd.read()
2151 TestFunctional._MakeInputFile(fname,data)
2152
2153 def _CheckIfwi(self, data):
2154 """Check that an image with an IFWI contains the correct output
2155
2156 Args:
2157 data: Conents of output file
2158 """
2159 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
2160 if data[:0x1000] != expected_desc:
2161 self.fail('Expected descriptor binary at start of image')
2162
2163 # We expect to find the TPL wil in subpart IBBP entry IBBL
2164 image_fname = tools.GetOutputFilename('image.bin')
2165 tpl_fname = tools.GetOutputFilename('tpl.out')
2166 tools.RunIfwiTool(image_fname, tools.CMD_EXTRACT, fname=tpl_fname,
2167 subpart='IBBP', entry_name='IBBL')
2168
2169 tpl_data = tools.ReadFile(tpl_fname)
Simon Glasse95be632019-08-24 07:22:51 -06002170 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glassc5ac1382019-07-08 13:18:54 -06002171
2172 def testPackX86RomIfwi(self):
2173 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2174 self._SetupIfwi('fitimage.bin')
Simon Glass9255f3c2019-08-24 07:23:01 -06002175 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002176 self._CheckIfwi(data)
2177
2178 def testPackX86RomIfwiNoDesc(self):
2179 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2180 self._SetupIfwi('ifwi.bin')
Simon Glass9255f3c2019-08-24 07:23:01 -06002181 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002182 self._CheckIfwi(data)
2183
2184 def testPackX86RomIfwiNoData(self):
2185 """Test that an x86 ROM with IFWI handles missing data"""
2186 self._SetupIfwi('ifwi.bin')
2187 with self.assertRaises(ValueError) as e:
Simon Glass9255f3c2019-08-24 07:23:01 -06002188 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002189 self.assertIn('Could not complete processing of contents',
2190 str(e.exception))
Simon Glass53af22a2018-07-17 13:25:32 -06002191
Simon Glasse073d4e2019-07-08 13:18:56 -06002192 def testCbfsOffset(self):
2193 """Test a CBFS with files at particular offsets
2194
2195 Like all CFBS tests, this is just checking the logic that calls
2196 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2197 """
2198 data = self._DoReadFile('114_cbfs_offset.dts')
2199 size = 0x200
2200
2201 cbfs = cbfs_util.CbfsReader(data)
2202 self.assertEqual(size, cbfs.rom_size)
2203
2204 self.assertIn('u-boot', cbfs.files)
2205 cfile = cbfs.files['u-boot']
2206 self.assertEqual(U_BOOT_DATA, cfile.data)
2207 self.assertEqual(0x40, cfile.cbfs_offset)
2208
2209 self.assertIn('u-boot-dtb', cbfs.files)
2210 cfile2 = cbfs.files['u-boot-dtb']
2211 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2212 self.assertEqual(0x140, cfile2.cbfs_offset)
2213
Simon Glass086cec92019-07-08 14:25:27 -06002214 def testFdtmap(self):
2215 """Test an FDT map can be inserted in the image"""
2216 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2217 fdtmap_data = data[len(U_BOOT_DATA):]
2218 magic = fdtmap_data[:8]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002219 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass086cec92019-07-08 14:25:27 -06002220 self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
2221
2222 fdt_data = fdtmap_data[16:]
2223 dtb = fdt.Fdt.FromData(fdt_data)
2224 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002225 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass086cec92019-07-08 14:25:27 -06002226 self.assertEqual({
2227 'image-pos': 0,
2228 'offset': 0,
2229 'u-boot:offset': 0,
2230 'u-boot:size': len(U_BOOT_DATA),
2231 'u-boot:image-pos': 0,
2232 'fdtmap:image-pos': 4,
2233 'fdtmap:offset': 4,
2234 'fdtmap:size': len(fdtmap_data),
2235 'size': len(data),
2236 }, props)
2237
2238 def testFdtmapNoMatch(self):
2239 """Check handling of an FDT map when the section cannot be found"""
2240 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2241
2242 # Mangle the section name, which should cause a mismatch between the
2243 # correct FDT path and the one expected by the section
2244 image = control.images['image']
Simon Glasscf228942019-07-08 14:25:28 -06002245 image._node.path += '-suffix'
Simon Glass086cec92019-07-08 14:25:27 -06002246 entries = image.GetEntries()
2247 fdtmap = entries['fdtmap']
2248 with self.assertRaises(ValueError) as e:
2249 fdtmap._GetFdtmap()
2250 self.assertIn("Cannot locate node for path '/binman-suffix'",
2251 str(e.exception))
2252
Simon Glasscf228942019-07-08 14:25:28 -06002253 def testFdtmapHeader(self):
2254 """Test an FDT map and image header can be inserted in the image"""
2255 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2256 fdtmap_pos = len(U_BOOT_DATA)
2257 fdtmap_data = data[fdtmap_pos:]
2258 fdt_data = fdtmap_data[16:]
2259 dtb = fdt.Fdt.FromData(fdt_data)
2260 fdt_size = dtb.GetFdtObj().totalsize()
2261 hdr_data = data[-8:]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002262 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002263 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2264 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2265
2266 def testFdtmapHeaderStart(self):
2267 """Test an image header can be inserted at the image start"""
2268 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2269 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2270 hdr_data = data[:8]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002271 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002272 offset = struct.unpack('<I', hdr_data[4:])[0]
2273 self.assertEqual(fdtmap_pos, offset)
2274
2275 def testFdtmapHeaderPos(self):
2276 """Test an image header can be inserted at a chosen position"""
2277 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2278 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2279 hdr_data = data[0x80:0x88]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002280 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002281 offset = struct.unpack('<I', hdr_data[4:])[0]
2282 self.assertEqual(fdtmap_pos, offset)
2283
2284 def testHeaderMissingFdtmap(self):
2285 """Test an image header requires an fdtmap"""
2286 with self.assertRaises(ValueError) as e:
2287 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2288 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2289 str(e.exception))
2290
2291 def testHeaderNoLocation(self):
2292 """Test an image header with a no specified location is detected"""
2293 with self.assertRaises(ValueError) as e:
2294 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2295 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2296 str(e.exception))
2297
Simon Glassc52c9e72019-07-08 14:25:37 -06002298 def testEntryExpand(self):
2299 """Test expanding an entry after it is packed"""
2300 data = self._DoReadFile('121_entry_expand.dts')
Simon Glass79d3c582019-07-20 12:23:57 -06002301 self.assertEqual(b'aaa', data[:3])
2302 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2303 self.assertEqual(b'aaa', data[-3:])
Simon Glassc52c9e72019-07-08 14:25:37 -06002304
2305 def testEntryExpandBad(self):
2306 """Test expanding an entry after it is packed, twice"""
2307 with self.assertRaises(ValueError) as e:
2308 self._DoReadFile('122_entry_expand_twice.dts')
Simon Glass61ec04f2019-07-20 12:23:58 -06002309 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glassc52c9e72019-07-08 14:25:37 -06002310 str(e.exception))
2311
2312 def testEntryExpandSection(self):
2313 """Test expanding an entry within a section after it is packed"""
2314 data = self._DoReadFile('123_entry_expand_section.dts')
Simon Glass79d3c582019-07-20 12:23:57 -06002315 self.assertEqual(b'aaa', data[:3])
2316 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2317 self.assertEqual(b'aaa', data[-3:])
Simon Glassc52c9e72019-07-08 14:25:37 -06002318
Simon Glass6c223fd2019-07-08 14:25:38 -06002319 def testCompressDtb(self):
2320 """Test that compress of device-tree files is supported"""
2321 self._CheckLz4()
2322 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2323 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2324 comp_data = data[len(U_BOOT_DATA):]
2325 orig = self._decompress(comp_data)
2326 dtb = fdt.Fdt.FromData(orig)
2327 dtb.Scan()
2328 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2329 expected = {
2330 'u-boot:size': len(U_BOOT_DATA),
2331 'u-boot-dtb:uncomp-size': len(orig),
2332 'u-boot-dtb:size': len(comp_data),
2333 'size': len(data),
2334 }
2335 self.assertEqual(expected, props)
2336
Simon Glass69f7cb32019-07-08 14:25:41 -06002337 def testCbfsUpdateFdt(self):
2338 """Test that we can update the device tree with CBFS offset/size info"""
2339 self._CheckLz4()
2340 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2341 update_dtb=True)
2342 dtb = fdt.Fdt(out_dtb_fname)
2343 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002344 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass69f7cb32019-07-08 14:25:41 -06002345 del props['cbfs/u-boot:size']
2346 self.assertEqual({
2347 'offset': 0,
2348 'size': len(data),
2349 'image-pos': 0,
2350 'cbfs:offset': 0,
2351 'cbfs:size': len(data),
2352 'cbfs:image-pos': 0,
2353 'cbfs/u-boot:offset': 0x38,
2354 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2355 'cbfs/u-boot:image-pos': 0x38,
2356 'cbfs/u-boot-dtb:offset': 0xb8,
2357 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2358 'cbfs/u-boot-dtb:image-pos': 0xb8,
2359 }, props)
2360
Simon Glass8a1ad062019-07-08 14:25:42 -06002361 def testCbfsBadType(self):
2362 """Test an image header with a no specified location is detected"""
2363 with self.assertRaises(ValueError) as e:
2364 self._DoReadFile('126_cbfs_bad_type.dts')
2365 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2366
Simon Glass41b8ba02019-07-08 14:25:43 -06002367 def testList(self):
2368 """Test listing the files in an image"""
2369 self._CheckLz4()
2370 data = self._DoReadFile('127_list.dts')
2371 image = control.images['image']
2372 entries = image.BuildEntryList()
2373 self.assertEqual(7, len(entries))
2374
2375 ent = entries[0]
2376 self.assertEqual(0, ent.indent)
2377 self.assertEqual('main-section', ent.name)
2378 self.assertEqual('section', ent.etype)
2379 self.assertEqual(len(data), ent.size)
2380 self.assertEqual(0, ent.image_pos)
2381 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002382 self.assertEqual(0, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002383
2384 ent = entries[1]
2385 self.assertEqual(1, ent.indent)
2386 self.assertEqual('u-boot', ent.name)
2387 self.assertEqual('u-boot', ent.etype)
2388 self.assertEqual(len(U_BOOT_DATA), ent.size)
2389 self.assertEqual(0, ent.image_pos)
2390 self.assertEqual(None, ent.uncomp_size)
2391 self.assertEqual(0, ent.offset)
2392
2393 ent = entries[2]
2394 self.assertEqual(1, ent.indent)
2395 self.assertEqual('section', ent.name)
2396 self.assertEqual('section', ent.etype)
2397 section_size = ent.size
2398 self.assertEqual(0x100, ent.image_pos)
2399 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002400 self.assertEqual(0x100, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002401
2402 ent = entries[3]
2403 self.assertEqual(2, ent.indent)
2404 self.assertEqual('cbfs', ent.name)
2405 self.assertEqual('cbfs', ent.etype)
2406 self.assertEqual(0x400, ent.size)
2407 self.assertEqual(0x100, ent.image_pos)
2408 self.assertEqual(None, ent.uncomp_size)
2409 self.assertEqual(0, ent.offset)
2410
2411 ent = entries[4]
2412 self.assertEqual(3, ent.indent)
2413 self.assertEqual('u-boot', ent.name)
2414 self.assertEqual('u-boot', ent.etype)
2415 self.assertEqual(len(U_BOOT_DATA), ent.size)
2416 self.assertEqual(0x138, ent.image_pos)
2417 self.assertEqual(None, ent.uncomp_size)
2418 self.assertEqual(0x38, ent.offset)
2419
2420 ent = entries[5]
2421 self.assertEqual(3, ent.indent)
2422 self.assertEqual('u-boot-dtb', ent.name)
2423 self.assertEqual('text', ent.etype)
2424 self.assertGreater(len(COMPRESS_DATA), ent.size)
2425 self.assertEqual(0x178, ent.image_pos)
2426 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2427 self.assertEqual(0x78, ent.offset)
2428
2429 ent = entries[6]
2430 self.assertEqual(2, ent.indent)
2431 self.assertEqual('u-boot-dtb', ent.name)
2432 self.assertEqual('u-boot-dtb', ent.etype)
2433 self.assertEqual(0x500, ent.image_pos)
2434 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2435 dtb_size = ent.size
2436 # Compressing this data expands it since headers are added
2437 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2438 self.assertEqual(0x400, ent.offset)
2439
2440 self.assertEqual(len(data), 0x100 + section_size)
2441 self.assertEqual(section_size, 0x400 + dtb_size)
2442
Simon Glasse1925fa2019-07-08 14:25:44 -06002443 def testFindFdtmap(self):
2444 """Test locating an FDT map in an image"""
2445 self._CheckLz4()
2446 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2447 image = control.images['image']
2448 entries = image.GetEntries()
2449 entry = entries['fdtmap']
2450 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2451
2452 def testFindFdtmapMissing(self):
2453 """Test failing to locate an FDP map"""
2454 data = self._DoReadFile('005_simple.dts')
2455 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2456
Simon Glass2d260032019-07-08 14:25:45 -06002457 def testFindImageHeader(self):
2458 """Test locating a image header"""
2459 self._CheckLz4()
Simon Glassffded752019-07-08 14:25:46 -06002460 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002461 image = control.images['image']
2462 entries = image.GetEntries()
2463 entry = entries['fdtmap']
2464 # The header should point to the FDT map
2465 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2466
2467 def testFindImageHeaderStart(self):
2468 """Test locating a image header located at the start of an image"""
Simon Glassffded752019-07-08 14:25:46 -06002469 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002470 image = control.images['image']
2471 entries = image.GetEntries()
2472 entry = entries['fdtmap']
2473 # The header should point to the FDT map
2474 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2475
2476 def testFindImageHeaderMissing(self):
2477 """Test failing to locate an image header"""
2478 data = self._DoReadFile('005_simple.dts')
2479 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2480
Simon Glassffded752019-07-08 14:25:46 -06002481 def testReadImage(self):
2482 """Test reading an image and accessing its FDT map"""
2483 self._CheckLz4()
2484 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2485 image_fname = tools.GetOutputFilename('image.bin')
2486 orig_image = control.images['image']
2487 image = Image.FromFile(image_fname)
2488 self.assertEqual(orig_image.GetEntries().keys(),
2489 image.GetEntries().keys())
2490
2491 orig_entry = orig_image.GetEntries()['fdtmap']
2492 entry = image.GetEntries()['fdtmap']
2493 self.assertEquals(orig_entry.offset, entry.offset)
2494 self.assertEquals(orig_entry.size, entry.size)
2495 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2496
2497 def testReadImageNoHeader(self):
2498 """Test accessing an image's FDT map without an image header"""
2499 self._CheckLz4()
2500 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
2501 image_fname = tools.GetOutputFilename('image.bin')
2502 image = Image.FromFile(image_fname)
2503 self.assertTrue(isinstance(image, Image))
Simon Glass10f9d002019-07-20 12:23:50 -06002504 self.assertEqual('image', image.image_name[-5:])
Simon Glassffded752019-07-08 14:25:46 -06002505
2506 def testReadImageFail(self):
2507 """Test failing to read an image image's FDT map"""
2508 self._DoReadFile('005_simple.dts')
2509 image_fname = tools.GetOutputFilename('image.bin')
2510 with self.assertRaises(ValueError) as e:
2511 image = Image.FromFile(image_fname)
2512 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glasse073d4e2019-07-08 13:18:56 -06002513
Simon Glass61f564d2019-07-08 14:25:48 -06002514 def testListCmd(self):
2515 """Test listing the files in an image using an Fdtmap"""
2516 self._CheckLz4()
2517 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2518
2519 # lz4 compression size differs depending on the version
2520 image = control.images['image']
2521 entries = image.GetEntries()
2522 section_size = entries['section'].size
2523 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2524 fdtmap_offset = entries['fdtmap'].offset
2525
Simon Glassf86a7362019-07-20 12:24:10 -06002526 try:
2527 tmpdir, updated_fname = self._SetupImageInTmpdir()
2528 with test_util.capture_sys_output() as (stdout, stderr):
2529 self._DoBinman('ls', '-i', updated_fname)
2530 finally:
2531 shutil.rmtree(tmpdir)
Simon Glass61f564d2019-07-08 14:25:48 -06002532 lines = stdout.getvalue().splitlines()
2533 expected = [
2534'Name Image-pos Size Entry-type Offset Uncomp-size',
2535'----------------------------------------------------------------------',
2536'main-section 0 c00 section 0',
2537' u-boot 0 4 u-boot 0',
2538' section 100 %x section 100' % section_size,
2539' cbfs 100 400 cbfs 0',
2540' u-boot 138 4 u-boot 38',
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002541' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glass61f564d2019-07-08 14:25:48 -06002542' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002543' fdtmap %x 3bd fdtmap %x' %
Simon Glass61f564d2019-07-08 14:25:48 -06002544 (fdtmap_offset, fdtmap_offset),
2545' image-header bf8 8 image-header bf8',
2546 ]
2547 self.assertEqual(expected, lines)
2548
2549 def testListCmdFail(self):
2550 """Test failing to list an image"""
2551 self._DoReadFile('005_simple.dts')
Simon Glassf86a7362019-07-20 12:24:10 -06002552 try:
2553 tmpdir, updated_fname = self._SetupImageInTmpdir()
2554 with self.assertRaises(ValueError) as e:
2555 self._DoBinman('ls', '-i', updated_fname)
2556 finally:
2557 shutil.rmtree(tmpdir)
Simon Glass61f564d2019-07-08 14:25:48 -06002558 self.assertIn("Cannot find FDT map in image", str(e.exception))
2559
2560 def _RunListCmd(self, paths, expected):
2561 """List out entries and check the result
2562
2563 Args:
2564 paths: List of paths to pass to the list command
2565 expected: Expected list of filenames to be returned, in order
2566 """
2567 self._CheckLz4()
2568 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2569 image_fname = tools.GetOutputFilename('image.bin')
2570 image = Image.FromFile(image_fname)
2571 lines = image.GetListEntries(paths)[1]
2572 files = [line[0].strip() for line in lines[1:]]
2573 self.assertEqual(expected, files)
2574
2575 def testListCmdSection(self):
2576 """Test listing the files in a section"""
2577 self._RunListCmd(['section'],
2578 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2579
2580 def testListCmdFile(self):
2581 """Test listing a particular file"""
2582 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2583
2584 def testListCmdWildcard(self):
2585 """Test listing a wildcarded file"""
2586 self._RunListCmd(['*boot*'],
2587 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2588
2589 def testListCmdWildcardMulti(self):
2590 """Test listing a wildcarded file"""
2591 self._RunListCmd(['*cb*', '*head*'],
2592 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2593
2594 def testListCmdEmpty(self):
2595 """Test listing a wildcarded file"""
2596 self._RunListCmd(['nothing'], [])
2597
2598 def testListCmdPath(self):
2599 """Test listing the files in a sub-entry of a section"""
2600 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2601
Simon Glassf667e452019-07-08 14:25:50 -06002602 def _RunExtractCmd(self, entry_name, decomp=True):
2603 """Extract an entry from an image
2604
2605 Args:
2606 entry_name: Entry name to extract
2607 decomp: True to decompress the data if compressed, False to leave
2608 it in its raw uncompressed format
2609
2610 Returns:
2611 data from entry
2612 """
2613 self._CheckLz4()
2614 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2615 image_fname = tools.GetOutputFilename('image.bin')
2616 return control.ReadEntry(image_fname, entry_name, decomp)
2617
2618 def testExtractSimple(self):
2619 """Test extracting a single file"""
2620 data = self._RunExtractCmd('u-boot')
2621 self.assertEqual(U_BOOT_DATA, data)
2622
Simon Glass71ce0ba2019-07-08 14:25:52 -06002623 def testExtractSection(self):
2624 """Test extracting the files in a section"""
2625 data = self._RunExtractCmd('section')
2626 cbfs_data = data[:0x400]
2627 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002628 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass71ce0ba2019-07-08 14:25:52 -06002629 dtb_data = data[0x400:]
2630 dtb = self._decompress(dtb_data)
2631 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2632
2633 def testExtractCompressed(self):
2634 """Test extracting compressed data"""
2635 data = self._RunExtractCmd('section/u-boot-dtb')
2636 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2637
2638 def testExtractRaw(self):
2639 """Test extracting compressed data without decompressing it"""
2640 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2641 dtb = self._decompress(data)
2642 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2643
2644 def testExtractCbfs(self):
2645 """Test extracting CBFS data"""
2646 data = self._RunExtractCmd('section/cbfs/u-boot')
2647 self.assertEqual(U_BOOT_DATA, data)
2648
2649 def testExtractCbfsCompressed(self):
2650 """Test extracting CBFS compressed data"""
2651 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2652 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2653
2654 def testExtractCbfsRaw(self):
2655 """Test extracting CBFS compressed data without decompressing it"""
2656 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Simon Glasseb0f4a42019-07-20 12:24:06 -06002657 dtb = tools.Decompress(data, 'lzma', with_header=False)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002658 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2659
Simon Glassf667e452019-07-08 14:25:50 -06002660 def testExtractBadEntry(self):
2661 """Test extracting a bad section path"""
2662 with self.assertRaises(ValueError) as e:
2663 self._RunExtractCmd('section/does-not-exist')
2664 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2665 str(e.exception))
2666
2667 def testExtractMissingFile(self):
2668 """Test extracting file that does not exist"""
2669 with self.assertRaises(IOError) as e:
2670 control.ReadEntry('missing-file', 'name')
2671
2672 def testExtractBadFile(self):
2673 """Test extracting an invalid file"""
2674 fname = os.path.join(self._indir, 'badfile')
2675 tools.WriteFile(fname, b'')
2676 with self.assertRaises(ValueError) as e:
2677 control.ReadEntry(fname, 'name')
2678
Simon Glass71ce0ba2019-07-08 14:25:52 -06002679 def testExtractCmd(self):
2680 """Test extracting a file fron an image on the command line"""
2681 self._CheckLz4()
2682 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass71ce0ba2019-07-08 14:25:52 -06002683 fname = os.path.join(self._indir, 'output.extact')
Simon Glassf86a7362019-07-20 12:24:10 -06002684 try:
2685 tmpdir, updated_fname = self._SetupImageInTmpdir()
2686 with test_util.capture_sys_output() as (stdout, stderr):
2687 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2688 '-f', fname)
2689 finally:
2690 shutil.rmtree(tmpdir)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002691 data = tools.ReadFile(fname)
2692 self.assertEqual(U_BOOT_DATA, data)
2693
2694 def testExtractOneEntry(self):
2695 """Test extracting a single entry fron an image """
2696 self._CheckLz4()
2697 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2698 image_fname = tools.GetOutputFilename('image.bin')
2699 fname = os.path.join(self._indir, 'output.extact')
2700 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
2701 data = tools.ReadFile(fname)
2702 self.assertEqual(U_BOOT_DATA, data)
2703
2704 def _CheckExtractOutput(self, decomp):
2705 """Helper to test file output with and without decompression
2706
2707 Args:
2708 decomp: True to decompress entry data, False to output it raw
2709 """
2710 def _CheckPresent(entry_path, expect_data, expect_size=None):
2711 """Check and remove expected file
2712
2713 This checks the data/size of a file and removes the file both from
2714 the outfiles set and from the output directory. Once all files are
2715 processed, both the set and directory should be empty.
2716
2717 Args:
2718 entry_path: Entry path
2719 expect_data: Data to expect in file, or None to skip check
2720 expect_size: Size of data to expect in file, or None to skip
2721 """
2722 path = os.path.join(outdir, entry_path)
2723 data = tools.ReadFile(path)
2724 os.remove(path)
2725 if expect_data:
2726 self.assertEqual(expect_data, data)
2727 elif expect_size:
2728 self.assertEqual(expect_size, len(data))
2729 outfiles.remove(path)
2730
2731 def _CheckDirPresent(name):
2732 """Remove expected directory
2733
2734 This gives an error if the directory does not exist as expected
2735
2736 Args:
2737 name: Name of directory to remove
2738 """
2739 path = os.path.join(outdir, name)
2740 os.rmdir(path)
2741
2742 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2743 image_fname = tools.GetOutputFilename('image.bin')
2744 outdir = os.path.join(self._indir, 'extract')
2745 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2746
2747 # Create a set of all file that were output (should be 9)
2748 outfiles = set()
2749 for root, dirs, files in os.walk(outdir):
2750 outfiles |= set([os.path.join(root, fname) for fname in files])
2751 self.assertEqual(9, len(outfiles))
2752 self.assertEqual(9, len(einfos))
2753
2754 image = control.images['image']
2755 entries = image.GetEntries()
2756
2757 # Check the 9 files in various ways
2758 section = entries['section']
2759 section_entries = section.GetEntries()
2760 cbfs_entries = section_entries['cbfs'].GetEntries()
2761 _CheckPresent('u-boot', U_BOOT_DATA)
2762 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
2763 dtb_len = EXTRACT_DTB_SIZE
2764 if not decomp:
2765 dtb_len = cbfs_entries['u-boot-dtb'].size
2766 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
2767 if not decomp:
2768 dtb_len = section_entries['u-boot-dtb'].size
2769 _CheckPresent('section/u-boot-dtb', None, dtb_len)
2770
2771 fdtmap = entries['fdtmap']
2772 _CheckPresent('fdtmap', fdtmap.data)
2773 hdr = entries['image-header']
2774 _CheckPresent('image-header', hdr.data)
2775
2776 _CheckPresent('section/root', section.data)
2777 cbfs = section_entries['cbfs']
2778 _CheckPresent('section/cbfs/root', cbfs.data)
2779 data = tools.ReadFile(image_fname)
2780 _CheckPresent('root', data)
2781
2782 # There should be no files left. Remove all the directories to check.
2783 # If there are any files/dirs remaining, one of these checks will fail.
2784 self.assertEqual(0, len(outfiles))
2785 _CheckDirPresent('section/cbfs')
2786 _CheckDirPresent('section')
2787 _CheckDirPresent('')
2788 self.assertFalse(os.path.exists(outdir))
2789
2790 def testExtractAllEntries(self):
2791 """Test extracting all entries"""
2792 self._CheckLz4()
2793 self._CheckExtractOutput(decomp=True)
2794
2795 def testExtractAllEntriesRaw(self):
2796 """Test extracting all entries without decompressing them"""
2797 self._CheckLz4()
2798 self._CheckExtractOutput(decomp=False)
2799
2800 def testExtractSelectedEntries(self):
2801 """Test extracting some entries"""
2802 self._CheckLz4()
2803 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2804 image_fname = tools.GetOutputFilename('image.bin')
2805 outdir = os.path.join(self._indir, 'extract')
2806 einfos = control.ExtractEntries(image_fname, None, outdir,
2807 ['*cb*', '*head*'])
2808
2809 # File output is tested by testExtractAllEntries(), so just check that
2810 # the expected entries are selected
2811 names = [einfo.name for einfo in einfos]
2812 self.assertEqual(names,
2813 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2814
2815 def testExtractNoEntryPaths(self):
2816 """Test extracting some entries"""
2817 self._CheckLz4()
2818 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2819 image_fname = tools.GetOutputFilename('image.bin')
2820 with self.assertRaises(ValueError) as e:
2821 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassbb5edc12019-07-20 12:24:14 -06002822 self.assertIn('Must specify an entry path to write with -f',
Simon Glass71ce0ba2019-07-08 14:25:52 -06002823 str(e.exception))
2824
2825 def testExtractTooManyEntryPaths(self):
2826 """Test extracting some entries"""
2827 self._CheckLz4()
2828 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2829 image_fname = tools.GetOutputFilename('image.bin')
2830 with self.assertRaises(ValueError) as e:
2831 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassbb5edc12019-07-20 12:24:14 -06002832 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass71ce0ba2019-07-08 14:25:52 -06002833 str(e.exception))
2834
Simon Glasse2705fa2019-07-08 14:25:53 -06002835 def testPackAlignSection(self):
2836 """Test that sections can have alignment"""
2837 self._DoReadFile('131_pack_align_section.dts')
2838
2839 self.assertIn('image', control.images)
2840 image = control.images['image']
2841 entries = image.GetEntries()
2842 self.assertEqual(3, len(entries))
2843
2844 # First u-boot
2845 self.assertIn('u-boot', entries)
2846 entry = entries['u-boot']
2847 self.assertEqual(0, entry.offset)
2848 self.assertEqual(0, entry.image_pos)
2849 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2850 self.assertEqual(len(U_BOOT_DATA), entry.size)
2851
2852 # Section0
2853 self.assertIn('section0', entries)
2854 section0 = entries['section0']
2855 self.assertEqual(0x10, section0.offset)
2856 self.assertEqual(0x10, section0.image_pos)
2857 self.assertEqual(len(U_BOOT_DATA), section0.size)
2858
2859 # Second u-boot
2860 section_entries = section0.GetEntries()
2861 self.assertIn('u-boot', section_entries)
2862 entry = section_entries['u-boot']
2863 self.assertEqual(0, entry.offset)
2864 self.assertEqual(0x10, entry.image_pos)
2865 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2866 self.assertEqual(len(U_BOOT_DATA), entry.size)
2867
2868 # Section1
2869 self.assertIn('section1', entries)
2870 section1 = entries['section1']
2871 self.assertEqual(0x14, section1.offset)
2872 self.assertEqual(0x14, section1.image_pos)
2873 self.assertEqual(0x20, section1.size)
2874
2875 # Second u-boot
2876 section_entries = section1.GetEntries()
2877 self.assertIn('u-boot', section_entries)
2878 entry = section_entries['u-boot']
2879 self.assertEqual(0, entry.offset)
2880 self.assertEqual(0x14, entry.image_pos)
2881 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2882 self.assertEqual(len(U_BOOT_DATA), entry.size)
2883
2884 # Section2
2885 self.assertIn('section2', section_entries)
2886 section2 = section_entries['section2']
2887 self.assertEqual(0x4, section2.offset)
2888 self.assertEqual(0x18, section2.image_pos)
2889 self.assertEqual(4, section2.size)
2890
2891 # Third u-boot
2892 section_entries = section2.GetEntries()
2893 self.assertIn('u-boot', section_entries)
2894 entry = section_entries['u-boot']
2895 self.assertEqual(0, entry.offset)
2896 self.assertEqual(0x18, entry.image_pos)
2897 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2898 self.assertEqual(len(U_BOOT_DATA), entry.size)
2899
Simon Glass51014aa2019-07-20 12:23:56 -06002900 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
2901 dts='132_replace.dts'):
Simon Glass10f9d002019-07-20 12:23:50 -06002902 """Replace an entry in an image
2903
2904 This writes the entry data to update it, then opens the updated file and
2905 returns the value that it now finds there.
2906
2907 Args:
2908 entry_name: Entry name to replace
2909 data: Data to replace it with
2910 decomp: True to compress the data if needed, False if data is
2911 already compressed so should be used as is
Simon Glass51014aa2019-07-20 12:23:56 -06002912 allow_resize: True to allow entries to change size, False to raise
2913 an exception
Simon Glass10f9d002019-07-20 12:23:50 -06002914
2915 Returns:
2916 Tuple:
2917 data from entry
2918 data from fdtmap (excluding header)
Simon Glass51014aa2019-07-20 12:23:56 -06002919 Image object that was modified
Simon Glass10f9d002019-07-20 12:23:50 -06002920 """
Simon Glass51014aa2019-07-20 12:23:56 -06002921 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass10f9d002019-07-20 12:23:50 -06002922 update_dtb=True)[1]
2923
2924 self.assertIn('image', control.images)
2925 image = control.images['image']
2926 entries = image.GetEntries()
2927 orig_dtb_data = entries['u-boot-dtb'].data
2928 orig_fdtmap_data = entries['fdtmap'].data
2929
2930 image_fname = tools.GetOutputFilename('image.bin')
2931 updated_fname = tools.GetOutputFilename('image-updated.bin')
2932 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
Simon Glass51014aa2019-07-20 12:23:56 -06002933 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
2934 allow_resize)
Simon Glass10f9d002019-07-20 12:23:50 -06002935 data = control.ReadEntry(updated_fname, entry_name, decomp)
2936
Simon Glass51014aa2019-07-20 12:23:56 -06002937 # The DT data should not change unless resized:
2938 if not allow_resize:
2939 new_dtb_data = entries['u-boot-dtb'].data
2940 self.assertEqual(new_dtb_data, orig_dtb_data)
2941 new_fdtmap_data = entries['fdtmap'].data
2942 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass10f9d002019-07-20 12:23:50 -06002943
Simon Glass51014aa2019-07-20 12:23:56 -06002944 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass10f9d002019-07-20 12:23:50 -06002945
2946 def testReplaceSimple(self):
2947 """Test replacing a single file"""
2948 expected = b'x' * len(U_BOOT_DATA)
Simon Glass51014aa2019-07-20 12:23:56 -06002949 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
2950 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06002951 self.assertEqual(expected, data)
2952
2953 # Test that the state looks right. There should be an FDT for the fdtmap
2954 # that we jsut read back in, and it should match what we find in the
2955 # 'control' tables. Checking for an FDT that does not exist should
2956 # return None.
2957 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glass51014aa2019-07-20 12:23:56 -06002958 self.assertIsNotNone(path)
Simon Glass10f9d002019-07-20 12:23:50 -06002959 self.assertEqual(expected_fdtmap, fdtmap)
2960
2961 dtb = state.GetFdtForEtype('fdtmap')
2962 self.assertEqual(dtb.GetContents(), fdtmap)
2963
2964 missing_path, missing_fdtmap = state.GetFdtContents('missing')
2965 self.assertIsNone(missing_path)
2966 self.assertIsNone(missing_fdtmap)
2967
2968 missing_dtb = state.GetFdtForEtype('missing')
2969 self.assertIsNone(missing_dtb)
2970
2971 self.assertEqual('/binman', state.fdt_path_prefix)
2972
2973 def testReplaceResizeFail(self):
2974 """Test replacing a file by something larger"""
2975 expected = U_BOOT_DATA + b'x'
2976 with self.assertRaises(ValueError) as e:
Simon Glass51014aa2019-07-20 12:23:56 -06002977 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
2978 dts='139_replace_repack.dts')
Simon Glass10f9d002019-07-20 12:23:50 -06002979 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
2980 str(e.exception))
2981
2982 def testReplaceMulti(self):
2983 """Test replacing entry data where multiple images are generated"""
2984 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
2985 update_dtb=True)[0]
2986 expected = b'x' * len(U_BOOT_DATA)
2987 updated_fname = tools.GetOutputFilename('image-updated.bin')
2988 tools.WriteFile(updated_fname, data)
2989 entry_name = 'u-boot'
Simon Glass51014aa2019-07-20 12:23:56 -06002990 control.WriteEntry(updated_fname, entry_name, expected,
2991 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06002992 data = control.ReadEntry(updated_fname, entry_name)
2993 self.assertEqual(expected, data)
2994
2995 # Check the state looks right.
2996 self.assertEqual('/binman/image', state.fdt_path_prefix)
2997
2998 # Now check we can write the first image
2999 image_fname = tools.GetOutputFilename('first-image.bin')
3000 updated_fname = tools.GetOutputFilename('first-updated.bin')
3001 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
3002 entry_name = 'u-boot'
Simon Glass51014aa2019-07-20 12:23:56 -06003003 control.WriteEntry(updated_fname, entry_name, expected,
3004 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06003005 data = control.ReadEntry(updated_fname, entry_name)
3006 self.assertEqual(expected, data)
3007
3008 # Check the state looks right.
3009 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass8beb11e2019-07-08 14:25:47 -06003010
Simon Glass12bb1a92019-07-20 12:23:51 -06003011 def testUpdateFdtAllRepack(self):
3012 """Test that all device trees are updated with offset/size info"""
3013 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3014 SECTION_SIZE = 0x300
3015 DTB_SIZE = 602
3016 FDTMAP_SIZE = 608
3017 base_expected = {
3018 'offset': 0,
3019 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3020 'image-pos': 0,
3021 'section:offset': 0,
3022 'section:size': SECTION_SIZE,
3023 'section:image-pos': 0,
3024 'section/u-boot-dtb:offset': 4,
3025 'section/u-boot-dtb:size': 636,
3026 'section/u-boot-dtb:image-pos': 4,
3027 'u-boot-spl-dtb:offset': SECTION_SIZE,
3028 'u-boot-spl-dtb:size': DTB_SIZE,
3029 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3030 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3031 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3032 'u-boot-tpl-dtb:size': DTB_SIZE,
3033 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3034 'fdtmap:size': FDTMAP_SIZE,
3035 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3036 }
3037 main_expected = {
3038 'section:orig-size': SECTION_SIZE,
3039 'section/u-boot-dtb:orig-offset': 4,
3040 }
3041
3042 # We expect three device-tree files in the output, with the first one
3043 # within a fixed-size section.
3044 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3045 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3046 # main U-Boot tree. All three should have the same positions and offset
3047 # except that the main tree should include the main_expected properties
3048 start = 4
3049 for item in ['', 'spl', 'tpl', None]:
3050 if item is None:
3051 start += 16 # Move past fdtmap header
3052 dtb = fdt.Fdt.FromData(data[start:])
3053 dtb.Scan()
3054 props = self._GetPropTree(dtb,
3055 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3056 prefix='/' if item is None else '/binman/')
3057 expected = dict(base_expected)
3058 if item:
3059 expected[item] = 0
3060 else:
3061 # Main DTB and fdtdec should include the 'orig-' properties
3062 expected.update(main_expected)
3063 # Helpful for debugging:
3064 #for prop in sorted(props):
3065 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3066 self.assertEqual(expected, props)
3067 if item == '':
3068 start = SECTION_SIZE
3069 else:
3070 start += dtb._fdt_obj.totalsize()
3071
Simon Glasseba1f0c2019-07-20 12:23:55 -06003072 def testFdtmapHeaderMiddle(self):
3073 """Test an FDT map in the middle of an image when it should be at end"""
3074 with self.assertRaises(ValueError) as e:
3075 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3076 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3077 str(e.exception))
3078
3079 def testFdtmapHeaderStartBad(self):
3080 """Test an FDT map in middle of an image when it should be at start"""
3081 with self.assertRaises(ValueError) as e:
3082 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3083 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3084 str(e.exception))
3085
3086 def testFdtmapHeaderEndBad(self):
3087 """Test an FDT map at the start of an image when it should be at end"""
3088 with self.assertRaises(ValueError) as e:
3089 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3090 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3091 str(e.exception))
3092
3093 def testFdtmapHeaderNoSize(self):
3094 """Test an image header at the end of an image with undefined size"""
3095 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3096
Simon Glass51014aa2019-07-20 12:23:56 -06003097 def testReplaceResize(self):
3098 """Test replacing a single file in an entry with a larger file"""
3099 expected = U_BOOT_DATA + b'x'
3100 data, _, image = self._RunReplaceCmd('u-boot', expected,
3101 dts='139_replace_repack.dts')
3102 self.assertEqual(expected, data)
3103
3104 entries = image.GetEntries()
3105 dtb_data = entries['u-boot-dtb'].data
3106 dtb = fdt.Fdt.FromData(dtb_data)
3107 dtb.Scan()
3108
3109 # The u-boot section should now be larger in the dtb
3110 node = dtb.GetNode('/binman/u-boot')
3111 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3112
3113 # Same for the fdtmap
3114 fdata = entries['fdtmap'].data
3115 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3116 fdtb.Scan()
3117 fnode = fdtb.GetNode('/u-boot')
3118 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3119
3120 def testReplaceResizeNoRepack(self):
3121 """Test replacing an entry with a larger file when not allowed"""
3122 expected = U_BOOT_DATA + b'x'
3123 with self.assertRaises(ValueError) as e:
3124 self._RunReplaceCmd('u-boot', expected)
3125 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3126 str(e.exception))
3127
Simon Glass61ec04f2019-07-20 12:23:58 -06003128 def testEntryShrink(self):
3129 """Test contracting an entry after it is packed"""
3130 try:
3131 state.SetAllowEntryContraction(True)
3132 data = self._DoReadFileDtb('140_entry_shrink.dts',
3133 update_dtb=True)[0]
3134 finally:
3135 state.SetAllowEntryContraction(False)
3136 self.assertEqual(b'a', data[:1])
3137 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3138 self.assertEqual(b'a', data[-1:])
3139
3140 def testEntryShrinkFail(self):
3141 """Test not being allowed to contract an entry after it is packed"""
3142 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3143
3144 # In this case there is a spare byte at the end of the data. The size of
3145 # the contents is only 1 byte but we still have the size before it
3146 # shrunk.
3147 self.assertEqual(b'a\0', data[:2])
3148 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3149 self.assertEqual(b'a\0', data[-2:])
3150
Simon Glass27145fd2019-07-20 12:24:01 -06003151 def testDescriptorOffset(self):
3152 """Test that the Intel descriptor is always placed at at the start"""
3153 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3154 image = control.images['image']
3155 entries = image.GetEntries()
3156 desc = entries['intel-descriptor']
3157 self.assertEqual(0xff800000, desc.offset);
3158 self.assertEqual(0xff800000, desc.image_pos);
3159
Simon Glasseb0f4a42019-07-20 12:24:06 -06003160 def testReplaceCbfs(self):
3161 """Test replacing a single file in CBFS without changing the size"""
3162 self._CheckLz4()
3163 expected = b'x' * len(U_BOOT_DATA)
3164 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3165 updated_fname = tools.GetOutputFilename('image-updated.bin')
3166 tools.WriteFile(updated_fname, data)
3167 entry_name = 'section/cbfs/u-boot'
3168 control.WriteEntry(updated_fname, entry_name, expected,
3169 allow_resize=True)
3170 data = control.ReadEntry(updated_fname, entry_name)
3171 self.assertEqual(expected, data)
3172
3173 def testReplaceResizeCbfs(self):
3174 """Test replacing a single file in CBFS with one of a different size"""
3175 self._CheckLz4()
3176 expected = U_BOOT_DATA + b'x'
3177 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3178 updated_fname = tools.GetOutputFilename('image-updated.bin')
3179 tools.WriteFile(updated_fname, data)
3180 entry_name = 'section/cbfs/u-boot'
3181 control.WriteEntry(updated_fname, entry_name, expected,
3182 allow_resize=True)
3183 data = control.ReadEntry(updated_fname, entry_name)
3184 self.assertEqual(expected, data)
3185
Simon Glassa6cb9952019-07-20 12:24:15 -06003186 def _SetupForReplace(self):
3187 """Set up some files to use to replace entries
3188
3189 This generates an image, copies it to a new file, extracts all the files
3190 in it and updates some of them
3191
3192 Returns:
3193 List
3194 Image filename
3195 Output directory
3196 Expected values for updated entries, each a string
3197 """
3198 data = self._DoReadFileRealDtb('143_replace_all.dts')
3199
3200 updated_fname = tools.GetOutputFilename('image-updated.bin')
3201 tools.WriteFile(updated_fname, data)
3202
3203 outdir = os.path.join(self._indir, 'extract')
3204 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3205
3206 expected1 = b'x' + U_BOOT_DATA + b'y'
3207 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3208 tools.WriteFile(u_boot_fname1, expected1)
3209
3210 expected2 = b'a' + U_BOOT_DATA + b'b'
3211 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
3212 tools.WriteFile(u_boot_fname2, expected2)
3213
3214 expected_text = b'not the same text'
3215 text_fname = os.path.join(outdir, 'text')
3216 tools.WriteFile(text_fname, expected_text)
3217
3218 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3219 dtb = fdt.FdtScan(dtb_fname)
3220 node = dtb.GetNode('/binman/text')
3221 node.AddString('my-property', 'the value')
3222 dtb.Sync(auto_resize=True)
3223 dtb.Flush()
3224
3225 return updated_fname, outdir, expected1, expected2, expected_text
3226
3227 def _CheckReplaceMultiple(self, entry_paths):
3228 """Handle replacing the contents of multiple entries
3229
3230 Args:
3231 entry_paths: List of entry paths to replace
3232
3233 Returns:
3234 List
3235 Dict of entries in the image:
3236 key: Entry name
3237 Value: Entry object
3238 Expected values for updated entries, each a string
3239 """
3240 updated_fname, outdir, expected1, expected2, expected_text = (
3241 self._SetupForReplace())
3242 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3243
3244 image = Image.FromFile(updated_fname)
3245 image.LoadData()
3246 return image.GetEntries(), expected1, expected2, expected_text
3247
3248 def testReplaceAll(self):
3249 """Test replacing the contents of all entries"""
3250 entries, expected1, expected2, expected_text = (
3251 self._CheckReplaceMultiple([]))
3252 data = entries['u-boot'].data
3253 self.assertEqual(expected1, data)
3254
3255 data = entries['u-boot2'].data
3256 self.assertEqual(expected2, data)
3257
3258 data = entries['text'].data
3259 self.assertEqual(expected_text, data)
3260
3261 # Check that the device tree is updated
3262 data = entries['u-boot-dtb'].data
3263 dtb = fdt.Fdt.FromData(data)
3264 dtb.Scan()
3265 node = dtb.GetNode('/binman/text')
3266 self.assertEqual('the value', node.props['my-property'].value)
3267
3268 def testReplaceSome(self):
3269 """Test replacing the contents of a few entries"""
3270 entries, expected1, expected2, expected_text = (
3271 self._CheckReplaceMultiple(['u-boot2', 'text']))
3272
3273 # This one should not change
3274 data = entries['u-boot'].data
3275 self.assertEqual(U_BOOT_DATA, data)
3276
3277 data = entries['u-boot2'].data
3278 self.assertEqual(expected2, data)
3279
3280 data = entries['text'].data
3281 self.assertEqual(expected_text, data)
3282
3283 def testReplaceCmd(self):
3284 """Test replacing a file fron an image on the command line"""
3285 self._DoReadFileRealDtb('143_replace_all.dts')
3286
3287 try:
3288 tmpdir, updated_fname = self._SetupImageInTmpdir()
3289
3290 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3291 expected = b'x' * len(U_BOOT_DATA)
3292 tools.WriteFile(fname, expected)
3293
3294 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
3295 data = tools.ReadFile(updated_fname)
3296 self.assertEqual(expected, data[:len(expected)])
3297 map_fname = os.path.join(tmpdir, 'image-updated.map')
3298 self.assertFalse(os.path.exists(map_fname))
3299 finally:
3300 shutil.rmtree(tmpdir)
3301
3302 def testReplaceCmdSome(self):
3303 """Test replacing some files fron an image on the command line"""
3304 updated_fname, outdir, expected1, expected2, expected_text = (
3305 self._SetupForReplace())
3306
3307 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3308 'u-boot2', 'text')
3309
3310 tools.PrepareOutputDir(None)
3311 image = Image.FromFile(updated_fname)
3312 image.LoadData()
3313 entries = image.GetEntries()
3314
3315 # This one should not change
3316 data = entries['u-boot'].data
3317 self.assertEqual(U_BOOT_DATA, data)
3318
3319 data = entries['u-boot2'].data
3320 self.assertEqual(expected2, data)
3321
3322 data = entries['text'].data
3323 self.assertEqual(expected_text, data)
3324
3325 def testReplaceMissing(self):
3326 """Test replacing entries where the file is missing"""
3327 updated_fname, outdir, expected1, expected2, expected_text = (
3328 self._SetupForReplace())
3329
3330 # Remove one of the files, to generate a warning
3331 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3332 os.remove(u_boot_fname1)
3333
3334 with test_util.capture_sys_output() as (stdout, stderr):
3335 control.ReplaceEntries(updated_fname, None, outdir, [])
3336 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass38fdb4c2020-07-09 18:39:39 -06003337 stderr.getvalue())
Simon Glassa6cb9952019-07-20 12:24:15 -06003338
3339 def testReplaceCmdMap(self):
3340 """Test replacing a file fron an image on the command line"""
3341 self._DoReadFileRealDtb('143_replace_all.dts')
3342
3343 try:
3344 tmpdir, updated_fname = self._SetupImageInTmpdir()
3345
3346 fname = os.path.join(self._indir, 'update-u-boot.bin')
3347 expected = b'x' * len(U_BOOT_DATA)
3348 tools.WriteFile(fname, expected)
3349
3350 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3351 '-f', fname, '-m')
3352 map_fname = os.path.join(tmpdir, 'image-updated.map')
3353 self.assertTrue(os.path.exists(map_fname))
3354 finally:
3355 shutil.rmtree(tmpdir)
3356
3357 def testReplaceNoEntryPaths(self):
3358 """Test replacing an entry without an entry path"""
3359 self._DoReadFileRealDtb('143_replace_all.dts')
3360 image_fname = tools.GetOutputFilename('image.bin')
3361 with self.assertRaises(ValueError) as e:
3362 control.ReplaceEntries(image_fname, 'fname', None, [])
3363 self.assertIn('Must specify an entry path to read with -f',
3364 str(e.exception))
3365
3366 def testReplaceTooManyEntryPaths(self):
3367 """Test extracting some entries"""
3368 self._DoReadFileRealDtb('143_replace_all.dts')
3369 image_fname = tools.GetOutputFilename('image.bin')
3370 with self.assertRaises(ValueError) as e:
3371 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3372 self.assertIn('Must specify exactly one entry path to write with -f',
3373 str(e.exception))
3374
Simon Glass2250ee62019-08-24 07:22:48 -06003375 def testPackReset16(self):
3376 """Test that an image with an x86 reset16 region can be created"""
3377 data = self._DoReadFile('144_x86_reset16.dts')
3378 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3379
3380 def testPackReset16Spl(self):
3381 """Test that an image with an x86 reset16-spl region can be created"""
3382 data = self._DoReadFile('145_x86_reset16_spl.dts')
3383 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3384
3385 def testPackReset16Tpl(self):
3386 """Test that an image with an x86 reset16-tpl region can be created"""
3387 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3388 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3389
Simon Glass5af12072019-08-24 07:22:50 -06003390 def testPackIntelFit(self):
3391 """Test that an image with an Intel FIT and pointer can be created"""
3392 data = self._DoReadFile('147_intel_fit.dts')
3393 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3394 fit = data[16:32];
3395 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3396 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3397
3398 image = control.images['image']
3399 entries = image.GetEntries()
3400 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3401 self.assertEqual(expected_ptr, ptr)
3402
3403 def testPackIntelFitMissing(self):
3404 """Test detection of a FIT pointer with not FIT region"""
3405 with self.assertRaises(ValueError) as e:
3406 self._DoReadFile('148_intel_fit_missing.dts')
3407 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3408 str(e.exception))
3409
Simon Glass7c150132019-11-06 17:22:44 -07003410 def _CheckSymbolsTplSection(self, dts, expected_vals):
3411 data = self._DoReadFile(dts)
3412 sym_values = struct.pack('<LQLL', *expected_vals)
Simon Glass2090f1e2019-08-24 07:23:00 -06003413 upto1 = 4 + len(U_BOOT_SPL_DATA)
Simon Glassb87064c2019-08-24 07:23:05 -06003414 expected1 = tools.GetBytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[20:]
Simon Glass2090f1e2019-08-24 07:23:00 -06003415 self.assertEqual(expected1, data[:upto1])
3416
3417 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Simon Glassb87064c2019-08-24 07:23:05 -06003418 expected2 = tools.GetBytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[20:]
Simon Glass2090f1e2019-08-24 07:23:00 -06003419 self.assertEqual(expected2, data[upto1:upto2])
3420
Simon Glasseb0086f2019-08-24 07:23:04 -06003421 upto3 = 0x34 + len(U_BOOT_DATA)
3422 expected3 = tools.GetBytes(0xff, 1) + U_BOOT_DATA
Simon Glass2090f1e2019-08-24 07:23:00 -06003423 self.assertEqual(expected3, data[upto2:upto3])
3424
Simon Glassb87064c2019-08-24 07:23:05 -06003425 expected4 = sym_values + U_BOOT_TPL_DATA[20:]
Simon Glass7c150132019-11-06 17:22:44 -07003426 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3427
3428 def testSymbolsTplSection(self):
3429 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3430 self._SetupSplElf('u_boot_binman_syms')
3431 self._SetupTplElf('u_boot_binman_syms')
3432 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
3433 [0x04, 0x1c, 0x10 + 0x34, 0x04])
3434
3435 def testSymbolsTplSectionX86(self):
3436 """Test binman can assign symbols in a section with end-at-4gb"""
3437 self._SetupSplElf('u_boot_binman_syms_x86')
3438 self._SetupTplElf('u_boot_binman_syms_x86')
3439 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
3440 [0xffffff04, 0xffffff1c, 0xffffff34,
3441 0x04])
Simon Glass2090f1e2019-08-24 07:23:00 -06003442
Simon Glassbf4d0e22019-08-24 07:23:03 -06003443 def testPackX86RomIfwiSectiom(self):
3444 """Test that a section can be placed in an IFWI region"""
3445 self._SetupIfwi('fitimage.bin')
3446 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3447 self._CheckIfwi(data)
3448
Simon Glassea0fff92019-08-24 07:23:07 -06003449 def testPackFspM(self):
3450 """Test that an image with a FSP memory-init binary can be created"""
3451 data = self._DoReadFile('152_intel_fsp_m.dts')
3452 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3453
Simon Glassbc6a88f2019-10-20 21:31:35 -06003454 def testPackFspS(self):
3455 """Test that an image with a FSP silicon-init binary can be created"""
3456 data = self._DoReadFile('153_intel_fsp_s.dts')
3457 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassea0fff92019-08-24 07:23:07 -06003458
Simon Glass998d1482019-10-20 21:31:36 -06003459 def testPackFspT(self):
3460 """Test that an image with a FSP temp-ram-init binary can be created"""
3461 data = self._DoReadFile('154_intel_fsp_t.dts')
3462 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3463
Simon Glass0dc706f2020-07-09 18:39:31 -06003464 def testMkimage(self):
3465 """Test using mkimage to build an image"""
3466 data = self._DoReadFile('156_mkimage.dts')
3467
3468 # Just check that the data appears in the file somewhere
3469 self.assertIn(U_BOOT_SPL_DATA, data)
3470
Simon Glassce867ad2020-07-09 18:39:36 -06003471 def testExtblob(self):
3472 """Test an image with an external blob"""
3473 data = self._DoReadFile('157_blob_ext.dts')
3474 self.assertEqual(REFCODE_DATA, data)
3475
3476 def testExtblobMissing(self):
3477 """Test an image with a missing external blob"""
3478 with self.assertRaises(ValueError) as e:
3479 self._DoReadFile('158_blob_ext_missing.dts')
3480 self.assertIn("Filename 'missing-file' not found in input path",
3481 str(e.exception))
3482
Simon Glass4f9f1052020-07-09 18:39:38 -06003483 def testExtblobMissingOk(self):
3484 """Test an image with an missing external blob that is allowed"""
Simon Glassb1cca952020-07-09 18:39:40 -06003485 with test_util.capture_sys_output() as (stdout, stderr):
3486 self._DoTestFile('158_blob_ext_missing.dts', allow_missing=True)
3487 err = stderr.getvalue()
3488 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
3489
3490 def testExtblobMissingOkSect(self):
3491 """Test an image with an missing external blob that is allowed"""
3492 with test_util.capture_sys_output() as (stdout, stderr):
3493 self._DoTestFile('159_blob_ext_missing_sect.dts',
3494 allow_missing=True)
3495 err = stderr.getvalue()
3496 self.assertRegex(err, "Image 'main-section'.*missing.*: "
3497 "blob-ext blob-ext2")
Simon Glass4f9f1052020-07-09 18:39:38 -06003498
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003499 def testPackX86RomMeMissingDesc(self):
3500 """Test that an missing Intel descriptor entry is allowed"""
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003501 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass52b10dd2020-07-25 15:11:19 -06003502 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003503 err = stderr.getvalue()
3504 self.assertRegex(err,
3505 "Image 'main-section'.*missing.*: intel-descriptor")
3506
3507 def testPackX86RomMissingIfwi(self):
3508 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3509 self._SetupIfwi('fitimage.bin')
3510 pathname = os.path.join(self._indir, 'fitimage.bin')
3511 os.remove(pathname)
3512 with test_util.capture_sys_output() as (stdout, stderr):
3513 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3514 err = stderr.getvalue()
3515 self.assertRegex(err, "Image 'main-section'.*missing.*: intel-ifwi")
3516
Simon Glassb3295fd2020-07-09 18:39:42 -06003517 def testPackOverlap(self):
3518 """Test that zero-size overlapping regions are ignored"""
3519 self._DoTestFile('160_pack_overlap_zero.dts')
3520
Simon Glassfdc34362020-07-09 18:39:45 -06003521 def testSimpleFit(self):
3522 """Test an image with a FIT inside"""
3523 data = self._DoReadFile('161_fit.dts')
3524 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3525 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3526 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3527
3528 # The data should be inside the FIT
3529 dtb = fdt.Fdt.FromData(fit_data)
3530 dtb.Scan()
3531 fnode = dtb.GetNode('/images/kernel')
3532 self.assertIn('data', fnode.props)
3533
3534 fname = os.path.join(self._indir, 'fit_data.fit')
3535 tools.WriteFile(fname, fit_data)
3536 out = tools.Run('dumpimage', '-l', fname)
3537
3538 # Check a few features to make sure the plumbing works. We don't need
3539 # to test the operation of mkimage or dumpimage here. First convert the
3540 # output into a dict where the keys are the fields printed by dumpimage
3541 # and the values are a list of values for each field
3542 lines = out.splitlines()
3543
3544 # Converts "Compression: gzip compressed" into two groups:
3545 # 'Compression' and 'gzip compressed'
3546 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3547 vals = collections.defaultdict(list)
3548 for line in lines:
3549 mat = re_line.match(line)
3550 vals[mat.group(1)].append(mat.group(2))
3551
3552 self.assertEquals('FIT description: test-desc', lines[0])
3553 self.assertIn('Created:', lines[1])
3554 self.assertIn('Image 0 (kernel)', vals)
3555 self.assertIn('Hash value', vals)
3556 data_sizes = vals.get('Data Size')
3557 self.assertIsNotNone(data_sizes)
3558 self.assertEqual(2, len(data_sizes))
3559 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
3560 self.assertEqual(len(U_BOOT_DATA), int(data_sizes[0].split()[0]))
3561 self.assertEqual(len(U_BOOT_SPL_DTB_DATA), int(data_sizes[1].split()[0]))
3562
3563 def testFitExternal(self):
Simon Glasse9d336d2020-09-01 05:13:55 -06003564 """Test an image with an FIT with external images"""
Simon Glassfdc34362020-07-09 18:39:45 -06003565 data = self._DoReadFile('162_fit_external.dts')
3566 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3567
3568 # The data should be outside the FIT
3569 dtb = fdt.Fdt.FromData(fit_data)
3570 dtb.Scan()
3571 fnode = dtb.GetNode('/images/kernel')
3572 self.assertNotIn('data', fnode.props)
Simon Glass12bb1a92019-07-20 12:23:51 -06003573
Alper Nebi Yasak8001d0b2020-08-31 12:58:18 +03003574 def testSectionIgnoreHashSignature(self):
3575 """Test that sections ignore hash, signature nodes for its data"""
3576 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
3577 expected = (U_BOOT_DATA + U_BOOT_DATA)
3578 self.assertEqual(expected, data)
3579
Alper Nebi Yasak3fdeb142020-08-31 12:58:19 +03003580 def testPadInSections(self):
3581 """Test pad-before, pad-after for entries in sections"""
Simon Glassf90d9062020-10-26 17:40:09 -06003582 data, _, _, out_dtb_fname = self._DoReadFileDtb(
3583 '166_pad_in_sections.dts', update_dtb=True)
Alper Nebi Yasak3fdeb142020-08-31 12:58:19 +03003584 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
3585 U_BOOT_DATA + tools.GetBytes(ord('!'), 6) +
3586 U_BOOT_DATA)
3587 self.assertEqual(expected, data)
3588
Simon Glassf90d9062020-10-26 17:40:09 -06003589 dtb = fdt.Fdt(out_dtb_fname)
3590 dtb.Scan()
3591 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
3592 expected = {
3593 'image-pos': 0,
3594 'offset': 0,
3595 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
3596
3597 'section:image-pos': 0,
3598 'section:offset': 0,
3599 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
3600
3601 'section/before:image-pos': 0,
3602 'section/before:offset': 0,
3603 'section/before:size': len(U_BOOT_DATA),
3604
3605 'section/u-boot:image-pos': 4,
3606 'section/u-boot:offset': 4,
3607 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
3608
3609 'section/after:image-pos': 26,
3610 'section/after:offset': 26,
3611 'section/after:size': len(U_BOOT_DATA),
3612 }
3613 self.assertEqual(expected, props)
3614
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03003615 def testFitImageSubentryAlignment(self):
3616 """Test relative alignability of FIT image subentries"""
3617 entry_args = {
3618 'test-id': TEXT_DATA,
3619 }
3620 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
3621 entry_args=entry_args)
3622 dtb = fdt.Fdt.FromData(data)
3623 dtb.Scan()
3624
3625 node = dtb.GetNode('/images/kernel')
3626 data = dtb.GetProps(node)["data"].bytes
3627 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
3628 expected = (tools.GetBytes(0, 0x20) + U_BOOT_SPL_DATA +
3629 tools.GetBytes(0, align_pad) + U_BOOT_DATA)
3630 self.assertEqual(expected, data)
3631
3632 node = dtb.GetNode('/images/fdt-1')
3633 data = dtb.GetProps(node)["data"].bytes
3634 expected = (U_BOOT_SPL_DTB_DATA + tools.GetBytes(0, 20) +
3635 tools.ToBytes(TEXT_DATA) + tools.GetBytes(0, 30) +
3636 U_BOOT_DTB_DATA)
3637 self.assertEqual(expected, data)
3638
3639 def testFitExtblobMissingOk(self):
3640 """Test a FIT with a missing external blob that is allowed"""
3641 with test_util.capture_sys_output() as (stdout, stderr):
3642 self._DoTestFile('168_fit_missing_blob.dts',
3643 allow_missing=True)
3644 err = stderr.getvalue()
Simon Glassb2381432020-09-06 10:39:09 -06003645 self.assertRegex(err, "Image 'main-section'.*missing.*: atf-bl31")
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03003646
Simon Glass3decfa32020-09-01 05:13:54 -06003647 def testBlobNamedByArgMissing(self):
3648 """Test handling of a missing entry arg"""
3649 with self.assertRaises(ValueError) as e:
3650 self._DoReadFile('068_blob_named_by_arg.dts')
3651 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
3652 str(e.exception))
3653
Simon Glassdc2f81a2020-09-01 05:13:58 -06003654 def testPackBl31(self):
3655 """Test that an image with an ATF BL31 binary can be created"""
3656 data = self._DoReadFile('169_atf_bl31.dts')
3657 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
3658
Samuel Holland18bd4552020-10-21 21:12:15 -05003659 def testPackScp(self):
3660 """Test that an image with an SCP binary can be created"""
3661 data = self._DoReadFile('172_scp.dts')
3662 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
3663
Simon Glass6cf99532020-09-01 05:13:59 -06003664 def testFitFdt(self):
3665 """Test an image with an FIT with multiple FDT images"""
3666 def _CheckFdt(seq, expected_data):
3667 """Check the FDT nodes
3668
3669 Args:
3670 seq: Sequence number to check (0 or 1)
3671 expected_data: Expected contents of 'data' property
3672 """
3673 name = 'fdt-%d' % seq
3674 fnode = dtb.GetNode('/images/%s' % name)
3675 self.assertIsNotNone(fnode)
3676 self.assertEqual({'description','type', 'compression', 'data'},
3677 set(fnode.props.keys()))
3678 self.assertEqual(expected_data, fnode.props['data'].bytes)
3679 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
3680 fnode.props['description'].value)
3681
3682 def _CheckConfig(seq, expected_data):
3683 """Check the configuration nodes
3684
3685 Args:
3686 seq: Sequence number to check (0 or 1)
3687 expected_data: Expected contents of 'data' property
3688 """
3689 cnode = dtb.GetNode('/configurations')
3690 self.assertIn('default', cnode.props)
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003691 self.assertEqual('config-2', cnode.props['default'].value)
Simon Glass6cf99532020-09-01 05:13:59 -06003692
3693 name = 'config-%d' % seq
3694 fnode = dtb.GetNode('/configurations/%s' % name)
3695 self.assertIsNotNone(fnode)
3696 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
3697 set(fnode.props.keys()))
3698 self.assertEqual('conf-test-fdt%d.dtb' % seq,
3699 fnode.props['description'].value)
3700 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
3701
3702 entry_args = {
3703 'of-list': 'test-fdt1 test-fdt2',
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003704 'default-dt': 'test-fdt2',
Simon Glass6cf99532020-09-01 05:13:59 -06003705 }
3706 data = self._DoReadFileDtb(
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003707 '172_fit_fdt.dts',
Simon Glass6cf99532020-09-01 05:13:59 -06003708 entry_args=entry_args,
3709 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3710 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3711 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3712
3713 dtb = fdt.Fdt.FromData(fit_data)
3714 dtb.Scan()
3715 fnode = dtb.GetNode('/images/kernel')
3716 self.assertIn('data', fnode.props)
3717
3718 # Check all the properties in fdt-1 and fdt-2
3719 _CheckFdt(1, TEST_FDT1_DATA)
3720 _CheckFdt(2, TEST_FDT2_DATA)
3721
3722 # Check configurations
3723 _CheckConfig(1, TEST_FDT1_DATA)
3724 _CheckConfig(2, TEST_FDT2_DATA)
3725
3726 def testFitFdtMissingList(self):
3727 """Test handling of a missing 'of-list' entry arg"""
3728 with self.assertRaises(ValueError) as e:
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003729 self._DoReadFile('172_fit_fdt.dts')
Simon Glass6cf99532020-09-01 05:13:59 -06003730 self.assertIn("Generator node requires 'of-list' entry argument",
3731 str(e.exception))
3732
3733 def testFitFdtEmptyList(self):
3734 """Test handling of an empty 'of-list' entry arg"""
3735 entry_args = {
3736 'of-list': '',
3737 }
3738 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
3739
3740 def testFitFdtMissingProp(self):
3741 """Test handling of a missing 'fit,fdt-list' property"""
3742 with self.assertRaises(ValueError) as e:
3743 self._DoReadFile('171_fit_fdt_missing_prop.dts')
3744 self.assertIn("Generator node requires 'fit,fdt-list' property",
3745 str(e.exception))
Simon Glassdc2f81a2020-09-01 05:13:58 -06003746
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003747 def testFitFdtEmptyList(self):
3748 """Test handling of an empty 'of-list' entry arg"""
3749 entry_args = {
3750 'of-list': '',
3751 }
3752 data = self._DoReadFileDtb('172_fit_fdt.dts', entry_args=entry_args)[0]
3753
3754 def testFitFdtMissing(self):
3755 """Test handling of a missing 'default-dt' entry arg"""
3756 entry_args = {
3757 'of-list': 'test-fdt1 test-fdt2',
3758 }
3759 with self.assertRaises(ValueError) as e:
3760 self._DoReadFileDtb(
3761 '172_fit_fdt.dts',
3762 entry_args=entry_args,
3763 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3764 self.assertIn("Generated 'default' node requires default-dt entry argument",
3765 str(e.exception))
3766
3767 def testFitFdtNotInList(self):
3768 """Test handling of a default-dt that is not in the of-list"""
3769 entry_args = {
3770 'of-list': 'test-fdt1 test-fdt2',
3771 'default-dt': 'test-fdt3',
3772 }
3773 with self.assertRaises(ValueError) as e:
3774 self._DoReadFileDtb(
3775 '172_fit_fdt.dts',
3776 entry_args=entry_args,
3777 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3778 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
3779 str(e.exception))
3780
Simon Glassb2381432020-09-06 10:39:09 -06003781 def testFitExtblobMissingHelp(self):
3782 """Test display of help messages when an external blob is missing"""
3783 control.missing_blob_help = control._ReadMissingBlobHelp()
3784 control.missing_blob_help['wibble'] = 'Wibble test'
3785 control.missing_blob_help['another'] = 'Another test'
3786 with test_util.capture_sys_output() as (stdout, stderr):
3787 self._DoTestFile('168_fit_missing_blob.dts',
3788 allow_missing=True)
3789 err = stderr.getvalue()
3790
3791 # We can get the tag from the name, the type or the missing-msg
3792 # property. Check all three.
3793 self.assertIn('You may need to build ARM Trusted', err)
3794 self.assertIn('Wibble test', err)
3795 self.assertIn('Another test', err)
3796
Simon Glass204aa782020-09-06 10:35:32 -06003797 def testMissingBlob(self):
3798 """Test handling of a blob containing a missing file"""
3799 with self.assertRaises(ValueError) as e:
3800 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
3801 self.assertIn("Filename 'missing' not found in input path",
3802 str(e.exception))
3803
Simon Glassfb91d562020-09-06 10:35:33 -06003804 def testEnvironment(self):
3805 """Test adding a U-Boot environment"""
3806 data = self._DoReadFile('174_env.dts')
3807 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3808 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3809 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3810 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
3811 env)
3812
3813 def testEnvironmentNoSize(self):
3814 """Test that a missing 'size' property is detected"""
3815 with self.assertRaises(ValueError) as e:
Simon Glassa4dfe3e2020-10-26 17:40:00 -06003816 self._DoTestFile('175_env_no_size.dts')
Simon Glassfb91d562020-09-06 10:35:33 -06003817 self.assertIn("'u-boot-env' entry must have a size property",
3818 str(e.exception))
3819
3820 def testEnvironmentTooSmall(self):
3821 """Test handling of an environment that does not fit"""
3822 with self.assertRaises(ValueError) as e:
Simon Glassa4dfe3e2020-10-26 17:40:00 -06003823 self._DoTestFile('176_env_too_small.dts')
Simon Glassfb91d562020-09-06 10:35:33 -06003824
3825 # checksum, start byte, environment with \0 terminator, final \0
3826 need = 4 + 1 + len(ENV_DATA) + 1 + 1
3827 short = need - 0x8
3828 self.assertIn("too small to hold data (need %#x more bytes)" % short,
3829 str(e.exception))
3830
Simon Glassf2c0dd82020-10-26 17:40:01 -06003831 def testSkipAtStart(self):
3832 """Test handling of skip-at-start section"""
3833 data = self._DoReadFile('177_skip_at_start.dts')
3834 self.assertEqual(U_BOOT_DATA, data)
3835
3836 image = control.images['image']
3837 entries = image.GetEntries()
3838 section = entries['section']
3839 self.assertEqual(0, section.offset)
3840 self.assertEqual(len(U_BOOT_DATA), section.size)
3841 self.assertEqual(U_BOOT_DATA, section.GetData())
3842
3843 entry = section.GetEntries()['u-boot']
3844 self.assertEqual(16, entry.offset)
3845 self.assertEqual(len(U_BOOT_DATA), entry.size)
3846 self.assertEqual(U_BOOT_DATA, entry.data)
3847
3848 def testSkipAtStartPad(self):
3849 """Test handling of skip-at-start section with padded entry"""
3850 data = self._DoReadFile('178_skip_at_start_pad.dts')
3851 before = tools.GetBytes(0, 8)
3852 after = tools.GetBytes(0, 4)
3853 all = before + U_BOOT_DATA + after
3854 self.assertEqual(all, data)
3855
3856 image = control.images['image']
3857 entries = image.GetEntries()
3858 section = entries['section']
3859 self.assertEqual(0, section.offset)
3860 self.assertEqual(len(all), section.size)
3861 self.assertEqual(all, section.GetData())
3862
3863 entry = section.GetEntries()['u-boot']
3864 self.assertEqual(16, entry.offset)
3865 self.assertEqual(len(all), entry.size)
3866 self.assertEqual(U_BOOT_DATA, entry.data)
3867
3868 def testSkipAtStartSectionPad(self):
3869 """Test handling of skip-at-start section with padding"""
3870 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
3871 before = tools.GetBytes(0, 8)
3872 after = tools.GetBytes(0, 4)
3873 all = before + U_BOOT_DATA + after
Simon Glassd1d3ad72020-10-26 17:40:13 -06003874 self.assertEqual(all, data)
Simon Glassf2c0dd82020-10-26 17:40:01 -06003875
3876 image = control.images['image']
3877 entries = image.GetEntries()
3878 section = entries['section']
3879 self.assertEqual(0, section.offset)
3880 self.assertEqual(len(all), section.size)
3881 self.assertIsNone(section.data)
Simon Glassd1d3ad72020-10-26 17:40:13 -06003882 self.assertEqual(all, section.GetPaddedData())
Simon Glassf2c0dd82020-10-26 17:40:01 -06003883
3884 entry = section.GetEntries()['u-boot']
3885 self.assertEqual(16, entry.offset)
3886 self.assertEqual(len(U_BOOT_DATA), entry.size)
3887 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassfb91d562020-09-06 10:35:33 -06003888
Simon Glass9fc60b42017-11-12 21:52:22 -07003889if __name__ == "__main__":
3890 unittest.main()