blob: 4f7e22612cc7b627d127f3486033561346d6aed3 [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 Glass741f2d62018-10-01 12:22:30 -0600788 retcode = self._DoTestFile('009_pack_extra.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700789
790 self.assertEqual(0, retcode)
791 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)
802
803 # Second u-boot has an aligned size, but it has no effect
804 self.assertIn('u-boot-align-size-nop', entries)
805 entry = entries['u-boot-align-size-nop']
Simon Glass3ab95982018-08-01 15:22:37 -0600806 self.assertEqual(12, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700807 self.assertEqual(4, entry.size)
808
809 # Third u-boot has an aligned size too
810 self.assertIn('u-boot-align-size', entries)
811 entry = entries['u-boot-align-size']
Simon Glass3ab95982018-08-01 15:22:37 -0600812 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700813 self.assertEqual(32, entry.size)
814
815 # Fourth u-boot has an aligned end
816 self.assertIn('u-boot-align-end', entries)
817 entry = entries['u-boot-align-end']
Simon Glass3ab95982018-08-01 15:22:37 -0600818 self.assertEqual(48, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700819 self.assertEqual(16, entry.size)
820
821 # Fifth u-boot immediately afterwards
822 self.assertIn('u-boot-align-both', entries)
823 entry = entries['u-boot-align-both']
Simon Glass3ab95982018-08-01 15:22:37 -0600824 self.assertEqual(64, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700825 self.assertEqual(64, entry.size)
826
827 self.CheckNoGaps(entries)
Simon Glass8beb11e2019-07-08 14:25:47 -0600828 self.assertEqual(128, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700829
830 def testPackAlignPowerOf2(self):
831 """Test that invalid entry alignment is detected"""
832 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600833 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700834 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
835 "of two", str(e.exception))
836
837 def testPackAlignSizePowerOf2(self):
838 """Test that invalid entry size alignment is detected"""
839 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600840 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700841 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
842 "power of two", str(e.exception))
843
844 def testPackInvalidAlign(self):
Simon Glass3ab95982018-08-01 15:22:37 -0600845 """Test detection of an offset that does not match its alignment"""
Simon Glass4f443042016-11-25 20:15:52 -0700846 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600847 self._DoTestFile('012_pack_inv_align.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600848 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700849 "align 0x4 (4)", str(e.exception))
850
851 def testPackInvalidSizeAlign(self):
852 """Test that invalid entry size alignment is detected"""
853 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600854 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700855 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
856 "align-size 0x4 (4)", str(e.exception))
857
858 def testPackOverlap(self):
859 """Test that overlapping regions are detected"""
860 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600861 self._DoTestFile('014_pack_overlap.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600862 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -0700863 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
864 str(e.exception))
865
866 def testPackEntryOverflow(self):
867 """Test that entries that overflow their size are detected"""
868 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600869 self._DoTestFile('015_pack_overflow.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700870 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
871 "but entry size is 0x3 (3)", str(e.exception))
872
873 def testPackImageOverflow(self):
874 """Test that entries which overflow the image size are detected"""
875 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600876 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600877 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass4f443042016-11-25 20:15:52 -0700878 "size 0x3 (3)", str(e.exception))
879
880 def testPackImageSize(self):
881 """Test that the image size can be set"""
Simon Glass741f2d62018-10-01 12:22:30 -0600882 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700883 self.assertEqual(0, retcode)
884 self.assertIn('image', control.images)
885 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -0600886 self.assertEqual(7, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700887
888 def testPackImageSizeAlign(self):
889 """Test that image size alignemnt works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600890 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700891 self.assertEqual(0, retcode)
892 self.assertIn('image', control.images)
893 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -0600894 self.assertEqual(16, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700895
896 def testPackInvalidImageAlign(self):
897 """Test that invalid image alignment is detected"""
898 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600899 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600900 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700901 "align-size 0x8 (8)", str(e.exception))
902
903 def testPackAlignPowerOf2(self):
904 """Test that invalid image alignment is detected"""
905 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600906 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -0600907 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass4f443042016-11-25 20:15:52 -0700908 "two", str(e.exception))
909
910 def testImagePadByte(self):
911 """Test that the image pad byte can be specified"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600912 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600913 data = self._DoReadFile('021_image_pad.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -0600914 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0xff, 1) +
915 U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -0700916
917 def testImageName(self):
918 """Test that image files can be named"""
Simon Glass741f2d62018-10-01 12:22:30 -0600919 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700920 self.assertEqual(0, retcode)
921 image = control.images['image1']
922 fname = tools.GetOutputFilename('test-name')
923 self.assertTrue(os.path.exists(fname))
924
925 image = control.images['image2']
926 fname = tools.GetOutputFilename('test-name.xx')
927 self.assertTrue(os.path.exists(fname))
928
929 def testBlobFilename(self):
930 """Test that generic blobs can be provided by filename"""
Simon Glass741f2d62018-10-01 12:22:30 -0600931 data = self._DoReadFile('023_blob.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700932 self.assertEqual(BLOB_DATA, data)
933
934 def testPackSorted(self):
935 """Test that entries can be sorted"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600936 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600937 data = self._DoReadFile('024_sorted.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -0600938 self.assertEqual(tools.GetBytes(0, 1) + U_BOOT_SPL_DATA +
939 tools.GetBytes(0, 2) + U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -0700940
Simon Glass3ab95982018-08-01 15:22:37 -0600941 def testPackZeroOffset(self):
942 """Test that an entry at offset 0 is not given a new offset"""
Simon Glass4f443042016-11-25 20:15:52 -0700943 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600944 self._DoTestFile('025_pack_zero_size.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600945 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -0700946 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
947 str(e.exception))
948
949 def testPackUbootDtb(self):
950 """Test that a device tree can be added to U-Boot"""
Simon Glass741f2d62018-10-01 12:22:30 -0600951 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700952 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glasse0ff8552016-11-25 20:15:53 -0700953
954 def testPackX86RomNoSize(self):
955 """Test that the end-at-4gb property requires a size property"""
956 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600957 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -0600958 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glasse0ff8552016-11-25 20:15:53 -0700959 "using end-at-4gb", str(e.exception))
960
Jagdish Gediya94b57db2018-09-03 21:35:07 +0530961 def test4gbAndSkipAtStartTogether(self):
962 """Test that the end-at-4gb and skip-at-size property can't be used
963 together"""
964 with self.assertRaises(ValueError) as e:
Simon Glassdfdd2b62019-08-24 07:23:02 -0600965 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -0600966 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya94b57db2018-09-03 21:35:07 +0530967 "'skip-at-start'", str(e.exception))
968
Simon Glasse0ff8552016-11-25 20:15:53 -0700969 def testPackX86RomOutside(self):
Simon Glass3ab95982018-08-01 15:22:37 -0600970 """Test that the end-at-4gb property checks for offset boundaries"""
Simon Glasse0ff8552016-11-25 20:15:53 -0700971 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600972 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glasse6bed4f2020-10-26 17:40:05 -0600973 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
974 "is outside the section '/binman' starting at "
975 '0xffffffe0 (4294967264) of size 0x20 (32)',
Simon Glasse0ff8552016-11-25 20:15:53 -0700976 str(e.exception))
977
978 def testPackX86Rom(self):
979 """Test that a basic x86 ROM can be created"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600980 self._SetupSplElf()
Simon Glass9255f3c2019-08-24 07:23:01 -0600981 data = self._DoReadFile('029_x86_rom.dts')
Simon Glasseb0086f2019-08-24 07:23:04 -0600982 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 3) + U_BOOT_SPL_DATA +
Simon Glasse6d85ff2019-05-14 15:53:47 -0600983 tools.GetBytes(0, 2), data)
Simon Glasse0ff8552016-11-25 20:15:53 -0700984
985 def testPackX86RomMeNoDesc(self):
986 """Test that an invalid Intel descriptor entry is detected"""
Simon Glass0ba4b3d2020-07-09 18:39:41 -0600987 try:
Simon Glass52b10dd2020-07-25 15:11:19 -0600988 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
Simon Glass0ba4b3d2020-07-09 18:39:41 -0600989 with self.assertRaises(ValueError) as e:
Simon Glass52b10dd2020-07-25 15:11:19 -0600990 self._DoTestFile('163_x86_rom_me_empty.dts')
Simon Glass0ba4b3d2020-07-09 18:39:41 -0600991 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
992 str(e.exception))
993 finally:
994 self._SetupDescriptor()
Simon Glasse0ff8552016-11-25 20:15:53 -0700995
996 def testPackX86RomBadDesc(self):
997 """Test that the Intel requires a descriptor entry"""
998 with self.assertRaises(ValueError) as e:
Simon Glass9255f3c2019-08-24 07:23:01 -0600999 self._DoTestFile('030_x86_rom_me_no_desc.dts')
Simon Glass3ab95982018-08-01 15:22:37 -06001000 self.assertIn("Node '/binman/intel-me': No offset set with "
1001 "offset-unset: should another entry provide this correct "
1002 "offset?", str(e.exception))
Simon Glasse0ff8552016-11-25 20:15:53 -07001003
1004 def testPackX86RomMe(self):
1005 """Test that an x86 ROM with an ME region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001006 data = self._DoReadFile('031_x86_rom_me.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06001007 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
1008 if data[:0x1000] != expected_desc:
1009 self.fail('Expected descriptor binary at start of image')
Simon Glasse0ff8552016-11-25 20:15:53 -07001010 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1011
1012 def testPackVga(self):
1013 """Test that an image with a VGA binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001014 data = self._DoReadFile('032_intel_vga.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -07001015 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1016
1017 def testPackStart16(self):
1018 """Test that an image with an x86 start16 region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001019 data = self._DoReadFile('033_x86_start16.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -07001020 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1021
Jagdish Gediya9d368f32018-09-03 21:35:08 +05301022 def testPackPowerpcMpc85xxBootpgResetvec(self):
1023 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1024 created"""
Simon Glassdfdd2b62019-08-24 07:23:02 -06001025 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
Jagdish Gediya9d368f32018-09-03 21:35:08 +05301026 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1027
Simon Glass736bb0a2018-07-06 10:27:17 -06001028 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glassadc57012018-07-06 10:27:16 -06001029 """Handle running a test for insertion of microcode
1030
1031 Args:
1032 dts_fname: Name of test .dts file
1033 nodtb_data: Data that we expect in the first section
Simon Glass736bb0a2018-07-06 10:27:17 -06001034 ucode_second: True if the microsecond entry is second instead of
1035 third
Simon Glassadc57012018-07-06 10:27:16 -06001036
1037 Returns:
1038 Tuple:
1039 Contents of first region (U-Boot or SPL)
Simon Glass3ab95982018-08-01 15:22:37 -06001040 Offset and size components of microcode pointer, as inserted
Simon Glassadc57012018-07-06 10:27:16 -06001041 in the above (two 4-byte words)
1042 """
Simon Glass6b187df2017-11-12 21:52:27 -07001043 data = self._DoReadFile(dts_fname, True)
Simon Glasse0ff8552016-11-25 20:15:53 -07001044
1045 # Now check the device tree has no microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001046 if ucode_second:
1047 ucode_content = data[len(nodtb_data):]
1048 ucode_pos = len(nodtb_data)
1049 dtb_with_ucode = ucode_content[16:]
1050 fdt_len = self.GetFdtLen(dtb_with_ucode)
1051 else:
1052 dtb_with_ucode = data[len(nodtb_data):]
1053 fdt_len = self.GetFdtLen(dtb_with_ucode)
1054 ucode_content = dtb_with_ucode[fdt_len:]
1055 ucode_pos = len(nodtb_data) + fdt_len
Simon Glasse0ff8552016-11-25 20:15:53 -07001056 fname = tools.GetOutputFilename('test.dtb')
1057 with open(fname, 'wb') as fd:
Simon Glassadc57012018-07-06 10:27:16 -06001058 fd.write(dtb_with_ucode)
Simon Glassec3f3782017-05-27 07:38:29 -06001059 dtb = fdt.FdtScan(fname)
1060 ucode = dtb.GetNode('/microcode')
Simon Glasse0ff8552016-11-25 20:15:53 -07001061 self.assertTrue(ucode)
1062 for node in ucode.subnodes:
1063 self.assertFalse(node.props.get('data'))
1064
Simon Glasse0ff8552016-11-25 20:15:53 -07001065 # Check that the microcode appears immediately after the Fdt
1066 # This matches the concatenation of the data properties in
Simon Glass87722132017-11-12 21:52:26 -07001067 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glasse0ff8552016-11-25 20:15:53 -07001068 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1069 0x78235609)
Simon Glassadc57012018-07-06 10:27:16 -06001070 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glasse0ff8552016-11-25 20:15:53 -07001071
1072 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -06001073 # expected offset and size
Simon Glasse0ff8552016-11-25 20:15:53 -07001074 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1075 len(ucode_data))
Simon Glass736bb0a2018-07-06 10:27:17 -06001076 u_boot = data[:len(nodtb_data)]
1077 return u_boot, pos_and_size
Simon Glass6b187df2017-11-12 21:52:27 -07001078
1079 def testPackUbootMicrocode(self):
1080 """Test that x86 microcode can be handled correctly
1081
1082 We expect to see the following in the image, in order:
1083 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1084 place
1085 u-boot.dtb with the microcode removed
1086 the microcode
1087 """
Simon Glass741f2d62018-10-01 12:22:30 -06001088 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass6b187df2017-11-12 21:52:27 -07001089 U_BOOT_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001090 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1091 b' somewhere in here', first)
Simon Glasse0ff8552016-11-25 20:15:53 -07001092
Simon Glass160a7662017-05-27 07:38:26 -06001093 def _RunPackUbootSingleMicrocode(self):
Simon Glasse0ff8552016-11-25 20:15:53 -07001094 """Test that x86 microcode can be handled correctly
1095
1096 We expect to see the following in the image, in order:
1097 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1098 place
1099 u-boot.dtb with the microcode
1100 an empty microcode region
1101 """
1102 # We need the libfdt library to run this test since only that allows
1103 # finding the offset of a property. This is required by
1104 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass741f2d62018-10-01 12:22:30 -06001105 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glasse0ff8552016-11-25 20:15:53 -07001106
1107 second = data[len(U_BOOT_NODTB_DATA):]
1108
1109 fdt_len = self.GetFdtLen(second)
1110 third = second[fdt_len:]
1111 second = second[:fdt_len]
1112
Simon Glass160a7662017-05-27 07:38:26 -06001113 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1114 self.assertIn(ucode_data, second)
1115 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -07001116
Simon Glass160a7662017-05-27 07:38:26 -06001117 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -06001118 # expected offset and size
Simon Glass160a7662017-05-27 07:38:26 -06001119 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1120 len(ucode_data))
1121 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glassc6c10e72019-05-17 22:00:46 -06001122 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1123 b' somewhere in here', first)
Simon Glassc49deb82016-11-25 20:15:54 -07001124
Simon Glass75db0862016-11-25 20:15:55 -07001125 def testPackUbootSingleMicrocode(self):
1126 """Test that x86 microcode can be handled correctly with fdt_normal.
1127 """
Simon Glass160a7662017-05-27 07:38:26 -06001128 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001129
Simon Glassc49deb82016-11-25 20:15:54 -07001130 def testUBootImg(self):
1131 """Test that u-boot.img can be put in a file"""
Simon Glass741f2d62018-10-01 12:22:30 -06001132 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glassc49deb82016-11-25 20:15:54 -07001133 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glass75db0862016-11-25 20:15:55 -07001134
1135 def testNoMicrocode(self):
1136 """Test that a missing microcode region is detected"""
1137 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001138 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001139 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1140 "node found in ", str(e.exception))
1141
1142 def testMicrocodeWithoutNode(self):
1143 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1144 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001145 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001146 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1147 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1148
1149 def testMicrocodeWithoutNode2(self):
1150 """Test that a missing u-boot-ucode node is detected"""
1151 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001152 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001153 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1154 "microcode region u-boot-ucode", str(e.exception))
1155
1156 def testMicrocodeWithoutPtrInElf(self):
1157 """Test that a U-Boot binary without the microcode symbol is detected"""
1158 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glass75db0862016-11-25 20:15:55 -07001159 try:
Simon Glassbccd91d2019-08-24 07:22:55 -06001160 TestFunctional._MakeInputFile('u-boot',
1161 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass75db0862016-11-25 20:15:55 -07001162
1163 with self.assertRaises(ValueError) as e:
Simon Glass160a7662017-05-27 07:38:26 -06001164 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001165 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1166 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1167
1168 finally:
1169 # Put the original file back
Simon Glassf514d8f2019-08-24 07:22:54 -06001170 TestFunctional._MakeInputFile('u-boot',
1171 tools.ReadFile(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glass75db0862016-11-25 20:15:55 -07001172
1173 def testMicrocodeNotInImage(self):
1174 """Test that microcode must be placed within the image"""
1175 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001176 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001177 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1178 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glass25ac0e62018-06-01 09:38:14 -06001179 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glass75db0862016-11-25 20:15:55 -07001180
1181 def testWithoutMicrocode(self):
1182 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glassbccd91d2019-08-24 07:22:55 -06001183 TestFunctional._MakeInputFile('u-boot',
1184 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass741f2d62018-10-01 12:22:30 -06001185 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001186
1187 # Now check the device tree has no microcode
1188 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1189 second = data[len(U_BOOT_NODTB_DATA):]
1190
1191 fdt_len = self.GetFdtLen(second)
1192 self.assertEqual(dtb, second[:fdt_len])
1193
1194 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1195 third = data[used_len:]
Simon Glasse6d85ff2019-05-14 15:53:47 -06001196 self.assertEqual(tools.GetBytes(0, 0x200 - used_len), third)
Simon Glass75db0862016-11-25 20:15:55 -07001197
1198 def testUnknownPosSize(self):
1199 """Test that microcode must be placed within the image"""
1200 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001201 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glass3ab95982018-08-01 15:22:37 -06001202 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glass75db0862016-11-25 20:15:55 -07001203 "entry 'invalid-entry'", str(e.exception))
Simon Glassda229092016-11-25 20:15:56 -07001204
1205 def testPackFsp(self):
1206 """Test that an image with a FSP binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001207 data = self._DoReadFile('042_intel_fsp.dts')
Simon Glassda229092016-11-25 20:15:56 -07001208 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1209
1210 def testPackCmc(self):
Bin Meng59ea8c22017-08-15 22:41:54 -07001211 """Test that an image with a CMC binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001212 data = self._DoReadFile('043_intel_cmc.dts')
Simon Glassda229092016-11-25 20:15:56 -07001213 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Meng59ea8c22017-08-15 22:41:54 -07001214
1215 def testPackVbt(self):
1216 """Test that an image with a VBT binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001217 data = self._DoReadFile('046_intel_vbt.dts')
Bin Meng59ea8c22017-08-15 22:41:54 -07001218 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glass9fc60b42017-11-12 21:52:22 -07001219
Simon Glass56509842017-11-12 21:52:25 -07001220 def testSplBssPad(self):
1221 """Test that we can pad SPL's BSS with zeros"""
Simon Glass6b187df2017-11-12 21:52:27 -07001222 # ELF file with a '__bss_size' symbol
Simon Glass11ae93e2018-10-01 21:12:47 -06001223 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001224 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001225 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
1226 data)
Simon Glass56509842017-11-12 21:52:25 -07001227
Simon Glass86af5112018-10-01 21:12:42 -06001228 def testSplBssPadMissing(self):
1229 """Test that a missing symbol is detected"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001230 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glassb50e5612017-11-13 18:54:54 -07001231 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001232 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassb50e5612017-11-13 18:54:54 -07001233 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1234 str(e.exception))
1235
Simon Glass87722132017-11-12 21:52:26 -07001236 def testPackStart16Spl(self):
Simon Glass35b384c2018-09-14 04:57:10 -06001237 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001238 data = self._DoReadFile('048_x86_start16_spl.dts')
Simon Glass87722132017-11-12 21:52:26 -07001239 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1240
Simon Glass736bb0a2018-07-06 10:27:17 -06001241 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1242 """Helper function for microcode tests
Simon Glass6b187df2017-11-12 21:52:27 -07001243
1244 We expect to see the following in the image, in order:
1245 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1246 correct place
1247 u-boot.dtb with the microcode removed
1248 the microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001249
1250 Args:
1251 dts: Device tree file to use for test
1252 ucode_second: True if the microsecond entry is second instead of
1253 third
Simon Glass6b187df2017-11-12 21:52:27 -07001254 """
Simon Glass11ae93e2018-10-01 21:12:47 -06001255 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass736bb0a2018-07-06 10:27:17 -06001256 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1257 ucode_second=ucode_second)
Simon Glassc6c10e72019-05-17 22:00:46 -06001258 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1259 b'ter somewhere in here', first)
Simon Glass6b187df2017-11-12 21:52:27 -07001260
Simon Glass736bb0a2018-07-06 10:27:17 -06001261 def testPackUbootSplMicrocode(self):
1262 """Test that x86 microcode can be handled correctly in SPL"""
Simon Glass741f2d62018-10-01 12:22:30 -06001263 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass736bb0a2018-07-06 10:27:17 -06001264
1265 def testPackUbootSplMicrocodeReorder(self):
1266 """Test that order doesn't matter for microcode entries
1267
1268 This is the same as testPackUbootSplMicrocode but when we process the
1269 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1270 entry, so we reply on binman to try later.
1271 """
Simon Glass741f2d62018-10-01 12:22:30 -06001272 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass736bb0a2018-07-06 10:27:17 -06001273 ucode_second=True)
1274
Simon Glassca4f4ff2017-11-12 21:52:28 -07001275 def testPackMrc(self):
1276 """Test that an image with an MRC binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001277 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassca4f4ff2017-11-12 21:52:28 -07001278 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1279
Simon Glass47419ea2017-11-13 18:54:55 -07001280 def testSplDtb(self):
1281 """Test that an image with spl/u-boot-spl.dtb can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001282 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass47419ea2017-11-13 18:54:55 -07001283 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1284
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001285 def testSplNoDtb(self):
1286 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001287 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001288 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1289
Simon Glass19790632017-11-13 18:55:01 -07001290 def testSymbols(self):
1291 """Test binman can assign symbols embedded in U-Boot"""
Simon Glass1542c8b2019-08-24 07:22:56 -06001292 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass19790632017-11-13 18:55:01 -07001293 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1294 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Simon Glass3ab95982018-08-01 15:22:37 -06001295 self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr)
Simon Glass19790632017-11-13 18:55:01 -07001296
Simon Glass11ae93e2018-10-01 21:12:47 -06001297 self._SetupSplElf('u_boot_binman_syms')
Simon Glass741f2d62018-10-01 12:22:30 -06001298 data = self._DoReadFile('053_symbols.dts')
Simon Glass7c150132019-11-06 17:22:44 -07001299 sym_values = struct.pack('<LQLL', 0x00, 0x1c, 0x28, 0x04)
Simon Glassb87064c2019-08-24 07:23:05 -06001300 expected = (sym_values + U_BOOT_SPL_DATA[20:] +
Simon Glasse6d85ff2019-05-14 15:53:47 -06001301 tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
Simon Glassb87064c2019-08-24 07:23:05 -06001302 U_BOOT_SPL_DATA[20:])
Simon Glass19790632017-11-13 18:55:01 -07001303 self.assertEqual(expected, data)
1304
Simon Glassdd57c132018-06-01 09:38:11 -06001305 def testPackUnitAddress(self):
1306 """Test that we support multiple binaries with the same name"""
Simon Glass741f2d62018-10-01 12:22:30 -06001307 data = self._DoReadFile('054_unit_address.dts')
Simon Glassdd57c132018-06-01 09:38:11 -06001308 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1309
Simon Glass18546952018-06-01 09:38:16 -06001310 def testSections(self):
1311 """Basic test of sections"""
Simon Glass741f2d62018-10-01 12:22:30 -06001312 data = self._DoReadFile('055_sections.dts')
Simon Glassc6c10e72019-05-17 22:00:46 -06001313 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1314 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
1315 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
Simon Glass18546952018-06-01 09:38:16 -06001316 self.assertEqual(expected, data)
Simon Glass9fc60b42017-11-12 21:52:22 -07001317
Simon Glass3b0c3822018-06-01 09:38:20 -06001318 def testMap(self):
1319 """Tests outputting a map of the images"""
Simon Glass741f2d62018-10-01 12:22:30 -06001320 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001321 self.assertEqual('''ImagePos Offset Size Name
132200000000 00000000 00000028 main-section
132300000000 00000000 00000010 section@0
132400000000 00000000 00000004 u-boot
132500000010 00000010 00000010 section@1
132600000010 00000000 00000004 u-boot
132700000020 00000020 00000004 section@2
132800000020 00000000 00000004 u-boot
Simon Glass3b0c3822018-06-01 09:38:20 -06001329''', map_data)
1330
Simon Glassc8d48ef2018-06-01 09:38:21 -06001331 def testNamePrefix(self):
1332 """Tests that name prefixes are used"""
Simon Glass741f2d62018-10-01 12:22:30 -06001333 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001334 self.assertEqual('''ImagePos Offset Size Name
133500000000 00000000 00000028 main-section
133600000000 00000000 00000010 section@0
133700000000 00000000 00000004 ro-u-boot
133800000010 00000010 00000010 section@1
133900000010 00000000 00000004 rw-u-boot
Simon Glassc8d48ef2018-06-01 09:38:21 -06001340''', map_data)
1341
Simon Glass736bb0a2018-07-06 10:27:17 -06001342 def testUnknownContents(self):
1343 """Test that obtaining the contents works as expected"""
1344 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001345 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass8beb11e2019-07-08 14:25:47 -06001346 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glass16287932020-04-17 18:09:03 -06001347 "processing of contents: remaining ["
1348 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass736bb0a2018-07-06 10:27:17 -06001349
Simon Glass5c890232018-07-06 10:27:19 -06001350 def testBadChangeSize(self):
1351 """Test that trying to change the size of an entry fails"""
Simon Glassc52c9e72019-07-08 14:25:37 -06001352 try:
1353 state.SetAllowEntryExpansion(False)
1354 with self.assertRaises(ValueError) as e:
1355 self._DoReadFile('059_change_size.dts', True)
Simon Glass79d3c582019-07-20 12:23:57 -06001356 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glassc52c9e72019-07-08 14:25:37 -06001357 str(e.exception))
1358 finally:
1359 state.SetAllowEntryExpansion(True)
Simon Glass5c890232018-07-06 10:27:19 -06001360
Simon Glass16b8d6b2018-07-06 10:27:42 -06001361 def testUpdateFdt(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001362 """Test that we can update the device tree with offset/size info"""
Simon Glass741f2d62018-10-01 12:22:30 -06001363 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glass16b8d6b2018-07-06 10:27:42 -06001364 update_dtb=True)
Simon Glasscee02e62018-07-17 13:25:52 -06001365 dtb = fdt.Fdt(out_dtb_fname)
1366 dtb.Scan()
Simon Glass12bb1a92019-07-20 12:23:51 -06001367 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001368 self.assertEqual({
Simon Glassdbf6be92018-08-01 15:22:42 -06001369 'image-pos': 0,
Simon Glass8122f392018-07-17 13:25:28 -06001370 'offset': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001371 '_testing:offset': 32,
Simon Glass79d3c582019-07-20 12:23:57 -06001372 '_testing:size': 2,
Simon Glassdbf6be92018-08-01 15:22:42 -06001373 '_testing:image-pos': 32,
Simon Glass3ab95982018-08-01 15:22:37 -06001374 'section@0/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001375 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001376 'section@0/u-boot:image-pos': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001377 'section@0:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001378 'section@0:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001379 'section@0:image-pos': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001380
Simon Glass3ab95982018-08-01 15:22:37 -06001381 'section@1/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001382 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001383 'section@1/u-boot:image-pos': 16,
Simon Glass3ab95982018-08-01 15:22:37 -06001384 'section@1:offset': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001385 'section@1:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001386 'section@1:image-pos': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001387 'size': 40
1388 }, props)
1389
1390 def testUpdateFdtBad(self):
1391 """Test that we detect when ProcessFdt never completes"""
1392 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001393 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001394 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glass16287932020-04-17 18:09:03 -06001395 '[<binman.etype._testing.Entry__testing',
1396 str(e.exception))
Simon Glass5c890232018-07-06 10:27:19 -06001397
Simon Glass53af22a2018-07-17 13:25:32 -06001398 def testEntryArgs(self):
1399 """Test passing arguments to entries from the command line"""
1400 entry_args = {
1401 'test-str-arg': 'test1',
1402 'test-int-arg': '456',
1403 }
Simon Glass741f2d62018-10-01 12:22:30 -06001404 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001405 self.assertIn('image', control.images)
1406 entry = control.images['image'].GetEntries()['_testing']
1407 self.assertEqual('test0', entry.test_str_fdt)
1408 self.assertEqual('test1', entry.test_str_arg)
1409 self.assertEqual(123, entry.test_int_fdt)
1410 self.assertEqual(456, entry.test_int_arg)
1411
1412 def testEntryArgsMissing(self):
1413 """Test missing arguments and properties"""
1414 entry_args = {
1415 'test-int-arg': '456',
1416 }
Simon Glass741f2d62018-10-01 12:22:30 -06001417 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001418 entry = control.images['image'].GetEntries()['_testing']
1419 self.assertEqual('test0', entry.test_str_fdt)
1420 self.assertEqual(None, entry.test_str_arg)
1421 self.assertEqual(None, entry.test_int_fdt)
1422 self.assertEqual(456, entry.test_int_arg)
1423
1424 def testEntryArgsRequired(self):
1425 """Test missing arguments and properties"""
1426 entry_args = {
1427 'test-int-arg': '456',
1428 }
1429 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001430 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass3decfa32020-09-01 05:13:54 -06001431 self.assertIn("Node '/binman/_testing': "
1432 'Missing required properties/entry args: test-str-arg, '
1433 'test-int-fdt, test-int-arg',
Simon Glass53af22a2018-07-17 13:25:32 -06001434 str(e.exception))
1435
1436 def testEntryArgsInvalidFormat(self):
1437 """Test that an invalid entry-argument format is detected"""
Simon Glass53cd5d92019-07-08 14:25:29 -06001438 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1439 '-ano-value']
Simon Glass53af22a2018-07-17 13:25:32 -06001440 with self.assertRaises(ValueError) as e:
1441 self._DoBinman(*args)
1442 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1443
1444 def testEntryArgsInvalidInteger(self):
1445 """Test that an invalid entry-argument integer is detected"""
1446 entry_args = {
1447 'test-int-arg': 'abc',
1448 }
1449 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001450 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001451 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1452 "'test-int-arg' (value 'abc') to integer",
1453 str(e.exception))
1454
1455 def testEntryArgsInvalidDatatype(self):
1456 """Test that an invalid entry-argument datatype is detected
1457
1458 This test could be written in entry_test.py except that it needs
1459 access to control.entry_args, which seems more than that module should
1460 be able to see.
1461 """
1462 entry_args = {
1463 'test-bad-datatype-arg': '12',
1464 }
1465 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001466 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass53af22a2018-07-17 13:25:32 -06001467 entry_args=entry_args)
1468 self.assertIn('GetArg() internal error: Unknown data type ',
1469 str(e.exception))
1470
Simon Glassbb748372018-07-17 13:25:33 -06001471 def testText(self):
1472 """Test for a text entry type"""
1473 entry_args = {
1474 'test-id': TEXT_DATA,
1475 'test-id2': TEXT_DATA2,
1476 'test-id3': TEXT_DATA3,
1477 }
Simon Glass741f2d62018-10-01 12:22:30 -06001478 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glassbb748372018-07-17 13:25:33 -06001479 entry_args=entry_args)
Simon Glassc6c10e72019-05-17 22:00:46 -06001480 expected = (tools.ToBytes(TEXT_DATA) +
1481 tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1482 tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
Simon Glassaa88b502019-07-08 13:18:40 -06001483 b'some text' + b'more text')
Simon Glassbb748372018-07-17 13:25:33 -06001484 self.assertEqual(expected, data)
1485
Simon Glassfd8d1f72018-07-17 13:25:36 -06001486 def testEntryDocs(self):
1487 """Test for creation of entry documentation"""
1488 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass87d43322020-08-05 13:27:46 -06001489 control.WriteEntryDocs(control.GetEntryModules())
Simon Glassfd8d1f72018-07-17 13:25:36 -06001490 self.assertTrue(len(stdout.getvalue()) > 0)
1491
1492 def testEntryDocsMissing(self):
1493 """Test handling of missing entry documentation"""
1494 with self.assertRaises(ValueError) as e:
1495 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass87d43322020-08-05 13:27:46 -06001496 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glassfd8d1f72018-07-17 13:25:36 -06001497 self.assertIn('Documentation is missing for modules: u_boot',
1498 str(e.exception))
1499
Simon Glass11e36cc2018-07-17 13:25:38 -06001500 def testFmap(self):
1501 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001502 data = self._DoReadFile('067_fmap.dts')
Simon Glass11e36cc2018-07-17 13:25:38 -06001503 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc6c10e72019-05-17 22:00:46 -06001504 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1505 U_BOOT_DATA + tools.GetBytes(ord('a'), 12))
Simon Glass11e36cc2018-07-17 13:25:38 -06001506 self.assertEqual(expected, data[:32])
Simon Glassc6c10e72019-05-17 22:00:46 -06001507 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass11e36cc2018-07-17 13:25:38 -06001508 self.assertEqual(1, fhdr.ver_major)
1509 self.assertEqual(0, fhdr.ver_minor)
1510 self.assertEqual(0, fhdr.base)
1511 self.assertEqual(16 + 16 +
1512 fmap_util.FMAP_HEADER_LEN +
1513 fmap_util.FMAP_AREA_LEN * 3, fhdr.image_size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001514 self.assertEqual(b'FMAP', fhdr.name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001515 self.assertEqual(3, fhdr.nareas)
1516 for fentry in fentries:
1517 self.assertEqual(0, fentry.flags)
1518
1519 self.assertEqual(0, fentries[0].offset)
1520 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001521 self.assertEqual(b'RO_U_BOOT', fentries[0].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001522
1523 self.assertEqual(16, fentries[1].offset)
1524 self.assertEqual(4, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001525 self.assertEqual(b'RW_U_BOOT', fentries[1].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001526
1527 self.assertEqual(32, fentries[2].offset)
1528 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1529 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001530 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001531
Simon Glassec127af2018-07-17 13:25:39 -06001532 def testBlobNamedByArg(self):
1533 """Test we can add a blob with the filename coming from an entry arg"""
1534 entry_args = {
1535 'cros-ec-rw-path': 'ecrw.bin',
1536 }
Simon Glass3decfa32020-09-01 05:13:54 -06001537 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassec127af2018-07-17 13:25:39 -06001538
Simon Glass3af8e492018-07-17 13:25:40 -06001539 def testFill(self):
1540 """Test for an fill entry type"""
Simon Glass741f2d62018-10-01 12:22:30 -06001541 data = self._DoReadFile('069_fill.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001542 expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
Simon Glass3af8e492018-07-17 13:25:40 -06001543 self.assertEqual(expected, data)
1544
1545 def testFillNoSize(self):
1546 """Test for an fill entry type with no size"""
1547 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001548 self._DoReadFile('070_fill_no_size.dts')
Simon Glass3af8e492018-07-17 13:25:40 -06001549 self.assertIn("'fill' entry must have a size property",
1550 str(e.exception))
1551
Simon Glass0ef87aa2018-07-17 13:25:44 -06001552 def _HandleGbbCommand(self, pipe_list):
1553 """Fake calls to the futility utility"""
1554 if pipe_list[0][0] == 'futility':
1555 fname = pipe_list[0][-1]
1556 # Append our GBB data to the file, which will happen every time the
1557 # futility command is called.
Simon Glass1d0ebf72019-05-14 15:53:42 -06001558 with open(fname, 'ab') as fd:
Simon Glass0ef87aa2018-07-17 13:25:44 -06001559 fd.write(GBB_DATA)
1560 return command.CommandResult()
1561
1562 def testGbb(self):
1563 """Test for the Chromium OS Google Binary Block"""
1564 command.test_result = self._HandleGbbCommand
1565 entry_args = {
1566 'keydir': 'devkeys',
1567 'bmpblk': 'bmpblk.bin',
1568 }
Simon Glass741f2d62018-10-01 12:22:30 -06001569 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glass0ef87aa2018-07-17 13:25:44 -06001570
1571 # Since futility
Simon Glasse6d85ff2019-05-14 15:53:47 -06001572 expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1573 tools.GetBytes(0, 0x2180 - 16))
Simon Glass0ef87aa2018-07-17 13:25:44 -06001574 self.assertEqual(expected, data)
1575
1576 def testGbbTooSmall(self):
1577 """Test for the Chromium OS Google Binary Block being large enough"""
1578 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001579 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001580 self.assertIn("Node '/binman/gbb': GBB is too small",
1581 str(e.exception))
1582
1583 def testGbbNoSize(self):
1584 """Test for the Chromium OS Google Binary Block having a size"""
1585 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001586 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001587 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1588 str(e.exception))
1589
Simon Glass24d0d3c2018-07-17 13:25:47 -06001590 def _HandleVblockCommand(self, pipe_list):
1591 """Fake calls to the futility utility"""
1592 if pipe_list[0][0] == 'futility':
1593 fname = pipe_list[0][3]
Simon Glassa326b492018-09-14 04:57:11 -06001594 with open(fname, 'wb') as fd:
Simon Glass24d0d3c2018-07-17 13:25:47 -06001595 fd.write(VBLOCK_DATA)
1596 return command.CommandResult()
1597
1598 def testVblock(self):
1599 """Test for the Chromium OS Verified Boot Block"""
1600 command.test_result = self._HandleVblockCommand
1601 entry_args = {
1602 'keydir': 'devkeys',
1603 }
Simon Glass741f2d62018-10-01 12:22:30 -06001604 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass24d0d3c2018-07-17 13:25:47 -06001605 entry_args=entry_args)
1606 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1607 self.assertEqual(expected, data)
1608
1609 def testVblockNoContent(self):
1610 """Test we detect a vblock which has no content to sign"""
1611 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001612 self._DoReadFile('075_vblock_no_content.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001613 self.assertIn("Node '/binman/vblock': Vblock must have a 'content' "
1614 'property', str(e.exception))
1615
1616 def testVblockBadPhandle(self):
1617 """Test that we detect a vblock with an invalid phandle in contents"""
1618 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001619 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001620 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1621 '1000', str(e.exception))
1622
1623 def testVblockBadEntry(self):
1624 """Test that we detect an entry that points to a non-entry"""
1625 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001626 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001627 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1628 "'other'", str(e.exception))
1629
Simon Glassb8ef5b62018-07-17 13:25:48 -06001630 def testTpl(self):
Simon Glass2090f1e2019-08-24 07:23:00 -06001631 """Test that an image with TPL and its device tree can be created"""
Simon Glassb8ef5b62018-07-17 13:25:48 -06001632 # ELF file with a '__bss_size' symbol
Simon Glass2090f1e2019-08-24 07:23:00 -06001633 self._SetupTplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001634 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glassb8ef5b62018-07-17 13:25:48 -06001635 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1636
Simon Glass15a587c2018-07-17 13:25:51 -06001637 def testUsesPos(self):
1638 """Test that the 'pos' property cannot be used anymore"""
1639 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001640 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass15a587c2018-07-17 13:25:51 -06001641 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1642 "'pos'", str(e.exception))
1643
Simon Glassd178eab2018-09-14 04:57:08 -06001644 def testFillZero(self):
1645 """Test for an fill entry type with a size of 0"""
Simon Glass741f2d62018-10-01 12:22:30 -06001646 data = self._DoReadFile('080_fill_empty.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001647 self.assertEqual(tools.GetBytes(0, 16), data)
Simon Glassd178eab2018-09-14 04:57:08 -06001648
Simon Glass0b489362018-09-14 04:57:09 -06001649 def testTextMissing(self):
1650 """Test for a text entry type where there is no text"""
1651 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001652 self._DoReadFileDtb('066_text.dts',)
Simon Glass0b489362018-09-14 04:57:09 -06001653 self.assertIn("Node '/binman/text': No value provided for text label "
1654 "'test-id'", str(e.exception))
1655
Simon Glass35b384c2018-09-14 04:57:10 -06001656 def testPackStart16Tpl(self):
1657 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001658 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glass35b384c2018-09-14 04:57:10 -06001659 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1660
Simon Glass0bfa7b02018-09-14 04:57:12 -06001661 def testSelectImage(self):
1662 """Test that we can select which images to build"""
Simon Glasseb833d82019-04-25 21:58:34 -06001663 expected = 'Skipping images: image1'
Simon Glass0bfa7b02018-09-14 04:57:12 -06001664
Simon Glasseb833d82019-04-25 21:58:34 -06001665 # We should only get the expected message in verbose mode
Simon Glassee0c9a72019-07-08 13:18:48 -06001666 for verbosity in (0, 2):
Simon Glasseb833d82019-04-25 21:58:34 -06001667 with test_util.capture_sys_output() as (stdout, stderr):
1668 retcode = self._DoTestFile('006_dual_image.dts',
1669 verbosity=verbosity,
1670 images=['image2'])
1671 self.assertEqual(0, retcode)
1672 if verbosity:
1673 self.assertIn(expected, stdout.getvalue())
1674 else:
1675 self.assertNotIn(expected, stdout.getvalue())
1676
1677 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1678 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
Simon Glassf86a7362019-07-20 12:24:10 -06001679 self._CleanupOutputDir()
Simon Glass0bfa7b02018-09-14 04:57:12 -06001680
Simon Glass6ed45ba2018-09-14 04:57:24 -06001681 def testUpdateFdtAll(self):
1682 """Test that all device trees are updated with offset/size info"""
Simon Glass3c081312019-07-08 14:25:26 -06001683 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glass6ed45ba2018-09-14 04:57:24 -06001684
1685 base_expected = {
1686 'section:image-pos': 0,
1687 'u-boot-tpl-dtb:size': 513,
1688 'u-boot-spl-dtb:size': 513,
1689 'u-boot-spl-dtb:offset': 493,
1690 'image-pos': 0,
1691 'section/u-boot-dtb:image-pos': 0,
1692 'u-boot-spl-dtb:image-pos': 493,
1693 'section/u-boot-dtb:size': 493,
1694 'u-boot-tpl-dtb:image-pos': 1006,
1695 'section/u-boot-dtb:offset': 0,
1696 'section:size': 493,
1697 'offset': 0,
1698 'section:offset': 0,
1699 'u-boot-tpl-dtb:offset': 1006,
1700 'size': 1519
1701 }
1702
1703 # We expect three device-tree files in the output, one after the other.
1704 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1705 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1706 # main U-Boot tree. All three should have the same postions and offset.
1707 start = 0
1708 for item in ['', 'spl', 'tpl']:
1709 dtb = fdt.Fdt.FromData(data[start:])
1710 dtb.Scan()
Simon Glass12bb1a92019-07-20 12:23:51 -06001711 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
1712 ['spl', 'tpl'])
Simon Glass6ed45ba2018-09-14 04:57:24 -06001713 expected = dict(base_expected)
1714 if item:
1715 expected[item] = 0
1716 self.assertEqual(expected, props)
1717 start += dtb._fdt_obj.totalsize()
1718
1719 def testUpdateFdtOutput(self):
1720 """Test that output DTB files are updated"""
1721 try:
Simon Glass741f2d62018-10-01 12:22:30 -06001722 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glass6ed45ba2018-09-14 04:57:24 -06001723 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1724
1725 # Unfortunately, compiling a source file always results in a file
1726 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass741f2d62018-10-01 12:22:30 -06001727 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glass6ed45ba2018-09-14 04:57:24 -06001728 # binman as a file called u-boot.dtb. To fix this, copy the file
1729 # over to the expected place.
Simon Glass6ed45ba2018-09-14 04:57:24 -06001730 start = 0
1731 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1732 'tpl/u-boot-tpl.dtb.out']:
1733 dtb = fdt.Fdt.FromData(data[start:])
1734 size = dtb._fdt_obj.totalsize()
1735 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1736 outdata = tools.ReadFile(pathname)
1737 name = os.path.split(fname)[0]
1738
1739 if name:
1740 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1741 else:
1742 orig_indata = dtb_data
1743 self.assertNotEqual(outdata, orig_indata,
1744 "Expected output file '%s' be updated" % pathname)
1745 self.assertEqual(outdata, data[start:start + size],
1746 "Expected output file '%s' to match output image" %
1747 pathname)
1748 start += size
1749 finally:
1750 self._ResetDtbs()
1751
Simon Glass83d73c22018-09-14 04:57:26 -06001752 def _decompress(self, data):
Simon Glassff5c7e32019-07-08 13:18:42 -06001753 return tools.Decompress(data, 'lz4')
Simon Glass83d73c22018-09-14 04:57:26 -06001754
1755 def testCompress(self):
1756 """Test compression of blobs"""
Simon Glassac62fba2019-07-08 13:18:53 -06001757 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06001758 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass83d73c22018-09-14 04:57:26 -06001759 use_real_dtb=True, update_dtb=True)
1760 dtb = fdt.Fdt(out_dtb_fname)
1761 dtb.Scan()
1762 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1763 orig = self._decompress(data)
1764 self.assertEquals(COMPRESS_DATA, orig)
1765 expected = {
1766 'blob:uncomp-size': len(COMPRESS_DATA),
1767 'blob:size': len(data),
1768 'size': len(data),
1769 }
1770 self.assertEqual(expected, props)
1771
Simon Glass0a98b282018-09-14 04:57:28 -06001772 def testFiles(self):
1773 """Test bringing in multiple files"""
Simon Glass741f2d62018-10-01 12:22:30 -06001774 data = self._DoReadFile('084_files.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001775 self.assertEqual(FILES_DATA, data)
1776
1777 def testFilesCompress(self):
1778 """Test bringing in multiple files and compressing them"""
Simon Glassac62fba2019-07-08 13:18:53 -06001779 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06001780 data = self._DoReadFile('085_files_compress.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001781
1782 image = control.images['image']
1783 entries = image.GetEntries()
1784 files = entries['files']
Simon Glass8beb11e2019-07-08 14:25:47 -06001785 entries = files._entries
Simon Glass0a98b282018-09-14 04:57:28 -06001786
Simon Glassc6c10e72019-05-17 22:00:46 -06001787 orig = b''
Simon Glass0a98b282018-09-14 04:57:28 -06001788 for i in range(1, 3):
1789 key = '%d.dat' % i
1790 start = entries[key].image_pos
1791 len = entries[key].size
1792 chunk = data[start:start + len]
1793 orig += self._decompress(chunk)
1794
1795 self.assertEqual(FILES_DATA, orig)
1796
1797 def testFilesMissing(self):
1798 """Test missing files"""
1799 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001800 data = self._DoReadFile('086_files_none.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001801 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1802 'no files', str(e.exception))
1803
1804 def testFilesNoPattern(self):
1805 """Test missing files"""
1806 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001807 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001808 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1809 str(e.exception))
1810
Simon Glassba64a0b2018-09-14 04:57:29 -06001811 def testExpandSize(self):
1812 """Test an expanding entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001813 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
Simon Glassba64a0b2018-09-14 04:57:29 -06001814 map=True)
Simon Glassc6c10e72019-05-17 22:00:46 -06001815 expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA +
1816 MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA +
1817 tools.GetBytes(ord('c'), 8) + U_BOOT_DATA +
1818 tools.GetBytes(ord('d'), 8))
Simon Glassba64a0b2018-09-14 04:57:29 -06001819 self.assertEqual(expect, data)
1820 self.assertEqual('''ImagePos Offset Size Name
182100000000 00000000 00000028 main-section
182200000000 00000000 00000008 fill
182300000008 00000008 00000004 u-boot
18240000000c 0000000c 00000004 section
18250000000c 00000000 00000003 intel-mrc
182600000010 00000010 00000004 u-boot2
182700000014 00000014 0000000c section2
182800000014 00000000 00000008 fill
18290000001c 00000008 00000004 u-boot
183000000020 00000020 00000008 fill2
1831''', map_data)
1832
1833 def testExpandSizeBad(self):
1834 """Test an expanding entry which fails to provide contents"""
Simon Glass163ed6c2018-09-14 04:57:36 -06001835 with test_util.capture_sys_output() as (stdout, stderr):
1836 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001837 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
Simon Glassba64a0b2018-09-14 04:57:29 -06001838 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
1839 'expanding entry', str(e.exception))
1840
Simon Glasse0e5df92018-09-14 04:57:31 -06001841 def testHash(self):
1842 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001843 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06001844 use_real_dtb=True, update_dtb=True)
1845 dtb = fdt.Fdt(out_dtb_fname)
1846 dtb.Scan()
1847 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
1848 m = hashlib.sha256()
1849 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001850 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06001851
1852 def testHashNoAlgo(self):
1853 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001854 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06001855 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
1856 'hash node', str(e.exception))
1857
1858 def testHashBadAlgo(self):
1859 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001860 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06001861 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
1862 str(e.exception))
1863
1864 def testHashSection(self):
1865 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001866 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06001867 use_real_dtb=True, update_dtb=True)
1868 dtb = fdt.Fdt(out_dtb_fname)
1869 dtb.Scan()
1870 hash_node = dtb.GetNode('/binman/section/hash').props['value']
1871 m = hashlib.sha256()
1872 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001873 m.update(tools.GetBytes(ord('a'), 16))
1874 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06001875
Simon Glassf0253632018-09-14 04:57:32 -06001876 def testPackUBootTplMicrocode(self):
1877 """Test that x86 microcode can be handled correctly in TPL
1878
1879 We expect to see the following in the image, in order:
1880 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
1881 place
1882 u-boot-tpl.dtb with the microcode removed
1883 the microcode
1884 """
Simon Glass2090f1e2019-08-24 07:23:00 -06001885 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass741f2d62018-10-01 12:22:30 -06001886 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glassf0253632018-09-14 04:57:32 -06001887 U_BOOT_TPL_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001888 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
1889 b'ter somewhere in here', first)
Simon Glassf0253632018-09-14 04:57:32 -06001890
Simon Glassf8f8df62018-09-14 04:57:34 -06001891 def testFmapX86(self):
1892 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001893 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassf8f8df62018-09-14 04:57:34 -06001894 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc6c10e72019-05-17 22:00:46 -06001895 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06001896 self.assertEqual(expected, data[:32])
1897 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1898
1899 self.assertEqual(0x100, fhdr.image_size)
1900
1901 self.assertEqual(0, fentries[0].offset)
1902 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001903 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001904
1905 self.assertEqual(4, fentries[1].offset)
1906 self.assertEqual(3, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001907 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001908
1909 self.assertEqual(32, fentries[2].offset)
1910 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1911 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001912 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001913
1914 def testFmapX86Section(self):
1915 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001916 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glassc6c10e72019-05-17 22:00:46 -06001917 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06001918 self.assertEqual(expected, data[:32])
1919 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
1920
1921 self.assertEqual(0x100, fhdr.image_size)
1922
1923 self.assertEqual(0, fentries[0].offset)
1924 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001925 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001926
1927 self.assertEqual(4, fentries[1].offset)
1928 self.assertEqual(3, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001929 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001930
1931 self.assertEqual(36, fentries[2].offset)
1932 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1933 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001934 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001935
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001936 def testElf(self):
1937 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001938 self._SetupSplElf()
Simon Glass2090f1e2019-08-24 07:23:00 -06001939 self._SetupTplElf()
Simon Glass53e22bf2019-08-24 07:22:53 -06001940 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001941 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001942 data = self._DoReadFile('096_elf.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001943
Simon Glass093d1682019-07-08 13:18:25 -06001944 def testElfStrip(self):
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001945 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001946 self._SetupSplElf()
Simon Glass53e22bf2019-08-24 07:22:53 -06001947 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001948 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001949 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001950
Simon Glass163ed6c2018-09-14 04:57:36 -06001951 def testPackOverlapMap(self):
1952 """Test that overlapping regions are detected"""
1953 with test_util.capture_sys_output() as (stdout, stderr):
1954 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001955 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glass163ed6c2018-09-14 04:57:36 -06001956 map_fname = tools.GetOutputFilename('image.map')
1957 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
1958 stdout.getvalue())
1959
1960 # We should not get an inmage, but there should be a map file
1961 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
1962 self.assertTrue(os.path.exists(map_fname))
Simon Glasseb546ac2019-05-17 22:00:51 -06001963 map_data = tools.ReadFile(map_fname, binary=False)
Simon Glass163ed6c2018-09-14 04:57:36 -06001964 self.assertEqual('''ImagePos Offset Size Name
1965<none> 00000000 00000007 main-section
1966<none> 00000000 00000004 u-boot
1967<none> 00000003 00000004 u-boot-align
1968''', map_data)
1969
Simon Glass093d1682019-07-08 13:18:25 -06001970 def testPackRefCode(self):
Simon Glass3ae192c2018-10-01 12:22:31 -06001971 """Test that an image with an Intel Reference code binary works"""
1972 data = self._DoReadFile('100_intel_refcode.dts')
1973 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
1974
Simon Glass9481c802019-04-25 21:58:39 -06001975 def testSectionOffset(self):
1976 """Tests use of a section with an offset"""
1977 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
1978 map=True)
1979 self.assertEqual('''ImagePos Offset Size Name
198000000000 00000000 00000038 main-section
198100000004 00000004 00000010 section@0
198200000004 00000000 00000004 u-boot
198300000018 00000018 00000010 section@1
198400000018 00000000 00000004 u-boot
19850000002c 0000002c 00000004 section@2
19860000002c 00000000 00000004 u-boot
1987''', map_data)
1988 self.assertEqual(data,
Simon Glasse6d85ff2019-05-14 15:53:47 -06001989 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1990 tools.GetBytes(0x21, 12) +
1991 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1992 tools.GetBytes(0x61, 12) +
1993 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1994 tools.GetBytes(0x26, 8))
Simon Glass9481c802019-04-25 21:58:39 -06001995
Simon Glassac62fba2019-07-08 13:18:53 -06001996 def testCbfsRaw(self):
1997 """Test base handling of a Coreboot Filesystem (CBFS)
1998
1999 The exact contents of the CBFS is verified by similar tests in
2000 cbfs_util_test.py. The tests here merely check that the files added to
2001 the CBFS can be found in the final image.
2002 """
2003 data = self._DoReadFile('102_cbfs_raw.dts')
2004 size = 0xb0
2005
2006 cbfs = cbfs_util.CbfsReader(data)
2007 self.assertEqual(size, cbfs.rom_size)
2008
2009 self.assertIn('u-boot-dtb', cbfs.files)
2010 cfile = cbfs.files['u-boot-dtb']
2011 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2012
2013 def testCbfsArch(self):
2014 """Test on non-x86 architecture"""
2015 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2016 size = 0x100
2017
2018 cbfs = cbfs_util.CbfsReader(data)
2019 self.assertEqual(size, cbfs.rom_size)
2020
2021 self.assertIn('u-boot-dtb', cbfs.files)
2022 cfile = cbfs.files['u-boot-dtb']
2023 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2024
2025 def testCbfsStage(self):
2026 """Tests handling of a Coreboot Filesystem (CBFS)"""
2027 if not elf.ELF_TOOLS:
2028 self.skipTest('Python elftools not available')
2029 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2030 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2031 size = 0xb0
2032
2033 data = self._DoReadFile('104_cbfs_stage.dts')
2034 cbfs = cbfs_util.CbfsReader(data)
2035 self.assertEqual(size, cbfs.rom_size)
2036
2037 self.assertIn('u-boot', cbfs.files)
2038 cfile = cbfs.files['u-boot']
2039 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2040
2041 def testCbfsRawCompress(self):
2042 """Test handling of compressing raw files"""
2043 self._CheckLz4()
2044 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2045 size = 0x140
2046
2047 cbfs = cbfs_util.CbfsReader(data)
2048 self.assertIn('u-boot', cbfs.files)
2049 cfile = cbfs.files['u-boot']
2050 self.assertEqual(COMPRESS_DATA, cfile.data)
2051
2052 def testCbfsBadArch(self):
2053 """Test handling of a bad architecture"""
2054 with self.assertRaises(ValueError) as e:
2055 self._DoReadFile('106_cbfs_bad_arch.dts')
2056 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2057
2058 def testCbfsNoSize(self):
2059 """Test handling of a missing size property"""
2060 with self.assertRaises(ValueError) as e:
2061 self._DoReadFile('107_cbfs_no_size.dts')
2062 self.assertIn('entry must have a size property', str(e.exception))
2063
2064 def testCbfsNoCOntents(self):
2065 """Test handling of a CBFS entry which does not provide contentsy"""
2066 with self.assertRaises(ValueError) as e:
2067 self._DoReadFile('108_cbfs_no_contents.dts')
2068 self.assertIn('Could not complete processing of contents',
2069 str(e.exception))
2070
2071 def testCbfsBadCompress(self):
2072 """Test handling of a bad architecture"""
2073 with self.assertRaises(ValueError) as e:
2074 self._DoReadFile('109_cbfs_bad_compress.dts')
2075 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2076 str(e.exception))
2077
2078 def testCbfsNamedEntries(self):
2079 """Test handling of named entries"""
2080 data = self._DoReadFile('110_cbfs_name.dts')
2081
2082 cbfs = cbfs_util.CbfsReader(data)
2083 self.assertIn('FRED', cbfs.files)
2084 cfile1 = cbfs.files['FRED']
2085 self.assertEqual(U_BOOT_DATA, cfile1.data)
2086
2087 self.assertIn('hello', cbfs.files)
2088 cfile2 = cbfs.files['hello']
2089 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2090
Simon Glassc5ac1382019-07-08 13:18:54 -06002091 def _SetupIfwi(self, fname):
2092 """Set up to run an IFWI test
2093
2094 Args:
2095 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2096 """
2097 self._SetupSplElf()
Simon Glass2090f1e2019-08-24 07:23:00 -06002098 self._SetupTplElf()
Simon Glassc5ac1382019-07-08 13:18:54 -06002099
2100 # Intel Integrated Firmware Image (IFWI) file
2101 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2102 data = fd.read()
2103 TestFunctional._MakeInputFile(fname,data)
2104
2105 def _CheckIfwi(self, data):
2106 """Check that an image with an IFWI contains the correct output
2107
2108 Args:
2109 data: Conents of output file
2110 """
2111 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
2112 if data[:0x1000] != expected_desc:
2113 self.fail('Expected descriptor binary at start of image')
2114
2115 # We expect to find the TPL wil in subpart IBBP entry IBBL
2116 image_fname = tools.GetOutputFilename('image.bin')
2117 tpl_fname = tools.GetOutputFilename('tpl.out')
2118 tools.RunIfwiTool(image_fname, tools.CMD_EXTRACT, fname=tpl_fname,
2119 subpart='IBBP', entry_name='IBBL')
2120
2121 tpl_data = tools.ReadFile(tpl_fname)
Simon Glasse95be632019-08-24 07:22:51 -06002122 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glassc5ac1382019-07-08 13:18:54 -06002123
2124 def testPackX86RomIfwi(self):
2125 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2126 self._SetupIfwi('fitimage.bin')
Simon Glass9255f3c2019-08-24 07:23:01 -06002127 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002128 self._CheckIfwi(data)
2129
2130 def testPackX86RomIfwiNoDesc(self):
2131 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2132 self._SetupIfwi('ifwi.bin')
Simon Glass9255f3c2019-08-24 07:23:01 -06002133 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002134 self._CheckIfwi(data)
2135
2136 def testPackX86RomIfwiNoData(self):
2137 """Test that an x86 ROM with IFWI handles missing data"""
2138 self._SetupIfwi('ifwi.bin')
2139 with self.assertRaises(ValueError) as e:
Simon Glass9255f3c2019-08-24 07:23:01 -06002140 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002141 self.assertIn('Could not complete processing of contents',
2142 str(e.exception))
Simon Glass53af22a2018-07-17 13:25:32 -06002143
Simon Glasse073d4e2019-07-08 13:18:56 -06002144 def testCbfsOffset(self):
2145 """Test a CBFS with files at particular offsets
2146
2147 Like all CFBS tests, this is just checking the logic that calls
2148 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2149 """
2150 data = self._DoReadFile('114_cbfs_offset.dts')
2151 size = 0x200
2152
2153 cbfs = cbfs_util.CbfsReader(data)
2154 self.assertEqual(size, cbfs.rom_size)
2155
2156 self.assertIn('u-boot', cbfs.files)
2157 cfile = cbfs.files['u-boot']
2158 self.assertEqual(U_BOOT_DATA, cfile.data)
2159 self.assertEqual(0x40, cfile.cbfs_offset)
2160
2161 self.assertIn('u-boot-dtb', cbfs.files)
2162 cfile2 = cbfs.files['u-boot-dtb']
2163 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2164 self.assertEqual(0x140, cfile2.cbfs_offset)
2165
Simon Glass086cec92019-07-08 14:25:27 -06002166 def testFdtmap(self):
2167 """Test an FDT map can be inserted in the image"""
2168 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2169 fdtmap_data = data[len(U_BOOT_DATA):]
2170 magic = fdtmap_data[:8]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002171 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass086cec92019-07-08 14:25:27 -06002172 self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
2173
2174 fdt_data = fdtmap_data[16:]
2175 dtb = fdt.Fdt.FromData(fdt_data)
2176 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002177 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass086cec92019-07-08 14:25:27 -06002178 self.assertEqual({
2179 'image-pos': 0,
2180 'offset': 0,
2181 'u-boot:offset': 0,
2182 'u-boot:size': len(U_BOOT_DATA),
2183 'u-boot:image-pos': 0,
2184 'fdtmap:image-pos': 4,
2185 'fdtmap:offset': 4,
2186 'fdtmap:size': len(fdtmap_data),
2187 'size': len(data),
2188 }, props)
2189
2190 def testFdtmapNoMatch(self):
2191 """Check handling of an FDT map when the section cannot be found"""
2192 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2193
2194 # Mangle the section name, which should cause a mismatch between the
2195 # correct FDT path and the one expected by the section
2196 image = control.images['image']
Simon Glasscf228942019-07-08 14:25:28 -06002197 image._node.path += '-suffix'
Simon Glass086cec92019-07-08 14:25:27 -06002198 entries = image.GetEntries()
2199 fdtmap = entries['fdtmap']
2200 with self.assertRaises(ValueError) as e:
2201 fdtmap._GetFdtmap()
2202 self.assertIn("Cannot locate node for path '/binman-suffix'",
2203 str(e.exception))
2204
Simon Glasscf228942019-07-08 14:25:28 -06002205 def testFdtmapHeader(self):
2206 """Test an FDT map and image header can be inserted in the image"""
2207 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2208 fdtmap_pos = len(U_BOOT_DATA)
2209 fdtmap_data = data[fdtmap_pos:]
2210 fdt_data = fdtmap_data[16:]
2211 dtb = fdt.Fdt.FromData(fdt_data)
2212 fdt_size = dtb.GetFdtObj().totalsize()
2213 hdr_data = data[-8:]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002214 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002215 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2216 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2217
2218 def testFdtmapHeaderStart(self):
2219 """Test an image header can be inserted at the image start"""
2220 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2221 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2222 hdr_data = data[:8]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002223 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002224 offset = struct.unpack('<I', hdr_data[4:])[0]
2225 self.assertEqual(fdtmap_pos, offset)
2226
2227 def testFdtmapHeaderPos(self):
2228 """Test an image header can be inserted at a chosen position"""
2229 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2230 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2231 hdr_data = data[0x80:0x88]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002232 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002233 offset = struct.unpack('<I', hdr_data[4:])[0]
2234 self.assertEqual(fdtmap_pos, offset)
2235
2236 def testHeaderMissingFdtmap(self):
2237 """Test an image header requires an fdtmap"""
2238 with self.assertRaises(ValueError) as e:
2239 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2240 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2241 str(e.exception))
2242
2243 def testHeaderNoLocation(self):
2244 """Test an image header with a no specified location is detected"""
2245 with self.assertRaises(ValueError) as e:
2246 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2247 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2248 str(e.exception))
2249
Simon Glassc52c9e72019-07-08 14:25:37 -06002250 def testEntryExpand(self):
2251 """Test expanding an entry after it is packed"""
2252 data = self._DoReadFile('121_entry_expand.dts')
Simon Glass79d3c582019-07-20 12:23:57 -06002253 self.assertEqual(b'aaa', data[:3])
2254 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2255 self.assertEqual(b'aaa', data[-3:])
Simon Glassc52c9e72019-07-08 14:25:37 -06002256
2257 def testEntryExpandBad(self):
2258 """Test expanding an entry after it is packed, twice"""
2259 with self.assertRaises(ValueError) as e:
2260 self._DoReadFile('122_entry_expand_twice.dts')
Simon Glass61ec04f2019-07-20 12:23:58 -06002261 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glassc52c9e72019-07-08 14:25:37 -06002262 str(e.exception))
2263
2264 def testEntryExpandSection(self):
2265 """Test expanding an entry within a section after it is packed"""
2266 data = self._DoReadFile('123_entry_expand_section.dts')
Simon Glass79d3c582019-07-20 12:23:57 -06002267 self.assertEqual(b'aaa', data[:3])
2268 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2269 self.assertEqual(b'aaa', data[-3:])
Simon Glassc52c9e72019-07-08 14:25:37 -06002270
Simon Glass6c223fd2019-07-08 14:25:38 -06002271 def testCompressDtb(self):
2272 """Test that compress of device-tree files is supported"""
2273 self._CheckLz4()
2274 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2275 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2276 comp_data = data[len(U_BOOT_DATA):]
2277 orig = self._decompress(comp_data)
2278 dtb = fdt.Fdt.FromData(orig)
2279 dtb.Scan()
2280 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2281 expected = {
2282 'u-boot:size': len(U_BOOT_DATA),
2283 'u-boot-dtb:uncomp-size': len(orig),
2284 'u-boot-dtb:size': len(comp_data),
2285 'size': len(data),
2286 }
2287 self.assertEqual(expected, props)
2288
Simon Glass69f7cb32019-07-08 14:25:41 -06002289 def testCbfsUpdateFdt(self):
2290 """Test that we can update the device tree with CBFS offset/size info"""
2291 self._CheckLz4()
2292 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2293 update_dtb=True)
2294 dtb = fdt.Fdt(out_dtb_fname)
2295 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002296 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass69f7cb32019-07-08 14:25:41 -06002297 del props['cbfs/u-boot:size']
2298 self.assertEqual({
2299 'offset': 0,
2300 'size': len(data),
2301 'image-pos': 0,
2302 'cbfs:offset': 0,
2303 'cbfs:size': len(data),
2304 'cbfs:image-pos': 0,
2305 'cbfs/u-boot:offset': 0x38,
2306 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2307 'cbfs/u-boot:image-pos': 0x38,
2308 'cbfs/u-boot-dtb:offset': 0xb8,
2309 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2310 'cbfs/u-boot-dtb:image-pos': 0xb8,
2311 }, props)
2312
Simon Glass8a1ad062019-07-08 14:25:42 -06002313 def testCbfsBadType(self):
2314 """Test an image header with a no specified location is detected"""
2315 with self.assertRaises(ValueError) as e:
2316 self._DoReadFile('126_cbfs_bad_type.dts')
2317 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2318
Simon Glass41b8ba02019-07-08 14:25:43 -06002319 def testList(self):
2320 """Test listing the files in an image"""
2321 self._CheckLz4()
2322 data = self._DoReadFile('127_list.dts')
2323 image = control.images['image']
2324 entries = image.BuildEntryList()
2325 self.assertEqual(7, len(entries))
2326
2327 ent = entries[0]
2328 self.assertEqual(0, ent.indent)
2329 self.assertEqual('main-section', ent.name)
2330 self.assertEqual('section', ent.etype)
2331 self.assertEqual(len(data), ent.size)
2332 self.assertEqual(0, ent.image_pos)
2333 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002334 self.assertEqual(0, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002335
2336 ent = entries[1]
2337 self.assertEqual(1, ent.indent)
2338 self.assertEqual('u-boot', ent.name)
2339 self.assertEqual('u-boot', ent.etype)
2340 self.assertEqual(len(U_BOOT_DATA), ent.size)
2341 self.assertEqual(0, ent.image_pos)
2342 self.assertEqual(None, ent.uncomp_size)
2343 self.assertEqual(0, ent.offset)
2344
2345 ent = entries[2]
2346 self.assertEqual(1, ent.indent)
2347 self.assertEqual('section', ent.name)
2348 self.assertEqual('section', ent.etype)
2349 section_size = ent.size
2350 self.assertEqual(0x100, ent.image_pos)
2351 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002352 self.assertEqual(0x100, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002353
2354 ent = entries[3]
2355 self.assertEqual(2, ent.indent)
2356 self.assertEqual('cbfs', ent.name)
2357 self.assertEqual('cbfs', ent.etype)
2358 self.assertEqual(0x400, ent.size)
2359 self.assertEqual(0x100, ent.image_pos)
2360 self.assertEqual(None, ent.uncomp_size)
2361 self.assertEqual(0, ent.offset)
2362
2363 ent = entries[4]
2364 self.assertEqual(3, ent.indent)
2365 self.assertEqual('u-boot', ent.name)
2366 self.assertEqual('u-boot', ent.etype)
2367 self.assertEqual(len(U_BOOT_DATA), ent.size)
2368 self.assertEqual(0x138, ent.image_pos)
2369 self.assertEqual(None, ent.uncomp_size)
2370 self.assertEqual(0x38, ent.offset)
2371
2372 ent = entries[5]
2373 self.assertEqual(3, ent.indent)
2374 self.assertEqual('u-boot-dtb', ent.name)
2375 self.assertEqual('text', ent.etype)
2376 self.assertGreater(len(COMPRESS_DATA), ent.size)
2377 self.assertEqual(0x178, ent.image_pos)
2378 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2379 self.assertEqual(0x78, ent.offset)
2380
2381 ent = entries[6]
2382 self.assertEqual(2, ent.indent)
2383 self.assertEqual('u-boot-dtb', ent.name)
2384 self.assertEqual('u-boot-dtb', ent.etype)
2385 self.assertEqual(0x500, ent.image_pos)
2386 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2387 dtb_size = ent.size
2388 # Compressing this data expands it since headers are added
2389 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2390 self.assertEqual(0x400, ent.offset)
2391
2392 self.assertEqual(len(data), 0x100 + section_size)
2393 self.assertEqual(section_size, 0x400 + dtb_size)
2394
Simon Glasse1925fa2019-07-08 14:25:44 -06002395 def testFindFdtmap(self):
2396 """Test locating an FDT map in an image"""
2397 self._CheckLz4()
2398 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2399 image = control.images['image']
2400 entries = image.GetEntries()
2401 entry = entries['fdtmap']
2402 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2403
2404 def testFindFdtmapMissing(self):
2405 """Test failing to locate an FDP map"""
2406 data = self._DoReadFile('005_simple.dts')
2407 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2408
Simon Glass2d260032019-07-08 14:25:45 -06002409 def testFindImageHeader(self):
2410 """Test locating a image header"""
2411 self._CheckLz4()
Simon Glassffded752019-07-08 14:25:46 -06002412 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002413 image = control.images['image']
2414 entries = image.GetEntries()
2415 entry = entries['fdtmap']
2416 # The header should point to the FDT map
2417 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2418
2419 def testFindImageHeaderStart(self):
2420 """Test locating a image header located at the start of an image"""
Simon Glassffded752019-07-08 14:25:46 -06002421 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002422 image = control.images['image']
2423 entries = image.GetEntries()
2424 entry = entries['fdtmap']
2425 # The header should point to the FDT map
2426 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2427
2428 def testFindImageHeaderMissing(self):
2429 """Test failing to locate an image header"""
2430 data = self._DoReadFile('005_simple.dts')
2431 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2432
Simon Glassffded752019-07-08 14:25:46 -06002433 def testReadImage(self):
2434 """Test reading an image and accessing its FDT map"""
2435 self._CheckLz4()
2436 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2437 image_fname = tools.GetOutputFilename('image.bin')
2438 orig_image = control.images['image']
2439 image = Image.FromFile(image_fname)
2440 self.assertEqual(orig_image.GetEntries().keys(),
2441 image.GetEntries().keys())
2442
2443 orig_entry = orig_image.GetEntries()['fdtmap']
2444 entry = image.GetEntries()['fdtmap']
2445 self.assertEquals(orig_entry.offset, entry.offset)
2446 self.assertEquals(orig_entry.size, entry.size)
2447 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2448
2449 def testReadImageNoHeader(self):
2450 """Test accessing an image's FDT map without an image header"""
2451 self._CheckLz4()
2452 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
2453 image_fname = tools.GetOutputFilename('image.bin')
2454 image = Image.FromFile(image_fname)
2455 self.assertTrue(isinstance(image, Image))
Simon Glass10f9d002019-07-20 12:23:50 -06002456 self.assertEqual('image', image.image_name[-5:])
Simon Glassffded752019-07-08 14:25:46 -06002457
2458 def testReadImageFail(self):
2459 """Test failing to read an image image's FDT map"""
2460 self._DoReadFile('005_simple.dts')
2461 image_fname = tools.GetOutputFilename('image.bin')
2462 with self.assertRaises(ValueError) as e:
2463 image = Image.FromFile(image_fname)
2464 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glasse073d4e2019-07-08 13:18:56 -06002465
Simon Glass61f564d2019-07-08 14:25:48 -06002466 def testListCmd(self):
2467 """Test listing the files in an image using an Fdtmap"""
2468 self._CheckLz4()
2469 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2470
2471 # lz4 compression size differs depending on the version
2472 image = control.images['image']
2473 entries = image.GetEntries()
2474 section_size = entries['section'].size
2475 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2476 fdtmap_offset = entries['fdtmap'].offset
2477
Simon Glassf86a7362019-07-20 12:24:10 -06002478 try:
2479 tmpdir, updated_fname = self._SetupImageInTmpdir()
2480 with test_util.capture_sys_output() as (stdout, stderr):
2481 self._DoBinman('ls', '-i', updated_fname)
2482 finally:
2483 shutil.rmtree(tmpdir)
Simon Glass61f564d2019-07-08 14:25:48 -06002484 lines = stdout.getvalue().splitlines()
2485 expected = [
2486'Name Image-pos Size Entry-type Offset Uncomp-size',
2487'----------------------------------------------------------------------',
2488'main-section 0 c00 section 0',
2489' u-boot 0 4 u-boot 0',
2490' section 100 %x section 100' % section_size,
2491' cbfs 100 400 cbfs 0',
2492' u-boot 138 4 u-boot 38',
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002493' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glass61f564d2019-07-08 14:25:48 -06002494' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002495' fdtmap %x 3bd fdtmap %x' %
Simon Glass61f564d2019-07-08 14:25:48 -06002496 (fdtmap_offset, fdtmap_offset),
2497' image-header bf8 8 image-header bf8',
2498 ]
2499 self.assertEqual(expected, lines)
2500
2501 def testListCmdFail(self):
2502 """Test failing to list an image"""
2503 self._DoReadFile('005_simple.dts')
Simon Glassf86a7362019-07-20 12:24:10 -06002504 try:
2505 tmpdir, updated_fname = self._SetupImageInTmpdir()
2506 with self.assertRaises(ValueError) as e:
2507 self._DoBinman('ls', '-i', updated_fname)
2508 finally:
2509 shutil.rmtree(tmpdir)
Simon Glass61f564d2019-07-08 14:25:48 -06002510 self.assertIn("Cannot find FDT map in image", str(e.exception))
2511
2512 def _RunListCmd(self, paths, expected):
2513 """List out entries and check the result
2514
2515 Args:
2516 paths: List of paths to pass to the list command
2517 expected: Expected list of filenames to be returned, in order
2518 """
2519 self._CheckLz4()
2520 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2521 image_fname = tools.GetOutputFilename('image.bin')
2522 image = Image.FromFile(image_fname)
2523 lines = image.GetListEntries(paths)[1]
2524 files = [line[0].strip() for line in lines[1:]]
2525 self.assertEqual(expected, files)
2526
2527 def testListCmdSection(self):
2528 """Test listing the files in a section"""
2529 self._RunListCmd(['section'],
2530 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2531
2532 def testListCmdFile(self):
2533 """Test listing a particular file"""
2534 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2535
2536 def testListCmdWildcard(self):
2537 """Test listing a wildcarded file"""
2538 self._RunListCmd(['*boot*'],
2539 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2540
2541 def testListCmdWildcardMulti(self):
2542 """Test listing a wildcarded file"""
2543 self._RunListCmd(['*cb*', '*head*'],
2544 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2545
2546 def testListCmdEmpty(self):
2547 """Test listing a wildcarded file"""
2548 self._RunListCmd(['nothing'], [])
2549
2550 def testListCmdPath(self):
2551 """Test listing the files in a sub-entry of a section"""
2552 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2553
Simon Glassf667e452019-07-08 14:25:50 -06002554 def _RunExtractCmd(self, entry_name, decomp=True):
2555 """Extract an entry from an image
2556
2557 Args:
2558 entry_name: Entry name to extract
2559 decomp: True to decompress the data if compressed, False to leave
2560 it in its raw uncompressed format
2561
2562 Returns:
2563 data from entry
2564 """
2565 self._CheckLz4()
2566 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2567 image_fname = tools.GetOutputFilename('image.bin')
2568 return control.ReadEntry(image_fname, entry_name, decomp)
2569
2570 def testExtractSimple(self):
2571 """Test extracting a single file"""
2572 data = self._RunExtractCmd('u-boot')
2573 self.assertEqual(U_BOOT_DATA, data)
2574
Simon Glass71ce0ba2019-07-08 14:25:52 -06002575 def testExtractSection(self):
2576 """Test extracting the files in a section"""
2577 data = self._RunExtractCmd('section')
2578 cbfs_data = data[:0x400]
2579 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002580 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass71ce0ba2019-07-08 14:25:52 -06002581 dtb_data = data[0x400:]
2582 dtb = self._decompress(dtb_data)
2583 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2584
2585 def testExtractCompressed(self):
2586 """Test extracting compressed data"""
2587 data = self._RunExtractCmd('section/u-boot-dtb')
2588 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2589
2590 def testExtractRaw(self):
2591 """Test extracting compressed data without decompressing it"""
2592 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2593 dtb = self._decompress(data)
2594 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2595
2596 def testExtractCbfs(self):
2597 """Test extracting CBFS data"""
2598 data = self._RunExtractCmd('section/cbfs/u-boot')
2599 self.assertEqual(U_BOOT_DATA, data)
2600
2601 def testExtractCbfsCompressed(self):
2602 """Test extracting CBFS compressed data"""
2603 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2604 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2605
2606 def testExtractCbfsRaw(self):
2607 """Test extracting CBFS compressed data without decompressing it"""
2608 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Simon Glasseb0f4a42019-07-20 12:24:06 -06002609 dtb = tools.Decompress(data, 'lzma', with_header=False)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002610 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2611
Simon Glassf667e452019-07-08 14:25:50 -06002612 def testExtractBadEntry(self):
2613 """Test extracting a bad section path"""
2614 with self.assertRaises(ValueError) as e:
2615 self._RunExtractCmd('section/does-not-exist')
2616 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2617 str(e.exception))
2618
2619 def testExtractMissingFile(self):
2620 """Test extracting file that does not exist"""
2621 with self.assertRaises(IOError) as e:
2622 control.ReadEntry('missing-file', 'name')
2623
2624 def testExtractBadFile(self):
2625 """Test extracting an invalid file"""
2626 fname = os.path.join(self._indir, 'badfile')
2627 tools.WriteFile(fname, b'')
2628 with self.assertRaises(ValueError) as e:
2629 control.ReadEntry(fname, 'name')
2630
Simon Glass71ce0ba2019-07-08 14:25:52 -06002631 def testExtractCmd(self):
2632 """Test extracting a file fron an image on the command line"""
2633 self._CheckLz4()
2634 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass71ce0ba2019-07-08 14:25:52 -06002635 fname = os.path.join(self._indir, 'output.extact')
Simon Glassf86a7362019-07-20 12:24:10 -06002636 try:
2637 tmpdir, updated_fname = self._SetupImageInTmpdir()
2638 with test_util.capture_sys_output() as (stdout, stderr):
2639 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2640 '-f', fname)
2641 finally:
2642 shutil.rmtree(tmpdir)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002643 data = tools.ReadFile(fname)
2644 self.assertEqual(U_BOOT_DATA, data)
2645
2646 def testExtractOneEntry(self):
2647 """Test extracting a single entry fron an image """
2648 self._CheckLz4()
2649 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2650 image_fname = tools.GetOutputFilename('image.bin')
2651 fname = os.path.join(self._indir, 'output.extact')
2652 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
2653 data = tools.ReadFile(fname)
2654 self.assertEqual(U_BOOT_DATA, data)
2655
2656 def _CheckExtractOutput(self, decomp):
2657 """Helper to test file output with and without decompression
2658
2659 Args:
2660 decomp: True to decompress entry data, False to output it raw
2661 """
2662 def _CheckPresent(entry_path, expect_data, expect_size=None):
2663 """Check and remove expected file
2664
2665 This checks the data/size of a file and removes the file both from
2666 the outfiles set and from the output directory. Once all files are
2667 processed, both the set and directory should be empty.
2668
2669 Args:
2670 entry_path: Entry path
2671 expect_data: Data to expect in file, or None to skip check
2672 expect_size: Size of data to expect in file, or None to skip
2673 """
2674 path = os.path.join(outdir, entry_path)
2675 data = tools.ReadFile(path)
2676 os.remove(path)
2677 if expect_data:
2678 self.assertEqual(expect_data, data)
2679 elif expect_size:
2680 self.assertEqual(expect_size, len(data))
2681 outfiles.remove(path)
2682
2683 def _CheckDirPresent(name):
2684 """Remove expected directory
2685
2686 This gives an error if the directory does not exist as expected
2687
2688 Args:
2689 name: Name of directory to remove
2690 """
2691 path = os.path.join(outdir, name)
2692 os.rmdir(path)
2693
2694 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2695 image_fname = tools.GetOutputFilename('image.bin')
2696 outdir = os.path.join(self._indir, 'extract')
2697 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2698
2699 # Create a set of all file that were output (should be 9)
2700 outfiles = set()
2701 for root, dirs, files in os.walk(outdir):
2702 outfiles |= set([os.path.join(root, fname) for fname in files])
2703 self.assertEqual(9, len(outfiles))
2704 self.assertEqual(9, len(einfos))
2705
2706 image = control.images['image']
2707 entries = image.GetEntries()
2708
2709 # Check the 9 files in various ways
2710 section = entries['section']
2711 section_entries = section.GetEntries()
2712 cbfs_entries = section_entries['cbfs'].GetEntries()
2713 _CheckPresent('u-boot', U_BOOT_DATA)
2714 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
2715 dtb_len = EXTRACT_DTB_SIZE
2716 if not decomp:
2717 dtb_len = cbfs_entries['u-boot-dtb'].size
2718 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
2719 if not decomp:
2720 dtb_len = section_entries['u-boot-dtb'].size
2721 _CheckPresent('section/u-boot-dtb', None, dtb_len)
2722
2723 fdtmap = entries['fdtmap']
2724 _CheckPresent('fdtmap', fdtmap.data)
2725 hdr = entries['image-header']
2726 _CheckPresent('image-header', hdr.data)
2727
2728 _CheckPresent('section/root', section.data)
2729 cbfs = section_entries['cbfs']
2730 _CheckPresent('section/cbfs/root', cbfs.data)
2731 data = tools.ReadFile(image_fname)
2732 _CheckPresent('root', data)
2733
2734 # There should be no files left. Remove all the directories to check.
2735 # If there are any files/dirs remaining, one of these checks will fail.
2736 self.assertEqual(0, len(outfiles))
2737 _CheckDirPresent('section/cbfs')
2738 _CheckDirPresent('section')
2739 _CheckDirPresent('')
2740 self.assertFalse(os.path.exists(outdir))
2741
2742 def testExtractAllEntries(self):
2743 """Test extracting all entries"""
2744 self._CheckLz4()
2745 self._CheckExtractOutput(decomp=True)
2746
2747 def testExtractAllEntriesRaw(self):
2748 """Test extracting all entries without decompressing them"""
2749 self._CheckLz4()
2750 self._CheckExtractOutput(decomp=False)
2751
2752 def testExtractSelectedEntries(self):
2753 """Test extracting some entries"""
2754 self._CheckLz4()
2755 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2756 image_fname = tools.GetOutputFilename('image.bin')
2757 outdir = os.path.join(self._indir, 'extract')
2758 einfos = control.ExtractEntries(image_fname, None, outdir,
2759 ['*cb*', '*head*'])
2760
2761 # File output is tested by testExtractAllEntries(), so just check that
2762 # the expected entries are selected
2763 names = [einfo.name for einfo in einfos]
2764 self.assertEqual(names,
2765 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2766
2767 def testExtractNoEntryPaths(self):
2768 """Test extracting some entries"""
2769 self._CheckLz4()
2770 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2771 image_fname = tools.GetOutputFilename('image.bin')
2772 with self.assertRaises(ValueError) as e:
2773 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassbb5edc12019-07-20 12:24:14 -06002774 self.assertIn('Must specify an entry path to write with -f',
Simon Glass71ce0ba2019-07-08 14:25:52 -06002775 str(e.exception))
2776
2777 def testExtractTooManyEntryPaths(self):
2778 """Test extracting some entries"""
2779 self._CheckLz4()
2780 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2781 image_fname = tools.GetOutputFilename('image.bin')
2782 with self.assertRaises(ValueError) as e:
2783 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassbb5edc12019-07-20 12:24:14 -06002784 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass71ce0ba2019-07-08 14:25:52 -06002785 str(e.exception))
2786
Simon Glasse2705fa2019-07-08 14:25:53 -06002787 def testPackAlignSection(self):
2788 """Test that sections can have alignment"""
2789 self._DoReadFile('131_pack_align_section.dts')
2790
2791 self.assertIn('image', control.images)
2792 image = control.images['image']
2793 entries = image.GetEntries()
2794 self.assertEqual(3, len(entries))
2795
2796 # First u-boot
2797 self.assertIn('u-boot', entries)
2798 entry = entries['u-boot']
2799 self.assertEqual(0, entry.offset)
2800 self.assertEqual(0, entry.image_pos)
2801 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2802 self.assertEqual(len(U_BOOT_DATA), entry.size)
2803
2804 # Section0
2805 self.assertIn('section0', entries)
2806 section0 = entries['section0']
2807 self.assertEqual(0x10, section0.offset)
2808 self.assertEqual(0x10, section0.image_pos)
2809 self.assertEqual(len(U_BOOT_DATA), section0.size)
2810
2811 # Second u-boot
2812 section_entries = section0.GetEntries()
2813 self.assertIn('u-boot', section_entries)
2814 entry = section_entries['u-boot']
2815 self.assertEqual(0, entry.offset)
2816 self.assertEqual(0x10, entry.image_pos)
2817 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2818 self.assertEqual(len(U_BOOT_DATA), entry.size)
2819
2820 # Section1
2821 self.assertIn('section1', entries)
2822 section1 = entries['section1']
2823 self.assertEqual(0x14, section1.offset)
2824 self.assertEqual(0x14, section1.image_pos)
2825 self.assertEqual(0x20, section1.size)
2826
2827 # Second u-boot
2828 section_entries = section1.GetEntries()
2829 self.assertIn('u-boot', section_entries)
2830 entry = section_entries['u-boot']
2831 self.assertEqual(0, entry.offset)
2832 self.assertEqual(0x14, entry.image_pos)
2833 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2834 self.assertEqual(len(U_BOOT_DATA), entry.size)
2835
2836 # Section2
2837 self.assertIn('section2', section_entries)
2838 section2 = section_entries['section2']
2839 self.assertEqual(0x4, section2.offset)
2840 self.assertEqual(0x18, section2.image_pos)
2841 self.assertEqual(4, section2.size)
2842
2843 # Third u-boot
2844 section_entries = section2.GetEntries()
2845 self.assertIn('u-boot', section_entries)
2846 entry = section_entries['u-boot']
2847 self.assertEqual(0, entry.offset)
2848 self.assertEqual(0x18, entry.image_pos)
2849 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2850 self.assertEqual(len(U_BOOT_DATA), entry.size)
2851
Simon Glass51014aa2019-07-20 12:23:56 -06002852 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
2853 dts='132_replace.dts'):
Simon Glass10f9d002019-07-20 12:23:50 -06002854 """Replace an entry in an image
2855
2856 This writes the entry data to update it, then opens the updated file and
2857 returns the value that it now finds there.
2858
2859 Args:
2860 entry_name: Entry name to replace
2861 data: Data to replace it with
2862 decomp: True to compress the data if needed, False if data is
2863 already compressed so should be used as is
Simon Glass51014aa2019-07-20 12:23:56 -06002864 allow_resize: True to allow entries to change size, False to raise
2865 an exception
Simon Glass10f9d002019-07-20 12:23:50 -06002866
2867 Returns:
2868 Tuple:
2869 data from entry
2870 data from fdtmap (excluding header)
Simon Glass51014aa2019-07-20 12:23:56 -06002871 Image object that was modified
Simon Glass10f9d002019-07-20 12:23:50 -06002872 """
Simon Glass51014aa2019-07-20 12:23:56 -06002873 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass10f9d002019-07-20 12:23:50 -06002874 update_dtb=True)[1]
2875
2876 self.assertIn('image', control.images)
2877 image = control.images['image']
2878 entries = image.GetEntries()
2879 orig_dtb_data = entries['u-boot-dtb'].data
2880 orig_fdtmap_data = entries['fdtmap'].data
2881
2882 image_fname = tools.GetOutputFilename('image.bin')
2883 updated_fname = tools.GetOutputFilename('image-updated.bin')
2884 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
Simon Glass51014aa2019-07-20 12:23:56 -06002885 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
2886 allow_resize)
Simon Glass10f9d002019-07-20 12:23:50 -06002887 data = control.ReadEntry(updated_fname, entry_name, decomp)
2888
Simon Glass51014aa2019-07-20 12:23:56 -06002889 # The DT data should not change unless resized:
2890 if not allow_resize:
2891 new_dtb_data = entries['u-boot-dtb'].data
2892 self.assertEqual(new_dtb_data, orig_dtb_data)
2893 new_fdtmap_data = entries['fdtmap'].data
2894 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass10f9d002019-07-20 12:23:50 -06002895
Simon Glass51014aa2019-07-20 12:23:56 -06002896 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass10f9d002019-07-20 12:23:50 -06002897
2898 def testReplaceSimple(self):
2899 """Test replacing a single file"""
2900 expected = b'x' * len(U_BOOT_DATA)
Simon Glass51014aa2019-07-20 12:23:56 -06002901 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
2902 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06002903 self.assertEqual(expected, data)
2904
2905 # Test that the state looks right. There should be an FDT for the fdtmap
2906 # that we jsut read back in, and it should match what we find in the
2907 # 'control' tables. Checking for an FDT that does not exist should
2908 # return None.
2909 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glass51014aa2019-07-20 12:23:56 -06002910 self.assertIsNotNone(path)
Simon Glass10f9d002019-07-20 12:23:50 -06002911 self.assertEqual(expected_fdtmap, fdtmap)
2912
2913 dtb = state.GetFdtForEtype('fdtmap')
2914 self.assertEqual(dtb.GetContents(), fdtmap)
2915
2916 missing_path, missing_fdtmap = state.GetFdtContents('missing')
2917 self.assertIsNone(missing_path)
2918 self.assertIsNone(missing_fdtmap)
2919
2920 missing_dtb = state.GetFdtForEtype('missing')
2921 self.assertIsNone(missing_dtb)
2922
2923 self.assertEqual('/binman', state.fdt_path_prefix)
2924
2925 def testReplaceResizeFail(self):
2926 """Test replacing a file by something larger"""
2927 expected = U_BOOT_DATA + b'x'
2928 with self.assertRaises(ValueError) as e:
Simon Glass51014aa2019-07-20 12:23:56 -06002929 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
2930 dts='139_replace_repack.dts')
Simon Glass10f9d002019-07-20 12:23:50 -06002931 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
2932 str(e.exception))
2933
2934 def testReplaceMulti(self):
2935 """Test replacing entry data where multiple images are generated"""
2936 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
2937 update_dtb=True)[0]
2938 expected = b'x' * len(U_BOOT_DATA)
2939 updated_fname = tools.GetOutputFilename('image-updated.bin')
2940 tools.WriteFile(updated_fname, data)
2941 entry_name = 'u-boot'
Simon Glass51014aa2019-07-20 12:23:56 -06002942 control.WriteEntry(updated_fname, entry_name, expected,
2943 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06002944 data = control.ReadEntry(updated_fname, entry_name)
2945 self.assertEqual(expected, data)
2946
2947 # Check the state looks right.
2948 self.assertEqual('/binman/image', state.fdt_path_prefix)
2949
2950 # Now check we can write the first image
2951 image_fname = tools.GetOutputFilename('first-image.bin')
2952 updated_fname = tools.GetOutputFilename('first-updated.bin')
2953 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
2954 entry_name = 'u-boot'
Simon Glass51014aa2019-07-20 12:23:56 -06002955 control.WriteEntry(updated_fname, entry_name, expected,
2956 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06002957 data = control.ReadEntry(updated_fname, entry_name)
2958 self.assertEqual(expected, data)
2959
2960 # Check the state looks right.
2961 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass8beb11e2019-07-08 14:25:47 -06002962
Simon Glass12bb1a92019-07-20 12:23:51 -06002963 def testUpdateFdtAllRepack(self):
2964 """Test that all device trees are updated with offset/size info"""
2965 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
2966 SECTION_SIZE = 0x300
2967 DTB_SIZE = 602
2968 FDTMAP_SIZE = 608
2969 base_expected = {
2970 'offset': 0,
2971 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
2972 'image-pos': 0,
2973 'section:offset': 0,
2974 'section:size': SECTION_SIZE,
2975 'section:image-pos': 0,
2976 'section/u-boot-dtb:offset': 4,
2977 'section/u-boot-dtb:size': 636,
2978 'section/u-boot-dtb:image-pos': 4,
2979 'u-boot-spl-dtb:offset': SECTION_SIZE,
2980 'u-boot-spl-dtb:size': DTB_SIZE,
2981 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
2982 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
2983 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
2984 'u-boot-tpl-dtb:size': DTB_SIZE,
2985 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
2986 'fdtmap:size': FDTMAP_SIZE,
2987 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
2988 }
2989 main_expected = {
2990 'section:orig-size': SECTION_SIZE,
2991 'section/u-boot-dtb:orig-offset': 4,
2992 }
2993
2994 # We expect three device-tree files in the output, with the first one
2995 # within a fixed-size section.
2996 # Read them in sequence. We look for an 'spl' property in the SPL tree,
2997 # and 'tpl' in the TPL tree, to make sure they are distinct from the
2998 # main U-Boot tree. All three should have the same positions and offset
2999 # except that the main tree should include the main_expected properties
3000 start = 4
3001 for item in ['', 'spl', 'tpl', None]:
3002 if item is None:
3003 start += 16 # Move past fdtmap header
3004 dtb = fdt.Fdt.FromData(data[start:])
3005 dtb.Scan()
3006 props = self._GetPropTree(dtb,
3007 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3008 prefix='/' if item is None else '/binman/')
3009 expected = dict(base_expected)
3010 if item:
3011 expected[item] = 0
3012 else:
3013 # Main DTB and fdtdec should include the 'orig-' properties
3014 expected.update(main_expected)
3015 # Helpful for debugging:
3016 #for prop in sorted(props):
3017 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3018 self.assertEqual(expected, props)
3019 if item == '':
3020 start = SECTION_SIZE
3021 else:
3022 start += dtb._fdt_obj.totalsize()
3023
Simon Glasseba1f0c2019-07-20 12:23:55 -06003024 def testFdtmapHeaderMiddle(self):
3025 """Test an FDT map in the middle of an image when it should be at end"""
3026 with self.assertRaises(ValueError) as e:
3027 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3028 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3029 str(e.exception))
3030
3031 def testFdtmapHeaderStartBad(self):
3032 """Test an FDT map in middle of an image when it should be at start"""
3033 with self.assertRaises(ValueError) as e:
3034 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3035 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3036 str(e.exception))
3037
3038 def testFdtmapHeaderEndBad(self):
3039 """Test an FDT map at the start of an image when it should be at end"""
3040 with self.assertRaises(ValueError) as e:
3041 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3042 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3043 str(e.exception))
3044
3045 def testFdtmapHeaderNoSize(self):
3046 """Test an image header at the end of an image with undefined size"""
3047 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3048
Simon Glass51014aa2019-07-20 12:23:56 -06003049 def testReplaceResize(self):
3050 """Test replacing a single file in an entry with a larger file"""
3051 expected = U_BOOT_DATA + b'x'
3052 data, _, image = self._RunReplaceCmd('u-boot', expected,
3053 dts='139_replace_repack.dts')
3054 self.assertEqual(expected, data)
3055
3056 entries = image.GetEntries()
3057 dtb_data = entries['u-boot-dtb'].data
3058 dtb = fdt.Fdt.FromData(dtb_data)
3059 dtb.Scan()
3060
3061 # The u-boot section should now be larger in the dtb
3062 node = dtb.GetNode('/binman/u-boot')
3063 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3064
3065 # Same for the fdtmap
3066 fdata = entries['fdtmap'].data
3067 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3068 fdtb.Scan()
3069 fnode = fdtb.GetNode('/u-boot')
3070 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3071
3072 def testReplaceResizeNoRepack(self):
3073 """Test replacing an entry with a larger file when not allowed"""
3074 expected = U_BOOT_DATA + b'x'
3075 with self.assertRaises(ValueError) as e:
3076 self._RunReplaceCmd('u-boot', expected)
3077 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3078 str(e.exception))
3079
Simon Glass61ec04f2019-07-20 12:23:58 -06003080 def testEntryShrink(self):
3081 """Test contracting an entry after it is packed"""
3082 try:
3083 state.SetAllowEntryContraction(True)
3084 data = self._DoReadFileDtb('140_entry_shrink.dts',
3085 update_dtb=True)[0]
3086 finally:
3087 state.SetAllowEntryContraction(False)
3088 self.assertEqual(b'a', data[:1])
3089 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3090 self.assertEqual(b'a', data[-1:])
3091
3092 def testEntryShrinkFail(self):
3093 """Test not being allowed to contract an entry after it is packed"""
3094 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3095
3096 # In this case there is a spare byte at the end of the data. The size of
3097 # the contents is only 1 byte but we still have the size before it
3098 # shrunk.
3099 self.assertEqual(b'a\0', data[:2])
3100 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3101 self.assertEqual(b'a\0', data[-2:])
3102
Simon Glass27145fd2019-07-20 12:24:01 -06003103 def testDescriptorOffset(self):
3104 """Test that the Intel descriptor is always placed at at the start"""
3105 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3106 image = control.images['image']
3107 entries = image.GetEntries()
3108 desc = entries['intel-descriptor']
3109 self.assertEqual(0xff800000, desc.offset);
3110 self.assertEqual(0xff800000, desc.image_pos);
3111
Simon Glasseb0f4a42019-07-20 12:24:06 -06003112 def testReplaceCbfs(self):
3113 """Test replacing a single file in CBFS without changing the size"""
3114 self._CheckLz4()
3115 expected = b'x' * len(U_BOOT_DATA)
3116 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3117 updated_fname = tools.GetOutputFilename('image-updated.bin')
3118 tools.WriteFile(updated_fname, data)
3119 entry_name = 'section/cbfs/u-boot'
3120 control.WriteEntry(updated_fname, entry_name, expected,
3121 allow_resize=True)
3122 data = control.ReadEntry(updated_fname, entry_name)
3123 self.assertEqual(expected, data)
3124
3125 def testReplaceResizeCbfs(self):
3126 """Test replacing a single file in CBFS with one of a different size"""
3127 self._CheckLz4()
3128 expected = U_BOOT_DATA + b'x'
3129 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3130 updated_fname = tools.GetOutputFilename('image-updated.bin')
3131 tools.WriteFile(updated_fname, data)
3132 entry_name = 'section/cbfs/u-boot'
3133 control.WriteEntry(updated_fname, entry_name, expected,
3134 allow_resize=True)
3135 data = control.ReadEntry(updated_fname, entry_name)
3136 self.assertEqual(expected, data)
3137
Simon Glassa6cb9952019-07-20 12:24:15 -06003138 def _SetupForReplace(self):
3139 """Set up some files to use to replace entries
3140
3141 This generates an image, copies it to a new file, extracts all the files
3142 in it and updates some of them
3143
3144 Returns:
3145 List
3146 Image filename
3147 Output directory
3148 Expected values for updated entries, each a string
3149 """
3150 data = self._DoReadFileRealDtb('143_replace_all.dts')
3151
3152 updated_fname = tools.GetOutputFilename('image-updated.bin')
3153 tools.WriteFile(updated_fname, data)
3154
3155 outdir = os.path.join(self._indir, 'extract')
3156 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3157
3158 expected1 = b'x' + U_BOOT_DATA + b'y'
3159 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3160 tools.WriteFile(u_boot_fname1, expected1)
3161
3162 expected2 = b'a' + U_BOOT_DATA + b'b'
3163 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
3164 tools.WriteFile(u_boot_fname2, expected2)
3165
3166 expected_text = b'not the same text'
3167 text_fname = os.path.join(outdir, 'text')
3168 tools.WriteFile(text_fname, expected_text)
3169
3170 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3171 dtb = fdt.FdtScan(dtb_fname)
3172 node = dtb.GetNode('/binman/text')
3173 node.AddString('my-property', 'the value')
3174 dtb.Sync(auto_resize=True)
3175 dtb.Flush()
3176
3177 return updated_fname, outdir, expected1, expected2, expected_text
3178
3179 def _CheckReplaceMultiple(self, entry_paths):
3180 """Handle replacing the contents of multiple entries
3181
3182 Args:
3183 entry_paths: List of entry paths to replace
3184
3185 Returns:
3186 List
3187 Dict of entries in the image:
3188 key: Entry name
3189 Value: Entry object
3190 Expected values for updated entries, each a string
3191 """
3192 updated_fname, outdir, expected1, expected2, expected_text = (
3193 self._SetupForReplace())
3194 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3195
3196 image = Image.FromFile(updated_fname)
3197 image.LoadData()
3198 return image.GetEntries(), expected1, expected2, expected_text
3199
3200 def testReplaceAll(self):
3201 """Test replacing the contents of all entries"""
3202 entries, expected1, expected2, expected_text = (
3203 self._CheckReplaceMultiple([]))
3204 data = entries['u-boot'].data
3205 self.assertEqual(expected1, data)
3206
3207 data = entries['u-boot2'].data
3208 self.assertEqual(expected2, data)
3209
3210 data = entries['text'].data
3211 self.assertEqual(expected_text, data)
3212
3213 # Check that the device tree is updated
3214 data = entries['u-boot-dtb'].data
3215 dtb = fdt.Fdt.FromData(data)
3216 dtb.Scan()
3217 node = dtb.GetNode('/binman/text')
3218 self.assertEqual('the value', node.props['my-property'].value)
3219
3220 def testReplaceSome(self):
3221 """Test replacing the contents of a few entries"""
3222 entries, expected1, expected2, expected_text = (
3223 self._CheckReplaceMultiple(['u-boot2', 'text']))
3224
3225 # This one should not change
3226 data = entries['u-boot'].data
3227 self.assertEqual(U_BOOT_DATA, data)
3228
3229 data = entries['u-boot2'].data
3230 self.assertEqual(expected2, data)
3231
3232 data = entries['text'].data
3233 self.assertEqual(expected_text, data)
3234
3235 def testReplaceCmd(self):
3236 """Test replacing a file fron an image on the command line"""
3237 self._DoReadFileRealDtb('143_replace_all.dts')
3238
3239 try:
3240 tmpdir, updated_fname = self._SetupImageInTmpdir()
3241
3242 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3243 expected = b'x' * len(U_BOOT_DATA)
3244 tools.WriteFile(fname, expected)
3245
3246 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
3247 data = tools.ReadFile(updated_fname)
3248 self.assertEqual(expected, data[:len(expected)])
3249 map_fname = os.path.join(tmpdir, 'image-updated.map')
3250 self.assertFalse(os.path.exists(map_fname))
3251 finally:
3252 shutil.rmtree(tmpdir)
3253
3254 def testReplaceCmdSome(self):
3255 """Test replacing some files fron an image on the command line"""
3256 updated_fname, outdir, expected1, expected2, expected_text = (
3257 self._SetupForReplace())
3258
3259 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3260 'u-boot2', 'text')
3261
3262 tools.PrepareOutputDir(None)
3263 image = Image.FromFile(updated_fname)
3264 image.LoadData()
3265 entries = image.GetEntries()
3266
3267 # This one should not change
3268 data = entries['u-boot'].data
3269 self.assertEqual(U_BOOT_DATA, data)
3270
3271 data = entries['u-boot2'].data
3272 self.assertEqual(expected2, data)
3273
3274 data = entries['text'].data
3275 self.assertEqual(expected_text, data)
3276
3277 def testReplaceMissing(self):
3278 """Test replacing entries where the file is missing"""
3279 updated_fname, outdir, expected1, expected2, expected_text = (
3280 self._SetupForReplace())
3281
3282 # Remove one of the files, to generate a warning
3283 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3284 os.remove(u_boot_fname1)
3285
3286 with test_util.capture_sys_output() as (stdout, stderr):
3287 control.ReplaceEntries(updated_fname, None, outdir, [])
3288 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass38fdb4c2020-07-09 18:39:39 -06003289 stderr.getvalue())
Simon Glassa6cb9952019-07-20 12:24:15 -06003290
3291 def testReplaceCmdMap(self):
3292 """Test replacing a file fron an image on the command line"""
3293 self._DoReadFileRealDtb('143_replace_all.dts')
3294
3295 try:
3296 tmpdir, updated_fname = self._SetupImageInTmpdir()
3297
3298 fname = os.path.join(self._indir, 'update-u-boot.bin')
3299 expected = b'x' * len(U_BOOT_DATA)
3300 tools.WriteFile(fname, expected)
3301
3302 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3303 '-f', fname, '-m')
3304 map_fname = os.path.join(tmpdir, 'image-updated.map')
3305 self.assertTrue(os.path.exists(map_fname))
3306 finally:
3307 shutil.rmtree(tmpdir)
3308
3309 def testReplaceNoEntryPaths(self):
3310 """Test replacing an entry without an entry path"""
3311 self._DoReadFileRealDtb('143_replace_all.dts')
3312 image_fname = tools.GetOutputFilename('image.bin')
3313 with self.assertRaises(ValueError) as e:
3314 control.ReplaceEntries(image_fname, 'fname', None, [])
3315 self.assertIn('Must specify an entry path to read with -f',
3316 str(e.exception))
3317
3318 def testReplaceTooManyEntryPaths(self):
3319 """Test extracting some entries"""
3320 self._DoReadFileRealDtb('143_replace_all.dts')
3321 image_fname = tools.GetOutputFilename('image.bin')
3322 with self.assertRaises(ValueError) as e:
3323 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3324 self.assertIn('Must specify exactly one entry path to write with -f',
3325 str(e.exception))
3326
Simon Glass2250ee62019-08-24 07:22:48 -06003327 def testPackReset16(self):
3328 """Test that an image with an x86 reset16 region can be created"""
3329 data = self._DoReadFile('144_x86_reset16.dts')
3330 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3331
3332 def testPackReset16Spl(self):
3333 """Test that an image with an x86 reset16-spl region can be created"""
3334 data = self._DoReadFile('145_x86_reset16_spl.dts')
3335 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3336
3337 def testPackReset16Tpl(self):
3338 """Test that an image with an x86 reset16-tpl region can be created"""
3339 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3340 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3341
Simon Glass5af12072019-08-24 07:22:50 -06003342 def testPackIntelFit(self):
3343 """Test that an image with an Intel FIT and pointer can be created"""
3344 data = self._DoReadFile('147_intel_fit.dts')
3345 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3346 fit = data[16:32];
3347 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3348 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3349
3350 image = control.images['image']
3351 entries = image.GetEntries()
3352 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3353 self.assertEqual(expected_ptr, ptr)
3354
3355 def testPackIntelFitMissing(self):
3356 """Test detection of a FIT pointer with not FIT region"""
3357 with self.assertRaises(ValueError) as e:
3358 self._DoReadFile('148_intel_fit_missing.dts')
3359 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3360 str(e.exception))
3361
Simon Glass7c150132019-11-06 17:22:44 -07003362 def _CheckSymbolsTplSection(self, dts, expected_vals):
3363 data = self._DoReadFile(dts)
3364 sym_values = struct.pack('<LQLL', *expected_vals)
Simon Glass2090f1e2019-08-24 07:23:00 -06003365 upto1 = 4 + len(U_BOOT_SPL_DATA)
Simon Glassb87064c2019-08-24 07:23:05 -06003366 expected1 = tools.GetBytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[20:]
Simon Glass2090f1e2019-08-24 07:23:00 -06003367 self.assertEqual(expected1, data[:upto1])
3368
3369 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Simon Glassb87064c2019-08-24 07:23:05 -06003370 expected2 = tools.GetBytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[20:]
Simon Glass2090f1e2019-08-24 07:23:00 -06003371 self.assertEqual(expected2, data[upto1:upto2])
3372
Simon Glasseb0086f2019-08-24 07:23:04 -06003373 upto3 = 0x34 + len(U_BOOT_DATA)
3374 expected3 = tools.GetBytes(0xff, 1) + U_BOOT_DATA
Simon Glass2090f1e2019-08-24 07:23:00 -06003375 self.assertEqual(expected3, data[upto2:upto3])
3376
Simon Glassb87064c2019-08-24 07:23:05 -06003377 expected4 = sym_values + U_BOOT_TPL_DATA[20:]
Simon Glass7c150132019-11-06 17:22:44 -07003378 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3379
3380 def testSymbolsTplSection(self):
3381 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3382 self._SetupSplElf('u_boot_binman_syms')
3383 self._SetupTplElf('u_boot_binman_syms')
3384 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
3385 [0x04, 0x1c, 0x10 + 0x34, 0x04])
3386
3387 def testSymbolsTplSectionX86(self):
3388 """Test binman can assign symbols in a section with end-at-4gb"""
3389 self._SetupSplElf('u_boot_binman_syms_x86')
3390 self._SetupTplElf('u_boot_binman_syms_x86')
3391 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
3392 [0xffffff04, 0xffffff1c, 0xffffff34,
3393 0x04])
Simon Glass2090f1e2019-08-24 07:23:00 -06003394
Simon Glassbf4d0e22019-08-24 07:23:03 -06003395 def testPackX86RomIfwiSectiom(self):
3396 """Test that a section can be placed in an IFWI region"""
3397 self._SetupIfwi('fitimage.bin')
3398 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3399 self._CheckIfwi(data)
3400
Simon Glassea0fff92019-08-24 07:23:07 -06003401 def testPackFspM(self):
3402 """Test that an image with a FSP memory-init binary can be created"""
3403 data = self._DoReadFile('152_intel_fsp_m.dts')
3404 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3405
Simon Glassbc6a88f2019-10-20 21:31:35 -06003406 def testPackFspS(self):
3407 """Test that an image with a FSP silicon-init binary can be created"""
3408 data = self._DoReadFile('153_intel_fsp_s.dts')
3409 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassea0fff92019-08-24 07:23:07 -06003410
Simon Glass998d1482019-10-20 21:31:36 -06003411 def testPackFspT(self):
3412 """Test that an image with a FSP temp-ram-init binary can be created"""
3413 data = self._DoReadFile('154_intel_fsp_t.dts')
3414 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3415
Simon Glass0dc706f2020-07-09 18:39:31 -06003416 def testMkimage(self):
3417 """Test using mkimage to build an image"""
3418 data = self._DoReadFile('156_mkimage.dts')
3419
3420 # Just check that the data appears in the file somewhere
3421 self.assertIn(U_BOOT_SPL_DATA, data)
3422
Simon Glassce867ad2020-07-09 18:39:36 -06003423 def testExtblob(self):
3424 """Test an image with an external blob"""
3425 data = self._DoReadFile('157_blob_ext.dts')
3426 self.assertEqual(REFCODE_DATA, data)
3427
3428 def testExtblobMissing(self):
3429 """Test an image with a missing external blob"""
3430 with self.assertRaises(ValueError) as e:
3431 self._DoReadFile('158_blob_ext_missing.dts')
3432 self.assertIn("Filename 'missing-file' not found in input path",
3433 str(e.exception))
3434
Simon Glass4f9f1052020-07-09 18:39:38 -06003435 def testExtblobMissingOk(self):
3436 """Test an image with an missing external blob that is allowed"""
Simon Glassb1cca952020-07-09 18:39:40 -06003437 with test_util.capture_sys_output() as (stdout, stderr):
3438 self._DoTestFile('158_blob_ext_missing.dts', allow_missing=True)
3439 err = stderr.getvalue()
3440 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
3441
3442 def testExtblobMissingOkSect(self):
3443 """Test an image with an missing external blob that is allowed"""
3444 with test_util.capture_sys_output() as (stdout, stderr):
3445 self._DoTestFile('159_blob_ext_missing_sect.dts',
3446 allow_missing=True)
3447 err = stderr.getvalue()
3448 self.assertRegex(err, "Image 'main-section'.*missing.*: "
3449 "blob-ext blob-ext2")
Simon Glass4f9f1052020-07-09 18:39:38 -06003450
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003451 def testPackX86RomMeMissingDesc(self):
3452 """Test that an missing Intel descriptor entry is allowed"""
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003453 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass52b10dd2020-07-25 15:11:19 -06003454 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003455 err = stderr.getvalue()
3456 self.assertRegex(err,
3457 "Image 'main-section'.*missing.*: intel-descriptor")
3458
3459 def testPackX86RomMissingIfwi(self):
3460 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3461 self._SetupIfwi('fitimage.bin')
3462 pathname = os.path.join(self._indir, 'fitimage.bin')
3463 os.remove(pathname)
3464 with test_util.capture_sys_output() as (stdout, stderr):
3465 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3466 err = stderr.getvalue()
3467 self.assertRegex(err, "Image 'main-section'.*missing.*: intel-ifwi")
3468
Simon Glassb3295fd2020-07-09 18:39:42 -06003469 def testPackOverlap(self):
3470 """Test that zero-size overlapping regions are ignored"""
3471 self._DoTestFile('160_pack_overlap_zero.dts')
3472
Simon Glassfdc34362020-07-09 18:39:45 -06003473 def testSimpleFit(self):
3474 """Test an image with a FIT inside"""
3475 data = self._DoReadFile('161_fit.dts')
3476 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3477 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3478 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3479
3480 # The data should be inside the FIT
3481 dtb = fdt.Fdt.FromData(fit_data)
3482 dtb.Scan()
3483 fnode = dtb.GetNode('/images/kernel')
3484 self.assertIn('data', fnode.props)
3485
3486 fname = os.path.join(self._indir, 'fit_data.fit')
3487 tools.WriteFile(fname, fit_data)
3488 out = tools.Run('dumpimage', '-l', fname)
3489
3490 # Check a few features to make sure the plumbing works. We don't need
3491 # to test the operation of mkimage or dumpimage here. First convert the
3492 # output into a dict where the keys are the fields printed by dumpimage
3493 # and the values are a list of values for each field
3494 lines = out.splitlines()
3495
3496 # Converts "Compression: gzip compressed" into two groups:
3497 # 'Compression' and 'gzip compressed'
3498 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3499 vals = collections.defaultdict(list)
3500 for line in lines:
3501 mat = re_line.match(line)
3502 vals[mat.group(1)].append(mat.group(2))
3503
3504 self.assertEquals('FIT description: test-desc', lines[0])
3505 self.assertIn('Created:', lines[1])
3506 self.assertIn('Image 0 (kernel)', vals)
3507 self.assertIn('Hash value', vals)
3508 data_sizes = vals.get('Data Size')
3509 self.assertIsNotNone(data_sizes)
3510 self.assertEqual(2, len(data_sizes))
3511 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
3512 self.assertEqual(len(U_BOOT_DATA), int(data_sizes[0].split()[0]))
3513 self.assertEqual(len(U_BOOT_SPL_DTB_DATA), int(data_sizes[1].split()[0]))
3514
3515 def testFitExternal(self):
Simon Glasse9d336d2020-09-01 05:13:55 -06003516 """Test an image with an FIT with external images"""
Simon Glassfdc34362020-07-09 18:39:45 -06003517 data = self._DoReadFile('162_fit_external.dts')
3518 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3519
3520 # The data should be outside the FIT
3521 dtb = fdt.Fdt.FromData(fit_data)
3522 dtb.Scan()
3523 fnode = dtb.GetNode('/images/kernel')
3524 self.assertNotIn('data', fnode.props)
Simon Glass12bb1a92019-07-20 12:23:51 -06003525
Alper Nebi Yasak8001d0b2020-08-31 12:58:18 +03003526 def testSectionIgnoreHashSignature(self):
3527 """Test that sections ignore hash, signature nodes for its data"""
3528 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
3529 expected = (U_BOOT_DATA + U_BOOT_DATA)
3530 self.assertEqual(expected, data)
3531
Alper Nebi Yasak3fdeb142020-08-31 12:58:19 +03003532 def testPadInSections(self):
3533 """Test pad-before, pad-after for entries in sections"""
3534 data = self._DoReadFile('166_pad_in_sections.dts')
3535 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
3536 U_BOOT_DATA + tools.GetBytes(ord('!'), 6) +
3537 U_BOOT_DATA)
3538 self.assertEqual(expected, data)
3539
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03003540 def testFitImageSubentryAlignment(self):
3541 """Test relative alignability of FIT image subentries"""
3542 entry_args = {
3543 'test-id': TEXT_DATA,
3544 }
3545 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
3546 entry_args=entry_args)
3547 dtb = fdt.Fdt.FromData(data)
3548 dtb.Scan()
3549
3550 node = dtb.GetNode('/images/kernel')
3551 data = dtb.GetProps(node)["data"].bytes
3552 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
3553 expected = (tools.GetBytes(0, 0x20) + U_BOOT_SPL_DATA +
3554 tools.GetBytes(0, align_pad) + U_BOOT_DATA)
3555 self.assertEqual(expected, data)
3556
3557 node = dtb.GetNode('/images/fdt-1')
3558 data = dtb.GetProps(node)["data"].bytes
3559 expected = (U_BOOT_SPL_DTB_DATA + tools.GetBytes(0, 20) +
3560 tools.ToBytes(TEXT_DATA) + tools.GetBytes(0, 30) +
3561 U_BOOT_DTB_DATA)
3562 self.assertEqual(expected, data)
3563
3564 def testFitExtblobMissingOk(self):
3565 """Test a FIT with a missing external blob that is allowed"""
3566 with test_util.capture_sys_output() as (stdout, stderr):
3567 self._DoTestFile('168_fit_missing_blob.dts',
3568 allow_missing=True)
3569 err = stderr.getvalue()
Simon Glassb2381432020-09-06 10:39:09 -06003570 self.assertRegex(err, "Image 'main-section'.*missing.*: atf-bl31")
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03003571
Simon Glass3decfa32020-09-01 05:13:54 -06003572 def testBlobNamedByArgMissing(self):
3573 """Test handling of a missing entry arg"""
3574 with self.assertRaises(ValueError) as e:
3575 self._DoReadFile('068_blob_named_by_arg.dts')
3576 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
3577 str(e.exception))
3578
Simon Glassdc2f81a2020-09-01 05:13:58 -06003579 def testPackBl31(self):
3580 """Test that an image with an ATF BL31 binary can be created"""
3581 data = self._DoReadFile('169_atf_bl31.dts')
3582 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
3583
Samuel Holland18bd4552020-10-21 21:12:15 -05003584 def testPackScp(self):
3585 """Test that an image with an SCP binary can be created"""
3586 data = self._DoReadFile('172_scp.dts')
3587 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
3588
Simon Glass6cf99532020-09-01 05:13:59 -06003589 def testFitFdt(self):
3590 """Test an image with an FIT with multiple FDT images"""
3591 def _CheckFdt(seq, expected_data):
3592 """Check the FDT nodes
3593
3594 Args:
3595 seq: Sequence number to check (0 or 1)
3596 expected_data: Expected contents of 'data' property
3597 """
3598 name = 'fdt-%d' % seq
3599 fnode = dtb.GetNode('/images/%s' % name)
3600 self.assertIsNotNone(fnode)
3601 self.assertEqual({'description','type', 'compression', 'data'},
3602 set(fnode.props.keys()))
3603 self.assertEqual(expected_data, fnode.props['data'].bytes)
3604 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
3605 fnode.props['description'].value)
3606
3607 def _CheckConfig(seq, expected_data):
3608 """Check the configuration nodes
3609
3610 Args:
3611 seq: Sequence number to check (0 or 1)
3612 expected_data: Expected contents of 'data' property
3613 """
3614 cnode = dtb.GetNode('/configurations')
3615 self.assertIn('default', cnode.props)
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003616 self.assertEqual('config-2', cnode.props['default'].value)
Simon Glass6cf99532020-09-01 05:13:59 -06003617
3618 name = 'config-%d' % seq
3619 fnode = dtb.GetNode('/configurations/%s' % name)
3620 self.assertIsNotNone(fnode)
3621 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
3622 set(fnode.props.keys()))
3623 self.assertEqual('conf-test-fdt%d.dtb' % seq,
3624 fnode.props['description'].value)
3625 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
3626
3627 entry_args = {
3628 'of-list': 'test-fdt1 test-fdt2',
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003629 'default-dt': 'test-fdt2',
Simon Glass6cf99532020-09-01 05:13:59 -06003630 }
3631 data = self._DoReadFileDtb(
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003632 '172_fit_fdt.dts',
Simon Glass6cf99532020-09-01 05:13:59 -06003633 entry_args=entry_args,
3634 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3635 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3636 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3637
3638 dtb = fdt.Fdt.FromData(fit_data)
3639 dtb.Scan()
3640 fnode = dtb.GetNode('/images/kernel')
3641 self.assertIn('data', fnode.props)
3642
3643 # Check all the properties in fdt-1 and fdt-2
3644 _CheckFdt(1, TEST_FDT1_DATA)
3645 _CheckFdt(2, TEST_FDT2_DATA)
3646
3647 # Check configurations
3648 _CheckConfig(1, TEST_FDT1_DATA)
3649 _CheckConfig(2, TEST_FDT2_DATA)
3650
3651 def testFitFdtMissingList(self):
3652 """Test handling of a missing 'of-list' entry arg"""
3653 with self.assertRaises(ValueError) as e:
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003654 self._DoReadFile('172_fit_fdt.dts')
Simon Glass6cf99532020-09-01 05:13:59 -06003655 self.assertIn("Generator node requires 'of-list' entry argument",
3656 str(e.exception))
3657
3658 def testFitFdtEmptyList(self):
3659 """Test handling of an empty 'of-list' entry arg"""
3660 entry_args = {
3661 'of-list': '',
3662 }
3663 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
3664
3665 def testFitFdtMissingProp(self):
3666 """Test handling of a missing 'fit,fdt-list' property"""
3667 with self.assertRaises(ValueError) as e:
3668 self._DoReadFile('171_fit_fdt_missing_prop.dts')
3669 self.assertIn("Generator node requires 'fit,fdt-list' property",
3670 str(e.exception))
Simon Glassdc2f81a2020-09-01 05:13:58 -06003671
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003672 def testFitFdtEmptyList(self):
3673 """Test handling of an empty 'of-list' entry arg"""
3674 entry_args = {
3675 'of-list': '',
3676 }
3677 data = self._DoReadFileDtb('172_fit_fdt.dts', entry_args=entry_args)[0]
3678
3679 def testFitFdtMissing(self):
3680 """Test handling of a missing 'default-dt' entry arg"""
3681 entry_args = {
3682 'of-list': 'test-fdt1 test-fdt2',
3683 }
3684 with self.assertRaises(ValueError) as e:
3685 self._DoReadFileDtb(
3686 '172_fit_fdt.dts',
3687 entry_args=entry_args,
3688 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3689 self.assertIn("Generated 'default' node requires default-dt entry argument",
3690 str(e.exception))
3691
3692 def testFitFdtNotInList(self):
3693 """Test handling of a default-dt that is not in the of-list"""
3694 entry_args = {
3695 'of-list': 'test-fdt1 test-fdt2',
3696 'default-dt': 'test-fdt3',
3697 }
3698 with self.assertRaises(ValueError) as e:
3699 self._DoReadFileDtb(
3700 '172_fit_fdt.dts',
3701 entry_args=entry_args,
3702 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3703 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
3704 str(e.exception))
3705
Simon Glassb2381432020-09-06 10:39:09 -06003706 def testFitExtblobMissingHelp(self):
3707 """Test display of help messages when an external blob is missing"""
3708 control.missing_blob_help = control._ReadMissingBlobHelp()
3709 control.missing_blob_help['wibble'] = 'Wibble test'
3710 control.missing_blob_help['another'] = 'Another test'
3711 with test_util.capture_sys_output() as (stdout, stderr):
3712 self._DoTestFile('168_fit_missing_blob.dts',
3713 allow_missing=True)
3714 err = stderr.getvalue()
3715
3716 # We can get the tag from the name, the type or the missing-msg
3717 # property. Check all three.
3718 self.assertIn('You may need to build ARM Trusted', err)
3719 self.assertIn('Wibble test', err)
3720 self.assertIn('Another test', err)
3721
Simon Glass204aa782020-09-06 10:35:32 -06003722 def testMissingBlob(self):
3723 """Test handling of a blob containing a missing file"""
3724 with self.assertRaises(ValueError) as e:
3725 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
3726 self.assertIn("Filename 'missing' not found in input path",
3727 str(e.exception))
3728
Simon Glassfb91d562020-09-06 10:35:33 -06003729 def testEnvironment(self):
3730 """Test adding a U-Boot environment"""
3731 data = self._DoReadFile('174_env.dts')
3732 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3733 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3734 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3735 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
3736 env)
3737
3738 def testEnvironmentNoSize(self):
3739 """Test that a missing 'size' property is detected"""
3740 with self.assertRaises(ValueError) as e:
Simon Glassa4dfe3e2020-10-26 17:40:00 -06003741 self._DoTestFile('175_env_no_size.dts')
Simon Glassfb91d562020-09-06 10:35:33 -06003742 self.assertIn("'u-boot-env' entry must have a size property",
3743 str(e.exception))
3744
3745 def testEnvironmentTooSmall(self):
3746 """Test handling of an environment that does not fit"""
3747 with self.assertRaises(ValueError) as e:
Simon Glassa4dfe3e2020-10-26 17:40:00 -06003748 self._DoTestFile('176_env_too_small.dts')
Simon Glassfb91d562020-09-06 10:35:33 -06003749
3750 # checksum, start byte, environment with \0 terminator, final \0
3751 need = 4 + 1 + len(ENV_DATA) + 1 + 1
3752 short = need - 0x8
3753 self.assertIn("too small to hold data (need %#x more bytes)" % short,
3754 str(e.exception))
3755
Simon Glassf2c0dd82020-10-26 17:40:01 -06003756 def testSkipAtStart(self):
3757 """Test handling of skip-at-start section"""
3758 data = self._DoReadFile('177_skip_at_start.dts')
3759 self.assertEqual(U_BOOT_DATA, data)
3760
3761 image = control.images['image']
3762 entries = image.GetEntries()
3763 section = entries['section']
3764 self.assertEqual(0, section.offset)
3765 self.assertEqual(len(U_BOOT_DATA), section.size)
3766 self.assertEqual(U_BOOT_DATA, section.GetData())
3767
3768 entry = section.GetEntries()['u-boot']
3769 self.assertEqual(16, entry.offset)
3770 self.assertEqual(len(U_BOOT_DATA), entry.size)
3771 self.assertEqual(U_BOOT_DATA, entry.data)
3772
3773 def testSkipAtStartPad(self):
3774 """Test handling of skip-at-start section with padded entry"""
3775 data = self._DoReadFile('178_skip_at_start_pad.dts')
3776 before = tools.GetBytes(0, 8)
3777 after = tools.GetBytes(0, 4)
3778 all = before + U_BOOT_DATA + after
3779 self.assertEqual(all, data)
3780
3781 image = control.images['image']
3782 entries = image.GetEntries()
3783 section = entries['section']
3784 self.assertEqual(0, section.offset)
3785 self.assertEqual(len(all), section.size)
3786 self.assertEqual(all, section.GetData())
3787
3788 entry = section.GetEntries()['u-boot']
3789 self.assertEqual(16, entry.offset)
3790 self.assertEqual(len(all), entry.size)
3791 self.assertEqual(U_BOOT_DATA, entry.data)
3792
3793 def testSkipAtStartSectionPad(self):
3794 """Test handling of skip-at-start section with padding"""
3795 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
3796 before = tools.GetBytes(0, 8)
3797 after = tools.GetBytes(0, 4)
3798 all = before + U_BOOT_DATA + after
3799
3800 # This is not correct, but it is what binman currently produces
3801 self.assertEqual(tools.GetBytes(0, 16) + U_BOOT_DATA + after, data)
3802
3803 image = control.images['image']
3804 entries = image.GetEntries()
3805 section = entries['section']
3806 self.assertEqual(0, section.offset)
3807 self.assertEqual(len(all), section.size)
3808 self.assertIsNone(section.data)
3809 self.assertEqual(all, section.GetData())
3810
3811 entry = section.GetEntries()['u-boot']
3812 self.assertEqual(16, entry.offset)
3813 self.assertEqual(len(U_BOOT_DATA), entry.size)
3814 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassfb91d562020-09-06 10:35:33 -06003815
Simon Glass9fc60b42017-11-12 21:52:22 -07003816if __name__ == "__main__":
3817 unittest.main()