blob: 5383eec489a278e817843609136005cbabc689a0 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001# SPDX-License-Identifier: GPL-2.0+
Simon Glass4f443042016-11-25 20:15:52 -07002# Copyright (c) 2016 Google, Inc
3# Written by Simon Glass <sjg@chromium.org>
4#
Simon Glass4f443042016-11-25 20:15:52 -07005# To run a single test, change to this directory, and:
6#
7# python -m unittest func_test.TestFunctional.testHelp
8
Simon Glassfdc34362020-07-09 18:39:45 -06009import collections
Simon Glass16287932020-04-17 18:09:03 -060010import gzip
Simon Glasse0e5df92018-09-14 04:57:31 -060011import hashlib
Simon Glass4f443042016-11-25 20:15:52 -070012from optparse import OptionParser
13import os
Simon Glassfdc34362020-07-09 18:39:45 -060014import re
Simon Glass4f443042016-11-25 20:15:52 -070015import shutil
16import struct
17import sys
18import tempfile
19import unittest
20
Simon Glass16287932020-04-17 18:09:03 -060021from binman import cbfs_util
22from binman import cmdline
23from binman import control
24from binman import elf
25from binman import elf_test
26from binman import fmap_util
Simon Glass16287932020-04-17 18:09:03 -060027from binman import state
28from dtoc import fdt
29from dtoc import fdt_util
30from binman.etype import fdtmap
31from binman.etype import image_header
Simon Glass07237982020-08-05 13:27:47 -060032from binman.image import Image
Simon Glassbf776672020-04-17 18:09:04 -060033from patman import command
34from patman import test_util
35from patman import tools
36from patman import tout
Simon Glass4f443042016-11-25 20:15:52 -070037
38# Contents of test files, corresponding to different entry types
Simon Glassc6c10e72019-05-17 22:00:46 -060039U_BOOT_DATA = b'1234'
40U_BOOT_IMG_DATA = b'img'
Simon Glasseb0086f2019-08-24 07:23:04 -060041U_BOOT_SPL_DATA = b'56780123456789abcdefghi'
42U_BOOT_TPL_DATA = b'tpl9876543210fedcbazyw'
Simon Glassc6c10e72019-05-17 22:00:46 -060043BLOB_DATA = b'89'
44ME_DATA = b'0abcd'
45VGA_DATA = b'vga'
46U_BOOT_DTB_DATA = b'udtb'
47U_BOOT_SPL_DTB_DATA = b'spldtb'
48U_BOOT_TPL_DTB_DATA = b'tpldtb'
49X86_START16_DATA = b'start16'
50X86_START16_SPL_DATA = b'start16spl'
51X86_START16_TPL_DATA = b'start16tpl'
Simon Glass2250ee62019-08-24 07:22:48 -060052X86_RESET16_DATA = b'reset16'
53X86_RESET16_SPL_DATA = b'reset16spl'
54X86_RESET16_TPL_DATA = b'reset16tpl'
Simon Glassc6c10e72019-05-17 22:00:46 -060055PPC_MPC85XX_BR_DATA = b'ppcmpc85xxbr'
56U_BOOT_NODTB_DATA = b'nodtb with microcode pointer somewhere in here'
57U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here'
58U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here'
59FSP_DATA = b'fsp'
60CMC_DATA = b'cmc'
61VBT_DATA = b'vbt'
62MRC_DATA = b'mrc'
Simon Glassbb748372018-07-17 13:25:33 -060063TEXT_DATA = 'text'
64TEXT_DATA2 = 'text2'
65TEXT_DATA3 = 'text3'
Simon Glassc6c10e72019-05-17 22:00:46 -060066CROS_EC_RW_DATA = b'ecrw'
67GBB_DATA = b'gbbd'
68BMPBLK_DATA = b'bmp'
69VBLOCK_DATA = b'vblk'
70FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
71 b"sorry you're alive\n")
Simon Glassff5c7e32019-07-08 13:18:42 -060072COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
Simon Glass8f5ef892020-10-26 17:40:25 -060073COMPRESS_DATA_BIG = COMPRESS_DATA * 2
Simon Glassc6c10e72019-05-17 22:00:46 -060074REFCODE_DATA = b'refcode'
Simon Glassea0fff92019-08-24 07:23:07 -060075FSP_M_DATA = b'fsp_m'
Simon Glassbc6a88f2019-10-20 21:31:35 -060076FSP_S_DATA = b'fsp_s'
Simon Glass998d1482019-10-20 21:31:36 -060077FSP_T_DATA = b'fsp_t'
Simon Glassdc2f81a2020-09-01 05:13:58 -060078ATF_BL31_DATA = b'bl31'
Bin Meng4c4d6072021-05-10 20:23:33 +080079OPENSBI_DATA = b'opensbi'
Samuel Holland18bd4552020-10-21 21:12:15 -050080SCP_DATA = b'scp'
Simon Glass6cf99532020-09-01 05:13:59 -060081TEST_FDT1_DATA = b'fdt1'
82TEST_FDT2_DATA = b'test-fdt2'
Simon Glassfb91d562020-09-06 10:35:33 -060083ENV_DATA = b'var1=1\nvar2="2"'
Simon Glass6cf99532020-09-01 05:13:59 -060084
85# Subdirectory of the input dir to use to put test FDTs
86TEST_FDT_SUBDIR = 'fdts'
Simon Glassec127af2018-07-17 13:25:39 -060087
Simon Glass6ccbfcd2019-07-20 12:23:47 -060088# The expected size for the device tree in some tests
Simon Glassf667e452019-07-08 14:25:50 -060089EXTRACT_DTB_SIZE = 0x3c9
90
Simon Glass6ccbfcd2019-07-20 12:23:47 -060091# Properties expected to be in the device tree when update_dtb is used
92BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
93
Simon Glass12bb1a92019-07-20 12:23:51 -060094# Extra properties expected to be in the device tree when allow-repack is used
95REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
96
Simon Glass4f443042016-11-25 20:15:52 -070097
98class TestFunctional(unittest.TestCase):
99 """Functional tests for binman
100
101 Most of these use a sample .dts file to build an image and then check
102 that it looks correct. The sample files are in the test/ subdirectory
103 and are numbered.
104
105 For each entry type a very small test file is created using fixed
106 string contents. This makes it easy to test that things look right, and
107 debug problems.
108
109 In some cases a 'real' file must be used - these are also supplied in
110 the test/ diurectory.
111 """
112 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600113 def setUpClass(cls):
Simon Glass4d5994f2017-11-12 21:52:20 -0700114 global entry
Simon Glass16287932020-04-17 18:09:03 -0600115 from binman import entry
Simon Glass4d5994f2017-11-12 21:52:20 -0700116
Simon Glass4f443042016-11-25 20:15:52 -0700117 # Handle the case where argv[0] is 'python'
Simon Glassb986b3b2019-08-24 07:22:43 -0600118 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
119 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
Simon Glass4f443042016-11-25 20:15:52 -0700120
121 # Create a temporary directory for input files
Simon Glassb986b3b2019-08-24 07:22:43 -0600122 cls._indir = tempfile.mkdtemp(prefix='binmant.')
Simon Glass4f443042016-11-25 20:15:52 -0700123
124 # Create some test files
125 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
126 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
127 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glassb8ef5b62018-07-17 13:25:48 -0600128 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700129 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -0700130 TestFunctional._MakeInputFile('me.bin', ME_DATA)
131 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glassb986b3b2019-08-24 07:22:43 -0600132 cls._ResetDtbs()
Simon Glass2250ee62019-08-24 07:22:48 -0600133
Jagdish Gediya9d368f32018-09-03 21:35:08 +0530134 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glass2250ee62019-08-24 07:22:48 -0600135
Simon Glass5e239182019-08-24 07:22:49 -0600136 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
137 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
Simon Glass87722132017-11-12 21:52:26 -0700138 X86_START16_SPL_DATA)
Simon Glass5e239182019-08-24 07:22:49 -0600139 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
Simon Glass35b384c2018-09-14 04:57:10 -0600140 X86_START16_TPL_DATA)
Simon Glass2250ee62019-08-24 07:22:48 -0600141
142 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
143 X86_RESET16_DATA)
144 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
145 X86_RESET16_SPL_DATA)
146 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
147 X86_RESET16_TPL_DATA)
148
Simon Glass4f443042016-11-25 20:15:52 -0700149 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass6b187df2017-11-12 21:52:27 -0700150 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
151 U_BOOT_SPL_NODTB_DATA)
Simon Glassf0253632018-09-14 04:57:32 -0600152 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
153 U_BOOT_TPL_NODTB_DATA)
Simon Glassda229092016-11-25 20:15:56 -0700154 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
155 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Meng59ea8c22017-08-15 22:41:54 -0700156 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassca4f4ff2017-11-12 21:52:28 -0700157 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassec127af2018-07-17 13:25:39 -0600158 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glass0ef87aa2018-07-17 13:25:44 -0600159 TestFunctional._MakeInputDir('devkeys')
160 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass3ae192c2018-10-01 12:22:31 -0600161 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glassea0fff92019-08-24 07:23:07 -0600162 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
Simon Glassbc6a88f2019-10-20 21:31:35 -0600163 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
Simon Glass998d1482019-10-20 21:31:36 -0600164 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700165
Simon Glass53e22bf2019-08-24 07:22:53 -0600166 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
167 elf_test.BuildElfTestFiles(cls._elf_testdir)
168
Simon Glasse0ff8552016-11-25 20:15:53 -0700169 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glassf514d8f2019-08-24 07:22:54 -0600170 TestFunctional._MakeInputFile('u-boot',
171 tools.ReadFile(cls.ElfTestFile('u_boot_ucode_ptr')))
Simon Glasse0ff8552016-11-25 20:15:53 -0700172
173 # Intel flash descriptor file
Simon Glass0ba4b3d2020-07-09 18:39:41 -0600174 cls._SetupDescriptor()
Simon Glasse0ff8552016-11-25 20:15:53 -0700175
Simon Glassb986b3b2019-08-24 07:22:43 -0600176 shutil.copytree(cls.TestFile('files'),
177 os.path.join(cls._indir, 'files'))
Simon Glass0a98b282018-09-14 04:57:28 -0600178
Simon Glass83d73c22018-09-14 04:57:26 -0600179 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
Simon Glass8f5ef892020-10-26 17:40:25 -0600180 TestFunctional._MakeInputFile('compress_big', COMPRESS_DATA_BIG)
Simon Glassdc2f81a2020-09-01 05:13:58 -0600181 TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
Bin Meng4c4d6072021-05-10 20:23:33 +0800182 TestFunctional._MakeInputFile('fw_dynamic.bin', OPENSBI_DATA)
Samuel Holland18bd4552020-10-21 21:12:15 -0500183 TestFunctional._MakeInputFile('scp.bin', SCP_DATA)
Simon Glass83d73c22018-09-14 04:57:26 -0600184
Simon Glass6cf99532020-09-01 05:13:59 -0600185 # Add a few .dtb files for testing
186 TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR,
187 TEST_FDT1_DATA)
188 TestFunctional._MakeInputFile('%s/test-fdt2.dtb' % TEST_FDT_SUBDIR,
189 TEST_FDT2_DATA)
190
Simon Glassfb91d562020-09-06 10:35:33 -0600191 TestFunctional._MakeInputFile('env.txt', ENV_DATA)
192
Simon Glassac62fba2019-07-08 13:18:53 -0600193 # Travis-CI may have an old lz4
Simon Glassb986b3b2019-08-24 07:22:43 -0600194 cls.have_lz4 = True
Simon Glassac62fba2019-07-08 13:18:53 -0600195 try:
196 tools.Run('lz4', '--no-frame-crc', '-c',
Simon Glass3b3e3c02019-10-31 07:42:50 -0600197 os.path.join(cls._indir, 'u-boot.bin'), binary=True)
Simon Glassac62fba2019-07-08 13:18:53 -0600198 except:
Simon Glassb986b3b2019-08-24 07:22:43 -0600199 cls.have_lz4 = False
Simon Glassac62fba2019-07-08 13:18:53 -0600200
Simon Glass4f443042016-11-25 20:15:52 -0700201 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600202 def tearDownClass(cls):
Simon Glass4f443042016-11-25 20:15:52 -0700203 """Remove the temporary input directory and its contents"""
Simon Glassb986b3b2019-08-24 07:22:43 -0600204 if cls.preserve_indir:
205 print('Preserving input dir: %s' % cls._indir)
Simon Glassd5164a72019-07-08 13:18:49 -0600206 else:
Simon Glassb986b3b2019-08-24 07:22:43 -0600207 if cls._indir:
208 shutil.rmtree(cls._indir)
209 cls._indir = None
Simon Glass4f443042016-11-25 20:15:52 -0700210
Simon Glassd5164a72019-07-08 13:18:49 -0600211 @classmethod
Simon Glass8acce602019-07-08 13:18:50 -0600212 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
Simon Glass53cd5d92019-07-08 14:25:29 -0600213 toolpath=None, verbosity=None):
Simon Glassd5164a72019-07-08 13:18:49 -0600214 """Accept arguments controlling test execution
215
216 Args:
217 preserve_indir: Preserve the shared input directory used by all
218 tests in this class.
219 preserve_outdir: Preserve the output directories used by tests. Each
220 test has its own, so this is normally only useful when running a
221 single test.
Simon Glass8acce602019-07-08 13:18:50 -0600222 toolpath: ist of paths to use for tools
Simon Glassd5164a72019-07-08 13:18:49 -0600223 """
224 cls.preserve_indir = preserve_indir
225 cls.preserve_outdirs = preserve_outdirs
Simon Glass8acce602019-07-08 13:18:50 -0600226 cls.toolpath = toolpath
Simon Glass53cd5d92019-07-08 14:25:29 -0600227 cls.verbosity = verbosity
Simon Glassd5164a72019-07-08 13:18:49 -0600228
Simon Glassac62fba2019-07-08 13:18:53 -0600229 def _CheckLz4(self):
230 if not self.have_lz4:
231 self.skipTest('lz4 --no-frame-crc not available')
232
Simon Glassbf574f12019-07-20 12:24:09 -0600233 def _CleanupOutputDir(self):
234 """Remove the temporary output directory"""
235 if self.preserve_outdirs:
236 print('Preserving output dir: %s' % tools.outdir)
237 else:
238 tools._FinaliseForTest()
239
Simon Glass4f443042016-11-25 20:15:52 -0700240 def setUp(self):
241 # Enable this to turn on debugging output
242 # tout.Init(tout.DEBUG)
243 command.test_result = None
244
245 def tearDown(self):
246 """Remove the temporary output directory"""
Simon Glassbf574f12019-07-20 12:24:09 -0600247 self._CleanupOutputDir()
Simon Glass4f443042016-11-25 20:15:52 -0700248
Simon Glassf86a7362019-07-20 12:24:10 -0600249 def _SetupImageInTmpdir(self):
250 """Set up the output image in a new temporary directory
251
252 This is used when an image has been generated in the output directory,
253 but we want to run binman again. This will create a new output
254 directory and fail to delete the original one.
255
256 This creates a new temporary directory, copies the image to it (with a
257 new name) and removes the old output directory.
258
259 Returns:
260 Tuple:
261 Temporary directory to use
262 New image filename
263 """
264 image_fname = tools.GetOutputFilename('image.bin')
265 tmpdir = tempfile.mkdtemp(prefix='binman.')
266 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
267 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
268 self._CleanupOutputDir()
269 return tmpdir, updated_fname
270
Simon Glassb8ef5b62018-07-17 13:25:48 -0600271 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600272 def _ResetDtbs(cls):
Simon Glassb8ef5b62018-07-17 13:25:48 -0600273 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
274 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
275 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
276
Simon Glass4f443042016-11-25 20:15:52 -0700277 def _RunBinman(self, *args, **kwargs):
278 """Run binman using the command line
279
280 Args:
281 Arguments to pass, as a list of strings
282 kwargs: Arguments to pass to Command.RunPipe()
283 """
284 result = command.RunPipe([[self._binman_pathname] + list(args)],
285 capture=True, capture_stderr=True, raise_on_error=False)
286 if result.return_code and kwargs.get('raise_on_error', True):
287 raise Exception("Error running '%s': %s" % (' '.join(args),
288 result.stdout + result.stderr))
289 return result
290
Simon Glass53cd5d92019-07-08 14:25:29 -0600291 def _DoBinman(self, *argv):
Simon Glass4f443042016-11-25 20:15:52 -0700292 """Run binman using directly (in the same process)
293
294 Args:
295 Arguments to pass, as a list of strings
296 Returns:
297 Return value (0 for success)
298 """
Simon Glass53cd5d92019-07-08 14:25:29 -0600299 argv = list(argv)
300 args = cmdline.ParseArgs(argv)
301 args.pager = 'binman-invalid-pager'
302 args.build_dir = self._indir
Simon Glass4f443042016-11-25 20:15:52 -0700303
304 # For testing, you can force an increase in verbosity here
Simon Glass53cd5d92019-07-08 14:25:29 -0600305 # args.verbosity = tout.DEBUG
306 return control.Binman(args)
Simon Glass4f443042016-11-25 20:15:52 -0700307
Simon Glass53af22a2018-07-17 13:25:32 -0600308 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glasseb833d82019-04-25 21:58:34 -0600309 entry_args=None, images=None, use_real_dtb=False,
Simon Glass63aeaeb2021-03-18 20:25:05 +1300310 use_expanded=False, verbosity=None, allow_missing=False,
311 extra_indirs=None):
Simon Glass4f443042016-11-25 20:15:52 -0700312 """Run binman with a given test file
313
314 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600315 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600316 debug: True to enable debugging output
Simon Glass3b0c3822018-06-01 09:38:20 -0600317 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600318 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600319 tree before packing it into the image
Simon Glass0bfa7b02018-09-14 04:57:12 -0600320 entry_args: Dict of entry args to supply to binman
321 key: arg name
322 value: value of that arg
323 images: List of image names to build
Simon Glasse9d336d2020-09-01 05:13:55 -0600324 use_real_dtb: True to use the test file as the contents of
325 the u-boot-dtb entry. Normally this is not needed and the
326 test contents (the U_BOOT_DTB_DATA string) can be used.
327 But in some test we need the real contents.
Simon Glass63aeaeb2021-03-18 20:25:05 +1300328 use_expanded: True to use expanded entries where available, e.g.
329 'u-boot-expanded' instead of 'u-boot'
Simon Glasse9d336d2020-09-01 05:13:55 -0600330 verbosity: Verbosity level to use (0-3, None=don't set it)
331 allow_missing: Set the '--allow-missing' flag so that missing
332 external binaries just produce a warning instead of an error
Simon Glass6cf99532020-09-01 05:13:59 -0600333 extra_indirs: Extra input directories to add using -I
Simon Glass4f443042016-11-25 20:15:52 -0700334 """
Simon Glass53cd5d92019-07-08 14:25:29 -0600335 args = []
Simon Glass7fe91732017-11-13 18:55:00 -0700336 if debug:
337 args.append('-D')
Simon Glass53cd5d92019-07-08 14:25:29 -0600338 if verbosity is not None:
339 args.append('-v%d' % verbosity)
340 elif self.verbosity:
341 args.append('-v%d' % self.verbosity)
342 if self.toolpath:
343 for path in self.toolpath:
344 args += ['--toolpath', path]
345 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass3b0c3822018-06-01 09:38:20 -0600346 if map:
347 args.append('-m')
Simon Glass16b8d6b2018-07-06 10:27:42 -0600348 if update_dtb:
Simon Glass2569e102019-07-08 13:18:47 -0600349 args.append('-u')
Simon Glass93d17412018-09-14 04:57:23 -0600350 if not use_real_dtb:
351 args.append('--fake-dtb')
Simon Glass63aeaeb2021-03-18 20:25:05 +1300352 if not use_expanded:
353 args.append('--no-expanded')
Simon Glass53af22a2018-07-17 13:25:32 -0600354 if entry_args:
Simon Glass50979152019-05-14 15:53:41 -0600355 for arg, value in entry_args.items():
Simon Glass53af22a2018-07-17 13:25:32 -0600356 args.append('-a%s=%s' % (arg, value))
Simon Glass4f9f1052020-07-09 18:39:38 -0600357 if allow_missing:
358 args.append('-M')
Simon Glass0bfa7b02018-09-14 04:57:12 -0600359 if images:
360 for image in images:
361 args += ['-i', image]
Simon Glass6cf99532020-09-01 05:13:59 -0600362 if extra_indirs:
363 for indir in extra_indirs:
364 args += ['-I', indir]
Simon Glass7fe91732017-11-13 18:55:00 -0700365 return self._DoBinman(*args)
Simon Glass4f443042016-11-25 20:15:52 -0700366
367 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glasse0ff8552016-11-25 20:15:53 -0700368 """Set up a new test device-tree file
369
370 The given file is compiled and set up as the device tree to be used
371 for ths test.
372
373 Args:
374 fname: Filename of .dts file to read
Simon Glass7ae5f312018-06-01 09:38:19 -0600375 outfile: Output filename for compiled device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700376
377 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600378 Contents of device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700379 """
Simon Glassa004f292019-07-20 12:23:49 -0600380 tmpdir = tempfile.mkdtemp(prefix='binmant.')
381 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
Simon Glass1d0ebf72019-05-14 15:53:42 -0600382 with open(dtb, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700383 data = fd.read()
384 TestFunctional._MakeInputFile(outfile, data)
Simon Glassa004f292019-07-20 12:23:49 -0600385 shutil.rmtree(tmpdir)
Simon Glasse0e62752018-10-01 21:12:41 -0600386 return data
Simon Glass4f443042016-11-25 20:15:52 -0700387
Simon Glass6ed45ba2018-09-14 04:57:24 -0600388 def _GetDtbContentsForSplTpl(self, dtb_data, name):
389 """Create a version of the main DTB for SPL or SPL
390
391 For testing we don't actually have different versions of the DTB. With
392 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
393 we don't normally have any unwanted nodes.
394
395 We still want the DTBs for SPL and TPL to be different though, since
396 otherwise it is confusing to know which one we are looking at. So add
397 an 'spl' or 'tpl' property to the top-level node.
Simon Glasse9d336d2020-09-01 05:13:55 -0600398
399 Args:
400 dtb_data: dtb data to modify (this should be a value devicetree)
401 name: Name of a new property to add
402
403 Returns:
404 New dtb data with the property added
Simon Glass6ed45ba2018-09-14 04:57:24 -0600405 """
406 dtb = fdt.Fdt.FromData(dtb_data)
407 dtb.Scan()
408 dtb.GetNode('/binman').AddZeroProp(name)
409 dtb.Sync(auto_resize=True)
410 dtb.Pack()
411 return dtb.GetContents()
412
Simon Glass63aeaeb2021-03-18 20:25:05 +1300413 def _DoReadFileDtb(self, fname, use_real_dtb=False, use_expanded=False,
414 map=False, update_dtb=False, entry_args=None,
415 reset_dtbs=True, extra_indirs=None):
Simon Glass4f443042016-11-25 20:15:52 -0700416 """Run binman and return the resulting image
417
418 This runs binman with a given test file and then reads the resulting
419 output file. It is a shortcut function since most tests need to do
420 these steps.
421
422 Raises an assertion failure if binman returns a non-zero exit code.
423
424 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600425 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass4f443042016-11-25 20:15:52 -0700426 use_real_dtb: True to use the test file as the contents of
427 the u-boot-dtb entry. Normally this is not needed and the
428 test contents (the U_BOOT_DTB_DATA string) can be used.
429 But in some test we need the real contents.
Simon Glass63aeaeb2021-03-18 20:25:05 +1300430 use_expanded: True to use expanded entries where available, e.g.
431 'u-boot-expanded' instead of 'u-boot'
Simon Glass3b0c3822018-06-01 09:38:20 -0600432 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600433 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600434 tree before packing it into the image
Simon Glasse9d336d2020-09-01 05:13:55 -0600435 entry_args: Dict of entry args to supply to binman
436 key: arg name
437 value: value of that arg
438 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
439 function. If reset_dtbs is True, then the original test dtb
440 is written back before this function finishes
Simon Glass6cf99532020-09-01 05:13:59 -0600441 extra_indirs: Extra input directories to add using -I
Simon Glasse0ff8552016-11-25 20:15:53 -0700442
443 Returns:
444 Tuple:
445 Resulting image contents
446 Device tree contents
Simon Glass3b0c3822018-06-01 09:38:20 -0600447 Map data showing contents of image (or None if none)
Simon Glassea6922e2018-07-17 13:25:27 -0600448 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass4f443042016-11-25 20:15:52 -0700449 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700450 dtb_data = None
Simon Glass4f443042016-11-25 20:15:52 -0700451 # Use the compiled test file as the u-boot-dtb input
452 if use_real_dtb:
Simon Glasse0ff8552016-11-25 20:15:53 -0700453 dtb_data = self._SetupDtb(fname)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600454
455 # For testing purposes, make a copy of the DT for SPL and TPL. Add
456 # a node indicating which it is, so aid verification.
457 for name in ['spl', 'tpl']:
458 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
459 outfile = os.path.join(self._indir, dtb_fname)
460 TestFunctional._MakeInputFile(dtb_fname,
461 self._GetDtbContentsForSplTpl(dtb_data, name))
Simon Glass4f443042016-11-25 20:15:52 -0700462
463 try:
Simon Glass53af22a2018-07-17 13:25:32 -0600464 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glass6cf99532020-09-01 05:13:59 -0600465 entry_args=entry_args, use_real_dtb=use_real_dtb,
Simon Glass63aeaeb2021-03-18 20:25:05 +1300466 use_expanded=use_expanded, extra_indirs=extra_indirs)
Simon Glass4f443042016-11-25 20:15:52 -0700467 self.assertEqual(0, retcode)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600468 out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
Simon Glass4f443042016-11-25 20:15:52 -0700469
470 # Find the (only) image, read it and return its contents
471 image = control.images['image']
Simon Glass16b8d6b2018-07-06 10:27:42 -0600472 image_fname = tools.GetOutputFilename('image.bin')
473 self.assertTrue(os.path.exists(image_fname))
Simon Glass3b0c3822018-06-01 09:38:20 -0600474 if map:
475 map_fname = tools.GetOutputFilename('image.map')
476 with open(map_fname) as fd:
477 map_data = fd.read()
478 else:
479 map_data = None
Simon Glass1d0ebf72019-05-14 15:53:42 -0600480 with open(image_fname, 'rb') as fd:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600481 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass4f443042016-11-25 20:15:52 -0700482 finally:
483 # Put the test file back
Simon Glass6ed45ba2018-09-14 04:57:24 -0600484 if reset_dtbs and use_real_dtb:
Simon Glassb8ef5b62018-07-17 13:25:48 -0600485 self._ResetDtbs()
Simon Glass4f443042016-11-25 20:15:52 -0700486
Simon Glass3c081312019-07-08 14:25:26 -0600487 def _DoReadFileRealDtb(self, fname):
488 """Run binman with a real .dtb file and return the resulting data
489
490 Args:
491 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
492
493 Returns:
494 Resulting image contents
495 """
496 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
497
Simon Glasse0ff8552016-11-25 20:15:53 -0700498 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass7ae5f312018-06-01 09:38:19 -0600499 """Helper function which discards the device-tree binary
500
501 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600502 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600503 use_real_dtb: True to use the test file as the contents of
504 the u-boot-dtb entry. Normally this is not needed and the
505 test contents (the U_BOOT_DTB_DATA string) can be used.
506 But in some test we need the real contents.
Simon Glassea6922e2018-07-17 13:25:27 -0600507
508 Returns:
509 Resulting image contents
Simon Glass7ae5f312018-06-01 09:38:19 -0600510 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700511 return self._DoReadFileDtb(fname, use_real_dtb)[0]
512
Simon Glass4f443042016-11-25 20:15:52 -0700513 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600514 def _MakeInputFile(cls, fname, contents):
Simon Glass4f443042016-11-25 20:15:52 -0700515 """Create a new test input file, creating directories as needed
516
517 Args:
Simon Glass3ab95982018-08-01 15:22:37 -0600518 fname: Filename to create
Simon Glass4f443042016-11-25 20:15:52 -0700519 contents: File contents to write in to the file
520 Returns:
521 Full pathname of file created
522 """
Simon Glassb986b3b2019-08-24 07:22:43 -0600523 pathname = os.path.join(cls._indir, fname)
Simon Glass4f443042016-11-25 20:15:52 -0700524 dirname = os.path.dirname(pathname)
525 if dirname and not os.path.exists(dirname):
526 os.makedirs(dirname)
527 with open(pathname, 'wb') as fd:
528 fd.write(contents)
529 return pathname
530
531 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600532 def _MakeInputDir(cls, dirname):
Simon Glass0ef87aa2018-07-17 13:25:44 -0600533 """Create a new test input directory, creating directories as needed
534
535 Args:
536 dirname: Directory name to create
537
538 Returns:
539 Full pathname of directory created
540 """
Simon Glassb986b3b2019-08-24 07:22:43 -0600541 pathname = os.path.join(cls._indir, dirname)
Simon Glass0ef87aa2018-07-17 13:25:44 -0600542 if not os.path.exists(pathname):
543 os.makedirs(pathname)
544 return pathname
545
546 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600547 def _SetupSplElf(cls, src_fname='bss_data'):
Simon Glass11ae93e2018-10-01 21:12:47 -0600548 """Set up an ELF file with a '_dt_ucode_base_size' symbol
549
550 Args:
551 Filename of ELF file to use as SPL
552 """
Simon Glassc9a0b272019-08-24 07:22:59 -0600553 TestFunctional._MakeInputFile('spl/u-boot-spl',
554 tools.ReadFile(cls.ElfTestFile(src_fname)))
Simon Glass11ae93e2018-10-01 21:12:47 -0600555
556 @classmethod
Simon Glass2090f1e2019-08-24 07:23:00 -0600557 def _SetupTplElf(cls, src_fname='bss_data'):
558 """Set up an ELF file with a '_dt_ucode_base_size' symbol
559
560 Args:
561 Filename of ELF file to use as TPL
562 """
563 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
564 tools.ReadFile(cls.ElfTestFile(src_fname)))
565
566 @classmethod
Simon Glass0ba4b3d2020-07-09 18:39:41 -0600567 def _SetupDescriptor(cls):
568 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
569 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
570
571 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600572 def TestFile(cls, fname):
573 return os.path.join(cls._binman_dir, 'test', fname)
Simon Glass4f443042016-11-25 20:15:52 -0700574
Simon Glass53e22bf2019-08-24 07:22:53 -0600575 @classmethod
576 def ElfTestFile(cls, fname):
577 return os.path.join(cls._elf_testdir, fname)
578
Simon Glass4f443042016-11-25 20:15:52 -0700579 def AssertInList(self, grep_list, target):
580 """Assert that at least one of a list of things is in a target
581
582 Args:
583 grep_list: List of strings to check
584 target: Target string
585 """
586 for grep in grep_list:
587 if grep in target:
588 return
Simon Glass1fc62de2019-05-17 22:00:50 -0600589 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass4f443042016-11-25 20:15:52 -0700590
591 def CheckNoGaps(self, entries):
592 """Check that all entries fit together without gaps
593
594 Args:
595 entries: List of entries to check
596 """
Simon Glass3ab95982018-08-01 15:22:37 -0600597 offset = 0
Simon Glass4f443042016-11-25 20:15:52 -0700598 for entry in entries.values():
Simon Glass3ab95982018-08-01 15:22:37 -0600599 self.assertEqual(offset, entry.offset)
600 offset += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700601
Simon Glasse0ff8552016-11-25 20:15:53 -0700602 def GetFdtLen(self, dtb):
Simon Glass7ae5f312018-06-01 09:38:19 -0600603 """Get the totalsize field from a device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700604
605 Args:
Simon Glass7ae5f312018-06-01 09:38:19 -0600606 dtb: Device-tree binary contents
Simon Glasse0ff8552016-11-25 20:15:53 -0700607
608 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600609 Total size of device-tree binary, from the header
Simon Glasse0ff8552016-11-25 20:15:53 -0700610 """
611 return struct.unpack('>L', dtb[4:8])[0]
612
Simon Glass086cec92019-07-08 14:25:27 -0600613 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glass16b8d6b2018-07-06 10:27:42 -0600614 def AddNode(node, path):
615 if node.name != '/':
616 path += '/' + node.name
Simon Glass086cec92019-07-08 14:25:27 -0600617 for prop in node.props.values():
618 if prop.name in prop_names:
619 prop_path = path + ':' + prop.name
620 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
621 prop.value)
Simon Glass16b8d6b2018-07-06 10:27:42 -0600622 for subnode in node.subnodes:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600623 AddNode(subnode, path)
624
625 tree = {}
Simon Glass16b8d6b2018-07-06 10:27:42 -0600626 AddNode(dtb.GetRoot(), '')
627 return tree
628
Simon Glass4f443042016-11-25 20:15:52 -0700629 def testRun(self):
630 """Test a basic run with valid args"""
631 result = self._RunBinman('-h')
632
633 def testFullHelp(self):
634 """Test that the full help is displayed with -H"""
635 result = self._RunBinman('-H')
Simon Glass61adb2d2021-03-18 20:25:13 +1300636 help_file = os.path.join(self._binman_dir, 'README.rst')
Tom Rini3759df02018-01-16 15:29:50 -0500637 # Remove possible extraneous strings
638 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
639 gothelp = result.stdout.replace(extra, '')
640 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass4f443042016-11-25 20:15:52 -0700641 self.assertEqual(0, len(result.stderr))
642 self.assertEqual(0, result.return_code)
643
644 def testFullHelpInternal(self):
645 """Test that the full help is displayed with -H"""
646 try:
647 command.test_result = command.CommandResult()
648 result = self._DoBinman('-H')
Simon Glass61adb2d2021-03-18 20:25:13 +1300649 help_file = os.path.join(self._binman_dir, 'README.rst')
Simon Glass4f443042016-11-25 20:15:52 -0700650 finally:
651 command.test_result = None
652
653 def testHelp(self):
654 """Test that the basic help is displayed with -h"""
655 result = self._RunBinman('-h')
656 self.assertTrue(len(result.stdout) > 200)
657 self.assertEqual(0, len(result.stderr))
658 self.assertEqual(0, result.return_code)
659
Simon Glass4f443042016-11-25 20:15:52 -0700660 def testBoard(self):
661 """Test that we can run it with a specific board"""
Simon Glass741f2d62018-10-01 12:22:30 -0600662 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass4f443042016-11-25 20:15:52 -0700663 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glass63aeaeb2021-03-18 20:25:05 +1300664 result = self._DoBinman('build', '-n', '-b', 'sandbox')
Simon Glass4f443042016-11-25 20:15:52 -0700665 self.assertEqual(0, result)
666
667 def testNeedBoard(self):
668 """Test that we get an error when no board ius supplied"""
669 with self.assertRaises(ValueError) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600670 result = self._DoBinman('build')
Simon Glass4f443042016-11-25 20:15:52 -0700671 self.assertIn("Must provide a board to process (use -b <board>)",
672 str(e.exception))
673
674 def testMissingDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600675 """Test that an invalid device-tree file generates an error"""
Simon Glass4f443042016-11-25 20:15:52 -0700676 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600677 self._RunBinman('build', '-d', 'missing_file')
Simon Glass4f443042016-11-25 20:15:52 -0700678 # We get one error from libfdt, and a different one from fdtget.
679 self.AssertInList(["Couldn't open blob from 'missing_file'",
680 'No such file or directory'], str(e.exception))
681
682 def testBrokenDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600683 """Test that an invalid device-tree source file generates an error
Simon Glass4f443042016-11-25 20:15:52 -0700684
685 Since this is a source file it should be compiled and the error
686 will come from the device-tree compiler (dtc).
687 """
688 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600689 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700690 self.assertIn("FATAL ERROR: Unable to parse input tree",
691 str(e.exception))
692
693 def testMissingNode(self):
694 """Test that a device tree without a 'binman' node generates an error"""
695 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600696 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700697 self.assertIn("does not have a 'binman' node", str(e.exception))
698
699 def testEmpty(self):
700 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glass53cd5d92019-07-08 14:25:29 -0600701 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700702 self.assertEqual(0, len(result.stderr))
703 self.assertEqual(0, result.return_code)
704
705 def testInvalidEntry(self):
706 """Test that an invalid entry is flagged"""
707 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600708 result = self._RunBinman('build', '-d',
Simon Glass741f2d62018-10-01 12:22:30 -0600709 self.TestFile('004_invalid_entry.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700710 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
711 "'/binman/not-a-valid-type'", str(e.exception))
712
713 def testSimple(self):
714 """Test a simple binman with a single file"""
Simon Glass741f2d62018-10-01 12:22:30 -0600715 data = self._DoReadFile('005_simple.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700716 self.assertEqual(U_BOOT_DATA, data)
717
Simon Glass7fe91732017-11-13 18:55:00 -0700718 def testSimpleDebug(self):
719 """Test a simple binman run with debugging enabled"""
Simon Glasse2705fa2019-07-08 14:25:53 -0600720 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass7fe91732017-11-13 18:55:00 -0700721
Simon Glass4f443042016-11-25 20:15:52 -0700722 def testDual(self):
723 """Test that we can handle creating two images
724
725 This also tests image padding.
726 """
Simon Glass741f2d62018-10-01 12:22:30 -0600727 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700728 self.assertEqual(0, retcode)
729
730 image = control.images['image1']
Simon Glass8beb11e2019-07-08 14:25:47 -0600731 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700732 fname = tools.GetOutputFilename('image1.bin')
733 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600734 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700735 data = fd.read()
736 self.assertEqual(U_BOOT_DATA, data)
737
738 image = control.images['image2']
Simon Glass8beb11e2019-07-08 14:25:47 -0600739 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700740 fname = tools.GetOutputFilename('image2.bin')
741 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600742 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700743 data = fd.read()
744 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glasse6d85ff2019-05-14 15:53:47 -0600745 self.assertEqual(tools.GetBytes(0, 3), data[:3])
746 self.assertEqual(tools.GetBytes(0, 5), data[7:])
Simon Glass4f443042016-11-25 20:15:52 -0700747
748 def testBadAlign(self):
749 """Test that an invalid alignment value is detected"""
750 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600751 self._DoTestFile('007_bad_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700752 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
753 "of two", str(e.exception))
754
755 def testPackSimple(self):
756 """Test that packing works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600757 retcode = self._DoTestFile('008_pack.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700758 self.assertEqual(0, retcode)
759 self.assertIn('image', control.images)
760 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600761 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700762 self.assertEqual(5, len(entries))
763
764 # First u-boot
765 self.assertIn('u-boot', entries)
766 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600767 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700768 self.assertEqual(len(U_BOOT_DATA), entry.size)
769
770 # Second u-boot, aligned to 16-byte boundary
771 self.assertIn('u-boot-align', entries)
772 entry = entries['u-boot-align']
Simon Glass3ab95982018-08-01 15:22:37 -0600773 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700774 self.assertEqual(len(U_BOOT_DATA), entry.size)
775
776 # Third u-boot, size 23 bytes
777 self.assertIn('u-boot-size', entries)
778 entry = entries['u-boot-size']
Simon Glass3ab95982018-08-01 15:22:37 -0600779 self.assertEqual(20, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700780 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
781 self.assertEqual(23, entry.size)
782
783 # Fourth u-boot, placed immediate after the above
784 self.assertIn('u-boot-next', entries)
785 entry = entries['u-boot-next']
Simon Glass3ab95982018-08-01 15:22:37 -0600786 self.assertEqual(43, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700787 self.assertEqual(len(U_BOOT_DATA), entry.size)
788
Simon Glass3ab95982018-08-01 15:22:37 -0600789 # Fifth u-boot, placed at a fixed offset
Simon Glass4f443042016-11-25 20:15:52 -0700790 self.assertIn('u-boot-fixed', entries)
791 entry = entries['u-boot-fixed']
Simon Glass3ab95982018-08-01 15:22:37 -0600792 self.assertEqual(61, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700793 self.assertEqual(len(U_BOOT_DATA), entry.size)
794
Simon Glass8beb11e2019-07-08 14:25:47 -0600795 self.assertEqual(65, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700796
797 def testPackExtra(self):
798 """Test that extra packing feature works as expected"""
Simon Glass4eec34c2020-10-26 17:40:10 -0600799 data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
800 update_dtb=True)
Simon Glass4f443042016-11-25 20:15:52 -0700801
Simon Glass4f443042016-11-25 20:15:52 -0700802 self.assertIn('image', control.images)
803 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600804 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700805 self.assertEqual(5, len(entries))
806
807 # First u-boot with padding before and after
808 self.assertIn('u-boot', entries)
809 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600810 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700811 self.assertEqual(3, entry.pad_before)
812 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600813 self.assertEqual(U_BOOT_DATA, entry.data)
814 self.assertEqual(tools.GetBytes(0, 3) + U_BOOT_DATA +
815 tools.GetBytes(0, 5), data[:entry.size])
816 pos = entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700817
818 # Second u-boot has an aligned size, but it has no effect
819 self.assertIn('u-boot-align-size-nop', entries)
820 entry = entries['u-boot-align-size-nop']
Simon Glassef439ed2020-10-26 17:40:08 -0600821 self.assertEqual(pos, entry.offset)
822 self.assertEqual(len(U_BOOT_DATA), entry.size)
823 self.assertEqual(U_BOOT_DATA, entry.data)
824 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
825 pos += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700826
827 # Third u-boot has an aligned size too
828 self.assertIn('u-boot-align-size', entries)
829 entry = entries['u-boot-align-size']
Simon Glassef439ed2020-10-26 17:40:08 -0600830 self.assertEqual(pos, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700831 self.assertEqual(32, entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600832 self.assertEqual(U_BOOT_DATA, entry.data)
833 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 32 - len(U_BOOT_DATA)),
834 data[pos:pos + entry.size])
835 pos += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700836
837 # Fourth u-boot has an aligned end
838 self.assertIn('u-boot-align-end', entries)
839 entry = entries['u-boot-align-end']
Simon Glass3ab95982018-08-01 15:22:37 -0600840 self.assertEqual(48, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700841 self.assertEqual(16, entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600842 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
843 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 16 - len(U_BOOT_DATA)),
844 data[pos:pos + entry.size])
845 pos += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700846
847 # Fifth u-boot immediately afterwards
848 self.assertIn('u-boot-align-both', entries)
849 entry = entries['u-boot-align-both']
Simon Glass3ab95982018-08-01 15:22:37 -0600850 self.assertEqual(64, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700851 self.assertEqual(64, entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600852 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
853 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 64 - len(U_BOOT_DATA)),
854 data[pos:pos + entry.size])
Simon Glass4f443042016-11-25 20:15:52 -0700855
856 self.CheckNoGaps(entries)
Simon Glass8beb11e2019-07-08 14:25:47 -0600857 self.assertEqual(128, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700858
Simon Glass4eec34c2020-10-26 17:40:10 -0600859 dtb = fdt.Fdt(out_dtb_fname)
860 dtb.Scan()
861 props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
862 expected = {
863 'image-pos': 0,
864 'offset': 0,
865 'size': 128,
866
867 'u-boot:image-pos': 0,
868 'u-boot:offset': 0,
869 'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
870
871 'u-boot-align-size-nop:image-pos': 12,
872 'u-boot-align-size-nop:offset': 12,
873 'u-boot-align-size-nop:size': 4,
874
875 'u-boot-align-size:image-pos': 16,
876 'u-boot-align-size:offset': 16,
877 'u-boot-align-size:size': 32,
878
879 'u-boot-align-end:image-pos': 48,
880 'u-boot-align-end:offset': 48,
881 'u-boot-align-end:size': 16,
882
883 'u-boot-align-both:image-pos': 64,
884 'u-boot-align-both:offset': 64,
885 'u-boot-align-both:size': 64,
886 }
887 self.assertEqual(expected, props)
888
Simon Glass4f443042016-11-25 20:15:52 -0700889 def testPackAlignPowerOf2(self):
890 """Test that invalid entry alignment is detected"""
891 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600892 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700893 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
894 "of two", str(e.exception))
895
896 def testPackAlignSizePowerOf2(self):
897 """Test that invalid entry size alignment is detected"""
898 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600899 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700900 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
901 "power of two", str(e.exception))
902
903 def testPackInvalidAlign(self):
Simon Glass3ab95982018-08-01 15:22:37 -0600904 """Test detection of an offset that does not match its alignment"""
Simon Glass4f443042016-11-25 20:15:52 -0700905 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600906 self._DoTestFile('012_pack_inv_align.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600907 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700908 "align 0x4 (4)", str(e.exception))
909
910 def testPackInvalidSizeAlign(self):
911 """Test that invalid entry size alignment is detected"""
912 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600913 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700914 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
915 "align-size 0x4 (4)", str(e.exception))
916
917 def testPackOverlap(self):
918 """Test that overlapping regions are detected"""
919 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600920 self._DoTestFile('014_pack_overlap.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600921 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -0700922 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
923 str(e.exception))
924
925 def testPackEntryOverflow(self):
926 """Test that entries that overflow their size are detected"""
927 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600928 self._DoTestFile('015_pack_overflow.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700929 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
930 "but entry size is 0x3 (3)", str(e.exception))
931
932 def testPackImageOverflow(self):
933 """Test that entries which overflow the image size are detected"""
934 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600935 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600936 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass4f443042016-11-25 20:15:52 -0700937 "size 0x3 (3)", str(e.exception))
938
939 def testPackImageSize(self):
940 """Test that the image size can be set"""
Simon Glass741f2d62018-10-01 12:22:30 -0600941 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700942 self.assertEqual(0, retcode)
943 self.assertIn('image', control.images)
944 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -0600945 self.assertEqual(7, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700946
947 def testPackImageSizeAlign(self):
948 """Test that image size alignemnt works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600949 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700950 self.assertEqual(0, retcode)
951 self.assertIn('image', control.images)
952 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -0600953 self.assertEqual(16, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700954
955 def testPackInvalidImageAlign(self):
956 """Test that invalid image alignment is detected"""
957 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600958 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600959 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700960 "align-size 0x8 (8)", str(e.exception))
961
962 def testPackAlignPowerOf2(self):
963 """Test that invalid image alignment is detected"""
964 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600965 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -0600966 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass4f443042016-11-25 20:15:52 -0700967 "two", str(e.exception))
968
969 def testImagePadByte(self):
970 """Test that the image pad byte can be specified"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600971 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600972 data = self._DoReadFile('021_image_pad.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -0600973 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0xff, 1) +
974 U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -0700975
976 def testImageName(self):
977 """Test that image files can be named"""
Simon Glass741f2d62018-10-01 12:22:30 -0600978 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700979 self.assertEqual(0, retcode)
980 image = control.images['image1']
981 fname = tools.GetOutputFilename('test-name')
982 self.assertTrue(os.path.exists(fname))
983
984 image = control.images['image2']
985 fname = tools.GetOutputFilename('test-name.xx')
986 self.assertTrue(os.path.exists(fname))
987
988 def testBlobFilename(self):
989 """Test that generic blobs can be provided by filename"""
Simon Glass741f2d62018-10-01 12:22:30 -0600990 data = self._DoReadFile('023_blob.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700991 self.assertEqual(BLOB_DATA, data)
992
993 def testPackSorted(self):
994 """Test that entries can be sorted"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600995 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600996 data = self._DoReadFile('024_sorted.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -0600997 self.assertEqual(tools.GetBytes(0, 1) + U_BOOT_SPL_DATA +
998 tools.GetBytes(0, 2) + U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -0700999
Simon Glass3ab95982018-08-01 15:22:37 -06001000 def testPackZeroOffset(self):
1001 """Test that an entry at offset 0 is not given a new offset"""
Simon Glass4f443042016-11-25 20:15:52 -07001002 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001003 self._DoTestFile('025_pack_zero_size.dts')
Simon Glass3ab95982018-08-01 15:22:37 -06001004 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -07001005 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1006 str(e.exception))
1007
1008 def testPackUbootDtb(self):
1009 """Test that a device tree can be added to U-Boot"""
Simon Glass741f2d62018-10-01 12:22:30 -06001010 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001011 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glasse0ff8552016-11-25 20:15:53 -07001012
1013 def testPackX86RomNoSize(self):
1014 """Test that the end-at-4gb property requires a size property"""
1015 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001016 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -06001017 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glasse0ff8552016-11-25 20:15:53 -07001018 "using end-at-4gb", str(e.exception))
1019
Jagdish Gediya94b57db2018-09-03 21:35:07 +05301020 def test4gbAndSkipAtStartTogether(self):
1021 """Test that the end-at-4gb and skip-at-size property can't be used
1022 together"""
1023 with self.assertRaises(ValueError) as e:
Simon Glassdfdd2b62019-08-24 07:23:02 -06001024 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -06001025 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya94b57db2018-09-03 21:35:07 +05301026 "'skip-at-start'", str(e.exception))
1027
Simon Glasse0ff8552016-11-25 20:15:53 -07001028 def testPackX86RomOutside(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001029 """Test that the end-at-4gb property checks for offset boundaries"""
Simon Glasse0ff8552016-11-25 20:15:53 -07001030 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001031 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glasse6bed4f2020-10-26 17:40:05 -06001032 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
1033 "is outside the section '/binman' starting at "
1034 '0xffffffe0 (4294967264) of size 0x20 (32)',
Simon Glasse0ff8552016-11-25 20:15:53 -07001035 str(e.exception))
1036
1037 def testPackX86Rom(self):
1038 """Test that a basic x86 ROM can be created"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001039 self._SetupSplElf()
Simon Glass9255f3c2019-08-24 07:23:01 -06001040 data = self._DoReadFile('029_x86_rom.dts')
Simon Glasseb0086f2019-08-24 07:23:04 -06001041 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 3) + U_BOOT_SPL_DATA +
Simon Glasse6d85ff2019-05-14 15:53:47 -06001042 tools.GetBytes(0, 2), data)
Simon Glasse0ff8552016-11-25 20:15:53 -07001043
1044 def testPackX86RomMeNoDesc(self):
1045 """Test that an invalid Intel descriptor entry is detected"""
Simon Glass0ba4b3d2020-07-09 18:39:41 -06001046 try:
Simon Glass52b10dd2020-07-25 15:11:19 -06001047 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
Simon Glass0ba4b3d2020-07-09 18:39:41 -06001048 with self.assertRaises(ValueError) as e:
Simon Glass52b10dd2020-07-25 15:11:19 -06001049 self._DoTestFile('163_x86_rom_me_empty.dts')
Simon Glass0ba4b3d2020-07-09 18:39:41 -06001050 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1051 str(e.exception))
1052 finally:
1053 self._SetupDescriptor()
Simon Glasse0ff8552016-11-25 20:15:53 -07001054
1055 def testPackX86RomBadDesc(self):
1056 """Test that the Intel requires a descriptor entry"""
1057 with self.assertRaises(ValueError) as e:
Simon Glass9255f3c2019-08-24 07:23:01 -06001058 self._DoTestFile('030_x86_rom_me_no_desc.dts')
Simon Glass3ab95982018-08-01 15:22:37 -06001059 self.assertIn("Node '/binman/intel-me': No offset set with "
1060 "offset-unset: should another entry provide this correct "
1061 "offset?", str(e.exception))
Simon Glasse0ff8552016-11-25 20:15:53 -07001062
1063 def testPackX86RomMe(self):
1064 """Test that an x86 ROM with an ME region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001065 data = self._DoReadFile('031_x86_rom_me.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06001066 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
1067 if data[:0x1000] != expected_desc:
1068 self.fail('Expected descriptor binary at start of image')
Simon Glasse0ff8552016-11-25 20:15:53 -07001069 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1070
1071 def testPackVga(self):
1072 """Test that an image with a VGA binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001073 data = self._DoReadFile('032_intel_vga.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -07001074 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1075
1076 def testPackStart16(self):
1077 """Test that an image with an x86 start16 region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001078 data = self._DoReadFile('033_x86_start16.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -07001079 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1080
Jagdish Gediya9d368f32018-09-03 21:35:08 +05301081 def testPackPowerpcMpc85xxBootpgResetvec(self):
1082 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1083 created"""
Simon Glassdfdd2b62019-08-24 07:23:02 -06001084 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
Jagdish Gediya9d368f32018-09-03 21:35:08 +05301085 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1086
Simon Glass736bb0a2018-07-06 10:27:17 -06001087 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glassadc57012018-07-06 10:27:16 -06001088 """Handle running a test for insertion of microcode
1089
1090 Args:
1091 dts_fname: Name of test .dts file
1092 nodtb_data: Data that we expect in the first section
Simon Glass736bb0a2018-07-06 10:27:17 -06001093 ucode_second: True if the microsecond entry is second instead of
1094 third
Simon Glassadc57012018-07-06 10:27:16 -06001095
1096 Returns:
1097 Tuple:
1098 Contents of first region (U-Boot or SPL)
Simon Glass3ab95982018-08-01 15:22:37 -06001099 Offset and size components of microcode pointer, as inserted
Simon Glassadc57012018-07-06 10:27:16 -06001100 in the above (two 4-byte words)
1101 """
Simon Glass6b187df2017-11-12 21:52:27 -07001102 data = self._DoReadFile(dts_fname, True)
Simon Glasse0ff8552016-11-25 20:15:53 -07001103
1104 # Now check the device tree has no microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001105 if ucode_second:
1106 ucode_content = data[len(nodtb_data):]
1107 ucode_pos = len(nodtb_data)
1108 dtb_with_ucode = ucode_content[16:]
1109 fdt_len = self.GetFdtLen(dtb_with_ucode)
1110 else:
1111 dtb_with_ucode = data[len(nodtb_data):]
1112 fdt_len = self.GetFdtLen(dtb_with_ucode)
1113 ucode_content = dtb_with_ucode[fdt_len:]
1114 ucode_pos = len(nodtb_data) + fdt_len
Simon Glasse0ff8552016-11-25 20:15:53 -07001115 fname = tools.GetOutputFilename('test.dtb')
1116 with open(fname, 'wb') as fd:
Simon Glassadc57012018-07-06 10:27:16 -06001117 fd.write(dtb_with_ucode)
Simon Glassec3f3782017-05-27 07:38:29 -06001118 dtb = fdt.FdtScan(fname)
1119 ucode = dtb.GetNode('/microcode')
Simon Glasse0ff8552016-11-25 20:15:53 -07001120 self.assertTrue(ucode)
1121 for node in ucode.subnodes:
1122 self.assertFalse(node.props.get('data'))
1123
Simon Glasse0ff8552016-11-25 20:15:53 -07001124 # Check that the microcode appears immediately after the Fdt
1125 # This matches the concatenation of the data properties in
Simon Glass87722132017-11-12 21:52:26 -07001126 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glasse0ff8552016-11-25 20:15:53 -07001127 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1128 0x78235609)
Simon Glassadc57012018-07-06 10:27:16 -06001129 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glasse0ff8552016-11-25 20:15:53 -07001130
1131 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -06001132 # expected offset and size
Simon Glasse0ff8552016-11-25 20:15:53 -07001133 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1134 len(ucode_data))
Simon Glass736bb0a2018-07-06 10:27:17 -06001135 u_boot = data[:len(nodtb_data)]
1136 return u_boot, pos_and_size
Simon Glass6b187df2017-11-12 21:52:27 -07001137
1138 def testPackUbootMicrocode(self):
1139 """Test that x86 microcode can be handled correctly
1140
1141 We expect to see the following in the image, in order:
1142 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1143 place
1144 u-boot.dtb with the microcode removed
1145 the microcode
1146 """
Simon Glass741f2d62018-10-01 12:22:30 -06001147 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass6b187df2017-11-12 21:52:27 -07001148 U_BOOT_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001149 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1150 b' somewhere in here', first)
Simon Glasse0ff8552016-11-25 20:15:53 -07001151
Simon Glass160a7662017-05-27 07:38:26 -06001152 def _RunPackUbootSingleMicrocode(self):
Simon Glasse0ff8552016-11-25 20:15:53 -07001153 """Test that x86 microcode can be handled correctly
1154
1155 We expect to see the following in the image, in order:
1156 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1157 place
1158 u-boot.dtb with the microcode
1159 an empty microcode region
1160 """
1161 # We need the libfdt library to run this test since only that allows
1162 # finding the offset of a property. This is required by
1163 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass741f2d62018-10-01 12:22:30 -06001164 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glasse0ff8552016-11-25 20:15:53 -07001165
1166 second = data[len(U_BOOT_NODTB_DATA):]
1167
1168 fdt_len = self.GetFdtLen(second)
1169 third = second[fdt_len:]
1170 second = second[:fdt_len]
1171
Simon Glass160a7662017-05-27 07:38:26 -06001172 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1173 self.assertIn(ucode_data, second)
1174 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -07001175
Simon Glass160a7662017-05-27 07:38:26 -06001176 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -06001177 # expected offset and size
Simon Glass160a7662017-05-27 07:38:26 -06001178 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1179 len(ucode_data))
1180 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glassc6c10e72019-05-17 22:00:46 -06001181 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1182 b' somewhere in here', first)
Simon Glassc49deb82016-11-25 20:15:54 -07001183
Simon Glass75db0862016-11-25 20:15:55 -07001184 def testPackUbootSingleMicrocode(self):
1185 """Test that x86 microcode can be handled correctly with fdt_normal.
1186 """
Simon Glass160a7662017-05-27 07:38:26 -06001187 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001188
Simon Glassc49deb82016-11-25 20:15:54 -07001189 def testUBootImg(self):
1190 """Test that u-boot.img can be put in a file"""
Simon Glass741f2d62018-10-01 12:22:30 -06001191 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glassc49deb82016-11-25 20:15:54 -07001192 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glass75db0862016-11-25 20:15:55 -07001193
1194 def testNoMicrocode(self):
1195 """Test that a missing microcode region is detected"""
1196 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001197 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001198 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1199 "node found in ", str(e.exception))
1200
1201 def testMicrocodeWithoutNode(self):
1202 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1203 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001204 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001205 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1206 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1207
1208 def testMicrocodeWithoutNode2(self):
1209 """Test that a missing u-boot-ucode node is detected"""
1210 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001211 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001212 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1213 "microcode region u-boot-ucode", str(e.exception))
1214
1215 def testMicrocodeWithoutPtrInElf(self):
1216 """Test that a U-Boot binary without the microcode symbol is detected"""
1217 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glass75db0862016-11-25 20:15:55 -07001218 try:
Simon Glassbccd91d2019-08-24 07:22:55 -06001219 TestFunctional._MakeInputFile('u-boot',
1220 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass75db0862016-11-25 20:15:55 -07001221
1222 with self.assertRaises(ValueError) as e:
Simon Glass160a7662017-05-27 07:38:26 -06001223 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001224 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1225 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1226
1227 finally:
1228 # Put the original file back
Simon Glassf514d8f2019-08-24 07:22:54 -06001229 TestFunctional._MakeInputFile('u-boot',
1230 tools.ReadFile(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glass75db0862016-11-25 20:15:55 -07001231
1232 def testMicrocodeNotInImage(self):
1233 """Test that microcode must be placed within the image"""
1234 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001235 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001236 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1237 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glass25ac0e62018-06-01 09:38:14 -06001238 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glass75db0862016-11-25 20:15:55 -07001239
1240 def testWithoutMicrocode(self):
1241 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glassbccd91d2019-08-24 07:22:55 -06001242 TestFunctional._MakeInputFile('u-boot',
1243 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass741f2d62018-10-01 12:22:30 -06001244 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001245
1246 # Now check the device tree has no microcode
1247 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1248 second = data[len(U_BOOT_NODTB_DATA):]
1249
1250 fdt_len = self.GetFdtLen(second)
1251 self.assertEqual(dtb, second[:fdt_len])
1252
1253 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1254 third = data[used_len:]
Simon Glasse6d85ff2019-05-14 15:53:47 -06001255 self.assertEqual(tools.GetBytes(0, 0x200 - used_len), third)
Simon Glass75db0862016-11-25 20:15:55 -07001256
1257 def testUnknownPosSize(self):
1258 """Test that microcode must be placed within the image"""
1259 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001260 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glass3ab95982018-08-01 15:22:37 -06001261 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glass75db0862016-11-25 20:15:55 -07001262 "entry 'invalid-entry'", str(e.exception))
Simon Glassda229092016-11-25 20:15:56 -07001263
1264 def testPackFsp(self):
1265 """Test that an image with a FSP binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001266 data = self._DoReadFile('042_intel_fsp.dts')
Simon Glassda229092016-11-25 20:15:56 -07001267 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1268
1269 def testPackCmc(self):
Bin Meng59ea8c22017-08-15 22:41:54 -07001270 """Test that an image with a CMC binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001271 data = self._DoReadFile('043_intel_cmc.dts')
Simon Glassda229092016-11-25 20:15:56 -07001272 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Meng59ea8c22017-08-15 22:41:54 -07001273
1274 def testPackVbt(self):
1275 """Test that an image with a VBT binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001276 data = self._DoReadFile('046_intel_vbt.dts')
Bin Meng59ea8c22017-08-15 22:41:54 -07001277 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glass9fc60b42017-11-12 21:52:22 -07001278
Simon Glass56509842017-11-12 21:52:25 -07001279 def testSplBssPad(self):
1280 """Test that we can pad SPL's BSS with zeros"""
Simon Glass6b187df2017-11-12 21:52:27 -07001281 # ELF file with a '__bss_size' symbol
Simon Glass11ae93e2018-10-01 21:12:47 -06001282 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001283 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001284 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
1285 data)
Simon Glass56509842017-11-12 21:52:25 -07001286
Simon Glass86af5112018-10-01 21:12:42 -06001287 def testSplBssPadMissing(self):
1288 """Test that a missing symbol is detected"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001289 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glassb50e5612017-11-13 18:54:54 -07001290 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001291 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassb50e5612017-11-13 18:54:54 -07001292 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1293 str(e.exception))
1294
Simon Glass87722132017-11-12 21:52:26 -07001295 def testPackStart16Spl(self):
Simon Glass35b384c2018-09-14 04:57:10 -06001296 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001297 data = self._DoReadFile('048_x86_start16_spl.dts')
Simon Glass87722132017-11-12 21:52:26 -07001298 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1299
Simon Glass736bb0a2018-07-06 10:27:17 -06001300 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1301 """Helper function for microcode tests
Simon Glass6b187df2017-11-12 21:52:27 -07001302
1303 We expect to see the following in the image, in order:
1304 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1305 correct place
1306 u-boot.dtb with the microcode removed
1307 the microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001308
1309 Args:
1310 dts: Device tree file to use for test
1311 ucode_second: True if the microsecond entry is second instead of
1312 third
Simon Glass6b187df2017-11-12 21:52:27 -07001313 """
Simon Glass11ae93e2018-10-01 21:12:47 -06001314 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass736bb0a2018-07-06 10:27:17 -06001315 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1316 ucode_second=ucode_second)
Simon Glassc6c10e72019-05-17 22:00:46 -06001317 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1318 b'ter somewhere in here', first)
Simon Glass6b187df2017-11-12 21:52:27 -07001319
Simon Glass736bb0a2018-07-06 10:27:17 -06001320 def testPackUbootSplMicrocode(self):
1321 """Test that x86 microcode can be handled correctly in SPL"""
Simon Glass741f2d62018-10-01 12:22:30 -06001322 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass736bb0a2018-07-06 10:27:17 -06001323
1324 def testPackUbootSplMicrocodeReorder(self):
1325 """Test that order doesn't matter for microcode entries
1326
1327 This is the same as testPackUbootSplMicrocode but when we process the
1328 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1329 entry, so we reply on binman to try later.
1330 """
Simon Glass741f2d62018-10-01 12:22:30 -06001331 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass736bb0a2018-07-06 10:27:17 -06001332 ucode_second=True)
1333
Simon Glassca4f4ff2017-11-12 21:52:28 -07001334 def testPackMrc(self):
1335 """Test that an image with an MRC binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001336 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassca4f4ff2017-11-12 21:52:28 -07001337 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1338
Simon Glass47419ea2017-11-13 18:54:55 -07001339 def testSplDtb(self):
1340 """Test that an image with spl/u-boot-spl.dtb can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001341 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass47419ea2017-11-13 18:54:55 -07001342 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1343
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001344 def testSplNoDtb(self):
1345 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass0fe44dc2021-04-25 08:39:32 +12001346 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001347 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001348 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1349
Simon Glass3d433382021-03-21 18:24:30 +13001350 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
1351 use_expanded=False):
Simon Glassf5898822021-03-18 20:24:56 +13001352 """Check the image contains the expected symbol values
1353
1354 Args:
1355 dts: Device tree file to use for test
1356 base_data: Data before and after 'u-boot' section
1357 u_boot_offset: Offset of 'u-boot' section in image
Simon Glass3d433382021-03-21 18:24:30 +13001358 entry_args: Dict of entry args to supply to binman
1359 key: arg name
1360 value: value of that arg
1361 use_expanded: True to use expanded entries where available, e.g.
1362 'u-boot-expanded' instead of 'u-boot'
Simon Glassf5898822021-03-18 20:24:56 +13001363 """
Simon Glass1542c8b2019-08-24 07:22:56 -06001364 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass19790632017-11-13 18:55:01 -07001365 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1366 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Simon Glassf5898822021-03-18 20:24:56 +13001367 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
1368 addr)
Simon Glass19790632017-11-13 18:55:01 -07001369
Simon Glass11ae93e2018-10-01 21:12:47 -06001370 self._SetupSplElf('u_boot_binman_syms')
Simon Glass3d433382021-03-21 18:24:30 +13001371 data = self._DoReadFileDtb(dts, entry_args=entry_args,
1372 use_expanded=use_expanded)[0]
Simon Glassf5898822021-03-18 20:24:56 +13001373 # The image should contain the symbols from u_boot_binman_syms.c
1374 # Note that image_pos is adjusted by the base address of the image,
1375 # which is 0x10 in our test image
1376 sym_values = struct.pack('<LQLL', 0x00,
1377 u_boot_offset + len(U_BOOT_DATA),
1378 0x10 + u_boot_offset, 0x04)
1379 expected = (sym_values + base_data[20:] +
Simon Glasse6d85ff2019-05-14 15:53:47 -06001380 tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
Simon Glassf5898822021-03-18 20:24:56 +13001381 base_data[20:])
Simon Glass19790632017-11-13 18:55:01 -07001382 self.assertEqual(expected, data)
1383
Simon Glassf5898822021-03-18 20:24:56 +13001384 def testSymbols(self):
1385 """Test binman can assign symbols embedded in U-Boot"""
1386 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x18)
1387
1388 def testSymbolsNoDtb(self):
1389 """Test binman can assign symbols embedded in U-Boot SPL"""
Simon Glasse9e0db82021-03-21 18:24:29 +13001390 self.checkSymbols('196_symbols_nodtb.dts',
Simon Glassf5898822021-03-18 20:24:56 +13001391 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1392 0x38)
1393
Simon Glassdd57c132018-06-01 09:38:11 -06001394 def testPackUnitAddress(self):
1395 """Test that we support multiple binaries with the same name"""
Simon Glass741f2d62018-10-01 12:22:30 -06001396 data = self._DoReadFile('054_unit_address.dts')
Simon Glassdd57c132018-06-01 09:38:11 -06001397 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1398
Simon Glass18546952018-06-01 09:38:16 -06001399 def testSections(self):
1400 """Basic test of sections"""
Simon Glass741f2d62018-10-01 12:22:30 -06001401 data = self._DoReadFile('055_sections.dts')
Simon Glassc6c10e72019-05-17 22:00:46 -06001402 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1403 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
1404 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
Simon Glass18546952018-06-01 09:38:16 -06001405 self.assertEqual(expected, data)
Simon Glass9fc60b42017-11-12 21:52:22 -07001406
Simon Glass3b0c3822018-06-01 09:38:20 -06001407 def testMap(self):
1408 """Tests outputting a map of the images"""
Simon Glass741f2d62018-10-01 12:22:30 -06001409 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001410 self.assertEqual('''ImagePos Offset Size Name
141100000000 00000000 00000028 main-section
141200000000 00000000 00000010 section@0
141300000000 00000000 00000004 u-boot
141400000010 00000010 00000010 section@1
141500000010 00000000 00000004 u-boot
141600000020 00000020 00000004 section@2
141700000020 00000000 00000004 u-boot
Simon Glass3b0c3822018-06-01 09:38:20 -06001418''', map_data)
1419
Simon Glassc8d48ef2018-06-01 09:38:21 -06001420 def testNamePrefix(self):
1421 """Tests that name prefixes are used"""
Simon Glass741f2d62018-10-01 12:22:30 -06001422 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001423 self.assertEqual('''ImagePos Offset Size Name
142400000000 00000000 00000028 main-section
142500000000 00000000 00000010 section@0
142600000000 00000000 00000004 ro-u-boot
142700000010 00000010 00000010 section@1
142800000010 00000000 00000004 rw-u-boot
Simon Glassc8d48ef2018-06-01 09:38:21 -06001429''', map_data)
1430
Simon Glass736bb0a2018-07-06 10:27:17 -06001431 def testUnknownContents(self):
1432 """Test that obtaining the contents works as expected"""
1433 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001434 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass8beb11e2019-07-08 14:25:47 -06001435 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glass16287932020-04-17 18:09:03 -06001436 "processing of contents: remaining ["
1437 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass736bb0a2018-07-06 10:27:17 -06001438
Simon Glass5c890232018-07-06 10:27:19 -06001439 def testBadChangeSize(self):
1440 """Test that trying to change the size of an entry fails"""
Simon Glassc52c9e72019-07-08 14:25:37 -06001441 try:
1442 state.SetAllowEntryExpansion(False)
1443 with self.assertRaises(ValueError) as e:
1444 self._DoReadFile('059_change_size.dts', True)
Simon Glass79d3c582019-07-20 12:23:57 -06001445 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glassc52c9e72019-07-08 14:25:37 -06001446 str(e.exception))
1447 finally:
1448 state.SetAllowEntryExpansion(True)
Simon Glass5c890232018-07-06 10:27:19 -06001449
Simon Glass16b8d6b2018-07-06 10:27:42 -06001450 def testUpdateFdt(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001451 """Test that we can update the device tree with offset/size info"""
Simon Glass741f2d62018-10-01 12:22:30 -06001452 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glass16b8d6b2018-07-06 10:27:42 -06001453 update_dtb=True)
Simon Glasscee02e62018-07-17 13:25:52 -06001454 dtb = fdt.Fdt(out_dtb_fname)
1455 dtb.Scan()
Simon Glass12bb1a92019-07-20 12:23:51 -06001456 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001457 self.assertEqual({
Simon Glassdbf6be92018-08-01 15:22:42 -06001458 'image-pos': 0,
Simon Glass8122f392018-07-17 13:25:28 -06001459 'offset': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001460 '_testing:offset': 32,
Simon Glass79d3c582019-07-20 12:23:57 -06001461 '_testing:size': 2,
Simon Glassdbf6be92018-08-01 15:22:42 -06001462 '_testing:image-pos': 32,
Simon Glass3ab95982018-08-01 15:22:37 -06001463 'section@0/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001464 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001465 'section@0/u-boot:image-pos': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001466 'section@0:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001467 'section@0:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001468 'section@0:image-pos': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001469
Simon Glass3ab95982018-08-01 15:22:37 -06001470 'section@1/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001471 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001472 'section@1/u-boot:image-pos': 16,
Simon Glass3ab95982018-08-01 15:22:37 -06001473 'section@1:offset': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001474 'section@1:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001475 'section@1:image-pos': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001476 'size': 40
1477 }, props)
1478
1479 def testUpdateFdtBad(self):
1480 """Test that we detect when ProcessFdt never completes"""
1481 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001482 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001483 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glass16287932020-04-17 18:09:03 -06001484 '[<binman.etype._testing.Entry__testing',
1485 str(e.exception))
Simon Glass5c890232018-07-06 10:27:19 -06001486
Simon Glass53af22a2018-07-17 13:25:32 -06001487 def testEntryArgs(self):
1488 """Test passing arguments to entries from the command line"""
1489 entry_args = {
1490 'test-str-arg': 'test1',
1491 'test-int-arg': '456',
1492 }
Simon Glass741f2d62018-10-01 12:22:30 -06001493 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001494 self.assertIn('image', control.images)
1495 entry = control.images['image'].GetEntries()['_testing']
1496 self.assertEqual('test0', entry.test_str_fdt)
1497 self.assertEqual('test1', entry.test_str_arg)
1498 self.assertEqual(123, entry.test_int_fdt)
1499 self.assertEqual(456, entry.test_int_arg)
1500
1501 def testEntryArgsMissing(self):
1502 """Test missing arguments and properties"""
1503 entry_args = {
1504 'test-int-arg': '456',
1505 }
Simon Glass741f2d62018-10-01 12:22:30 -06001506 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001507 entry = control.images['image'].GetEntries()['_testing']
1508 self.assertEqual('test0', entry.test_str_fdt)
1509 self.assertEqual(None, entry.test_str_arg)
1510 self.assertEqual(None, entry.test_int_fdt)
1511 self.assertEqual(456, entry.test_int_arg)
1512
1513 def testEntryArgsRequired(self):
1514 """Test missing arguments and properties"""
1515 entry_args = {
1516 'test-int-arg': '456',
1517 }
1518 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001519 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass3decfa32020-09-01 05:13:54 -06001520 self.assertIn("Node '/binman/_testing': "
1521 'Missing required properties/entry args: test-str-arg, '
1522 'test-int-fdt, test-int-arg',
Simon Glass53af22a2018-07-17 13:25:32 -06001523 str(e.exception))
1524
1525 def testEntryArgsInvalidFormat(self):
1526 """Test that an invalid entry-argument format is detected"""
Simon Glass53cd5d92019-07-08 14:25:29 -06001527 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1528 '-ano-value']
Simon Glass53af22a2018-07-17 13:25:32 -06001529 with self.assertRaises(ValueError) as e:
1530 self._DoBinman(*args)
1531 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1532
1533 def testEntryArgsInvalidInteger(self):
1534 """Test that an invalid entry-argument integer is detected"""
1535 entry_args = {
1536 'test-int-arg': 'abc',
1537 }
1538 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001539 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001540 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1541 "'test-int-arg' (value 'abc') to integer",
1542 str(e.exception))
1543
1544 def testEntryArgsInvalidDatatype(self):
1545 """Test that an invalid entry-argument datatype is detected
1546
1547 This test could be written in entry_test.py except that it needs
1548 access to control.entry_args, which seems more than that module should
1549 be able to see.
1550 """
1551 entry_args = {
1552 'test-bad-datatype-arg': '12',
1553 }
1554 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001555 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass53af22a2018-07-17 13:25:32 -06001556 entry_args=entry_args)
1557 self.assertIn('GetArg() internal error: Unknown data type ',
1558 str(e.exception))
1559
Simon Glassbb748372018-07-17 13:25:33 -06001560 def testText(self):
1561 """Test for a text entry type"""
1562 entry_args = {
1563 'test-id': TEXT_DATA,
1564 'test-id2': TEXT_DATA2,
1565 'test-id3': TEXT_DATA3,
1566 }
Simon Glass741f2d62018-10-01 12:22:30 -06001567 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glassbb748372018-07-17 13:25:33 -06001568 entry_args=entry_args)
Simon Glassc6c10e72019-05-17 22:00:46 -06001569 expected = (tools.ToBytes(TEXT_DATA) +
1570 tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1571 tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
Simon Glassaa88b502019-07-08 13:18:40 -06001572 b'some text' + b'more text')
Simon Glassbb748372018-07-17 13:25:33 -06001573 self.assertEqual(expected, data)
1574
Simon Glassfd8d1f72018-07-17 13:25:36 -06001575 def testEntryDocs(self):
1576 """Test for creation of entry documentation"""
1577 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass87d43322020-08-05 13:27:46 -06001578 control.WriteEntryDocs(control.GetEntryModules())
Simon Glassfd8d1f72018-07-17 13:25:36 -06001579 self.assertTrue(len(stdout.getvalue()) > 0)
1580
1581 def testEntryDocsMissing(self):
1582 """Test handling of missing entry documentation"""
1583 with self.assertRaises(ValueError) as e:
1584 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass87d43322020-08-05 13:27:46 -06001585 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glassfd8d1f72018-07-17 13:25:36 -06001586 self.assertIn('Documentation is missing for modules: u_boot',
1587 str(e.exception))
1588
Simon Glass11e36cc2018-07-17 13:25:38 -06001589 def testFmap(self):
1590 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001591 data = self._DoReadFile('067_fmap.dts')
Simon Glass11e36cc2018-07-17 13:25:38 -06001592 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc6c10e72019-05-17 22:00:46 -06001593 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1594 U_BOOT_DATA + tools.GetBytes(ord('a'), 12))
Simon Glass11e36cc2018-07-17 13:25:38 -06001595 self.assertEqual(expected, data[:32])
Simon Glassc6c10e72019-05-17 22:00:46 -06001596 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass11e36cc2018-07-17 13:25:38 -06001597 self.assertEqual(1, fhdr.ver_major)
1598 self.assertEqual(0, fhdr.ver_minor)
1599 self.assertEqual(0, fhdr.base)
Simon Glass17365752021-04-03 11:05:10 +13001600 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 5
Simon Glassc7722e82021-04-03 11:05:09 +13001601 self.assertEqual(16 + 16 + expect_size, fhdr.image_size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001602 self.assertEqual(b'FMAP', fhdr.name)
Simon Glass17365752021-04-03 11:05:10 +13001603 self.assertEqual(5, fhdr.nareas)
Simon Glassc7722e82021-04-03 11:05:09 +13001604 fiter = iter(fentries)
Simon Glass11e36cc2018-07-17 13:25:38 -06001605
Simon Glassc7722e82021-04-03 11:05:09 +13001606 fentry = next(fiter)
Simon Glass17365752021-04-03 11:05:10 +13001607 self.assertEqual(b'SECTION0', fentry.name)
1608 self.assertEqual(0, fentry.offset)
1609 self.assertEqual(16, fentry.size)
1610 self.assertEqual(0, fentry.flags)
1611
1612 fentry = next(fiter)
Simon Glassc7722e82021-04-03 11:05:09 +13001613 self.assertEqual(b'RO_U_BOOT', fentry.name)
1614 self.assertEqual(0, fentry.offset)
1615 self.assertEqual(4, fentry.size)
1616 self.assertEqual(0, fentry.flags)
Simon Glass11e36cc2018-07-17 13:25:38 -06001617
Simon Glassc7722e82021-04-03 11:05:09 +13001618 fentry = next(fiter)
Simon Glass17365752021-04-03 11:05:10 +13001619 self.assertEqual(b'SECTION1', fentry.name)
1620 self.assertEqual(16, fentry.offset)
1621 self.assertEqual(16, fentry.size)
1622 self.assertEqual(0, fentry.flags)
1623
1624 fentry = next(fiter)
Simon Glassc7722e82021-04-03 11:05:09 +13001625 self.assertEqual(b'RW_U_BOOT', fentry.name)
1626 self.assertEqual(16, fentry.offset)
1627 self.assertEqual(4, fentry.size)
1628 self.assertEqual(0, fentry.flags)
Simon Glass11e36cc2018-07-17 13:25:38 -06001629
Simon Glassc7722e82021-04-03 11:05:09 +13001630 fentry = next(fiter)
1631 self.assertEqual(b'FMAP', fentry.name)
1632 self.assertEqual(32, fentry.offset)
1633 self.assertEqual(expect_size, fentry.size)
1634 self.assertEqual(0, fentry.flags)
Simon Glass11e36cc2018-07-17 13:25:38 -06001635
Simon Glassec127af2018-07-17 13:25:39 -06001636 def testBlobNamedByArg(self):
1637 """Test we can add a blob with the filename coming from an entry arg"""
1638 entry_args = {
1639 'cros-ec-rw-path': 'ecrw.bin',
1640 }
Simon Glass3decfa32020-09-01 05:13:54 -06001641 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassec127af2018-07-17 13:25:39 -06001642
Simon Glass3af8e492018-07-17 13:25:40 -06001643 def testFill(self):
1644 """Test for an fill entry type"""
Simon Glass741f2d62018-10-01 12:22:30 -06001645 data = self._DoReadFile('069_fill.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001646 expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
Simon Glass3af8e492018-07-17 13:25:40 -06001647 self.assertEqual(expected, data)
1648
1649 def testFillNoSize(self):
1650 """Test for an fill entry type with no size"""
1651 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001652 self._DoReadFile('070_fill_no_size.dts')
Simon Glass3af8e492018-07-17 13:25:40 -06001653 self.assertIn("'fill' entry must have a size property",
1654 str(e.exception))
1655
Simon Glass0ef87aa2018-07-17 13:25:44 -06001656 def _HandleGbbCommand(self, pipe_list):
1657 """Fake calls to the futility utility"""
1658 if pipe_list[0][0] == 'futility':
1659 fname = pipe_list[0][-1]
1660 # Append our GBB data to the file, which will happen every time the
1661 # futility command is called.
Simon Glass1d0ebf72019-05-14 15:53:42 -06001662 with open(fname, 'ab') as fd:
Simon Glass0ef87aa2018-07-17 13:25:44 -06001663 fd.write(GBB_DATA)
1664 return command.CommandResult()
1665
1666 def testGbb(self):
1667 """Test for the Chromium OS Google Binary Block"""
1668 command.test_result = self._HandleGbbCommand
1669 entry_args = {
1670 'keydir': 'devkeys',
1671 'bmpblk': 'bmpblk.bin',
1672 }
Simon Glass741f2d62018-10-01 12:22:30 -06001673 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glass0ef87aa2018-07-17 13:25:44 -06001674
1675 # Since futility
Simon Glasse6d85ff2019-05-14 15:53:47 -06001676 expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1677 tools.GetBytes(0, 0x2180 - 16))
Simon Glass0ef87aa2018-07-17 13:25:44 -06001678 self.assertEqual(expected, data)
1679
1680 def testGbbTooSmall(self):
1681 """Test for the Chromium OS Google Binary Block being large enough"""
1682 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001683 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001684 self.assertIn("Node '/binman/gbb': GBB is too small",
1685 str(e.exception))
1686
1687 def testGbbNoSize(self):
1688 """Test for the Chromium OS Google Binary Block having a size"""
1689 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001690 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001691 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1692 str(e.exception))
1693
Simon Glass24d0d3c2018-07-17 13:25:47 -06001694 def _HandleVblockCommand(self, pipe_list):
Simon Glass5af9ebc2021-01-06 21:35:17 -07001695 """Fake calls to the futility utility
1696
1697 The expected pipe is:
1698
1699 [('futility', 'vbutil_firmware', '--vblock',
1700 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1701 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1702 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1703 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1704
1705 This writes to the output file (here, 'vblock.vblock'). If
1706 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1707 of the input data (here, 'input.vblock').
1708 """
Simon Glass24d0d3c2018-07-17 13:25:47 -06001709 if pipe_list[0][0] == 'futility':
1710 fname = pipe_list[0][3]
Simon Glassa326b492018-09-14 04:57:11 -06001711 with open(fname, 'wb') as fd:
Simon Glass5af9ebc2021-01-06 21:35:17 -07001712 if self._hash_data:
1713 infile = pipe_list[0][11]
1714 m = hashlib.sha256()
1715 data = tools.ReadFile(infile)
1716 m.update(data)
1717 fd.write(m.digest())
1718 else:
1719 fd.write(VBLOCK_DATA)
1720
Simon Glass24d0d3c2018-07-17 13:25:47 -06001721 return command.CommandResult()
1722
1723 def testVblock(self):
1724 """Test for the Chromium OS Verified Boot Block"""
Simon Glass5af9ebc2021-01-06 21:35:17 -07001725 self._hash_data = False
Simon Glass24d0d3c2018-07-17 13:25:47 -06001726 command.test_result = self._HandleVblockCommand
1727 entry_args = {
1728 'keydir': 'devkeys',
1729 }
Simon Glass741f2d62018-10-01 12:22:30 -06001730 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass24d0d3c2018-07-17 13:25:47 -06001731 entry_args=entry_args)
1732 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1733 self.assertEqual(expected, data)
1734
1735 def testVblockNoContent(self):
1736 """Test we detect a vblock which has no content to sign"""
1737 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001738 self._DoReadFile('075_vblock_no_content.dts')
Simon Glass189f2912021-03-21 18:24:31 +13001739 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
Simon Glass24d0d3c2018-07-17 13:25:47 -06001740 'property', str(e.exception))
1741
1742 def testVblockBadPhandle(self):
1743 """Test that we detect a vblock with an invalid phandle in contents"""
1744 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001745 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001746 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1747 '1000', str(e.exception))
1748
1749 def testVblockBadEntry(self):
1750 """Test that we detect an entry that points to a non-entry"""
1751 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001752 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001753 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1754 "'other'", str(e.exception))
1755
Simon Glass5af9ebc2021-01-06 21:35:17 -07001756 def testVblockContent(self):
1757 """Test that the vblock signs the right data"""
1758 self._hash_data = True
1759 command.test_result = self._HandleVblockCommand
1760 entry_args = {
1761 'keydir': 'devkeys',
1762 }
1763 data = self._DoReadFileDtb(
1764 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1765 entry_args=entry_args)[0]
1766 hashlen = 32 # SHA256 hash is 32 bytes
1767 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1768 hashval = data[-hashlen:]
1769 dtb = data[len(U_BOOT_DATA):-hashlen]
1770
1771 expected_data = U_BOOT_DATA + dtb
1772
1773 # The hashval should be a hash of the dtb
1774 m = hashlib.sha256()
1775 m.update(expected_data)
1776 expected_hashval = m.digest()
1777 self.assertEqual(expected_hashval, hashval)
1778
Simon Glassb8ef5b62018-07-17 13:25:48 -06001779 def testTpl(self):
Simon Glass2090f1e2019-08-24 07:23:00 -06001780 """Test that an image with TPL and its device tree can be created"""
Simon Glassb8ef5b62018-07-17 13:25:48 -06001781 # ELF file with a '__bss_size' symbol
Simon Glass2090f1e2019-08-24 07:23:00 -06001782 self._SetupTplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001783 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glassb8ef5b62018-07-17 13:25:48 -06001784 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1785
Simon Glass15a587c2018-07-17 13:25:51 -06001786 def testUsesPos(self):
1787 """Test that the 'pos' property cannot be used anymore"""
1788 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001789 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass15a587c2018-07-17 13:25:51 -06001790 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1791 "'pos'", str(e.exception))
1792
Simon Glassd178eab2018-09-14 04:57:08 -06001793 def testFillZero(self):
1794 """Test for an fill entry type with a size of 0"""
Simon Glass741f2d62018-10-01 12:22:30 -06001795 data = self._DoReadFile('080_fill_empty.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001796 self.assertEqual(tools.GetBytes(0, 16), data)
Simon Glassd178eab2018-09-14 04:57:08 -06001797
Simon Glass0b489362018-09-14 04:57:09 -06001798 def testTextMissing(self):
1799 """Test for a text entry type where there is no text"""
1800 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001801 self._DoReadFileDtb('066_text.dts',)
Simon Glass0b489362018-09-14 04:57:09 -06001802 self.assertIn("Node '/binman/text': No value provided for text label "
1803 "'test-id'", str(e.exception))
1804
Simon Glass35b384c2018-09-14 04:57:10 -06001805 def testPackStart16Tpl(self):
1806 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001807 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glass35b384c2018-09-14 04:57:10 -06001808 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1809
Simon Glass0bfa7b02018-09-14 04:57:12 -06001810 def testSelectImage(self):
1811 """Test that we can select which images to build"""
Simon Glasseb833d82019-04-25 21:58:34 -06001812 expected = 'Skipping images: image1'
Simon Glass0bfa7b02018-09-14 04:57:12 -06001813
Simon Glasseb833d82019-04-25 21:58:34 -06001814 # We should only get the expected message in verbose mode
Simon Glassee0c9a72019-07-08 13:18:48 -06001815 for verbosity in (0, 2):
Simon Glasseb833d82019-04-25 21:58:34 -06001816 with test_util.capture_sys_output() as (stdout, stderr):
1817 retcode = self._DoTestFile('006_dual_image.dts',
1818 verbosity=verbosity,
1819 images=['image2'])
1820 self.assertEqual(0, retcode)
1821 if verbosity:
1822 self.assertIn(expected, stdout.getvalue())
1823 else:
1824 self.assertNotIn(expected, stdout.getvalue())
1825
1826 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1827 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
Simon Glassf86a7362019-07-20 12:24:10 -06001828 self._CleanupOutputDir()
Simon Glass0bfa7b02018-09-14 04:57:12 -06001829
Simon Glass6ed45ba2018-09-14 04:57:24 -06001830 def testUpdateFdtAll(self):
1831 """Test that all device trees are updated with offset/size info"""
Simon Glass3c081312019-07-08 14:25:26 -06001832 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glass6ed45ba2018-09-14 04:57:24 -06001833
1834 base_expected = {
1835 'section:image-pos': 0,
1836 'u-boot-tpl-dtb:size': 513,
1837 'u-boot-spl-dtb:size': 513,
1838 'u-boot-spl-dtb:offset': 493,
1839 'image-pos': 0,
1840 'section/u-boot-dtb:image-pos': 0,
1841 'u-boot-spl-dtb:image-pos': 493,
1842 'section/u-boot-dtb:size': 493,
1843 'u-boot-tpl-dtb:image-pos': 1006,
1844 'section/u-boot-dtb:offset': 0,
1845 'section:size': 493,
1846 'offset': 0,
1847 'section:offset': 0,
1848 'u-boot-tpl-dtb:offset': 1006,
1849 'size': 1519
1850 }
1851
1852 # We expect three device-tree files in the output, one after the other.
1853 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1854 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1855 # main U-Boot tree. All three should have the same postions and offset.
1856 start = 0
1857 for item in ['', 'spl', 'tpl']:
1858 dtb = fdt.Fdt.FromData(data[start:])
1859 dtb.Scan()
Simon Glass12bb1a92019-07-20 12:23:51 -06001860 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
1861 ['spl', 'tpl'])
Simon Glass6ed45ba2018-09-14 04:57:24 -06001862 expected = dict(base_expected)
1863 if item:
1864 expected[item] = 0
1865 self.assertEqual(expected, props)
1866 start += dtb._fdt_obj.totalsize()
1867
1868 def testUpdateFdtOutput(self):
1869 """Test that output DTB files are updated"""
1870 try:
Simon Glass741f2d62018-10-01 12:22:30 -06001871 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glass6ed45ba2018-09-14 04:57:24 -06001872 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1873
1874 # Unfortunately, compiling a source file always results in a file
1875 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass741f2d62018-10-01 12:22:30 -06001876 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glass6ed45ba2018-09-14 04:57:24 -06001877 # binman as a file called u-boot.dtb. To fix this, copy the file
1878 # over to the expected place.
Simon Glass6ed45ba2018-09-14 04:57:24 -06001879 start = 0
1880 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1881 'tpl/u-boot-tpl.dtb.out']:
1882 dtb = fdt.Fdt.FromData(data[start:])
1883 size = dtb._fdt_obj.totalsize()
1884 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1885 outdata = tools.ReadFile(pathname)
1886 name = os.path.split(fname)[0]
1887
1888 if name:
1889 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1890 else:
1891 orig_indata = dtb_data
1892 self.assertNotEqual(outdata, orig_indata,
1893 "Expected output file '%s' be updated" % pathname)
1894 self.assertEqual(outdata, data[start:start + size],
1895 "Expected output file '%s' to match output image" %
1896 pathname)
1897 start += size
1898 finally:
1899 self._ResetDtbs()
1900
Simon Glass83d73c22018-09-14 04:57:26 -06001901 def _decompress(self, data):
Simon Glassff5c7e32019-07-08 13:18:42 -06001902 return tools.Decompress(data, 'lz4')
Simon Glass83d73c22018-09-14 04:57:26 -06001903
1904 def testCompress(self):
1905 """Test compression of blobs"""
Simon Glassac62fba2019-07-08 13:18:53 -06001906 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06001907 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass83d73c22018-09-14 04:57:26 -06001908 use_real_dtb=True, update_dtb=True)
1909 dtb = fdt.Fdt(out_dtb_fname)
1910 dtb.Scan()
1911 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1912 orig = self._decompress(data)
1913 self.assertEquals(COMPRESS_DATA, orig)
Simon Glass97c3e9a2020-10-26 17:40:15 -06001914
1915 # Do a sanity check on various fields
1916 image = control.images['image']
1917 entries = image.GetEntries()
1918 self.assertEqual(1, len(entries))
1919
1920 entry = entries['blob']
1921 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
1922 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
1923 orig = self._decompress(entry.data)
1924 self.assertEqual(orig, entry.uncomp_data)
1925
Simon Glass63e7ba62020-10-26 17:40:16 -06001926 self.assertEqual(image.data, entry.data)
1927
Simon Glass83d73c22018-09-14 04:57:26 -06001928 expected = {
1929 'blob:uncomp-size': len(COMPRESS_DATA),
1930 'blob:size': len(data),
1931 'size': len(data),
1932 }
1933 self.assertEqual(expected, props)
1934
Simon Glass0a98b282018-09-14 04:57:28 -06001935 def testFiles(self):
1936 """Test bringing in multiple files"""
Simon Glass741f2d62018-10-01 12:22:30 -06001937 data = self._DoReadFile('084_files.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001938 self.assertEqual(FILES_DATA, data)
1939
1940 def testFilesCompress(self):
1941 """Test bringing in multiple files and compressing them"""
Simon Glassac62fba2019-07-08 13:18:53 -06001942 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06001943 data = self._DoReadFile('085_files_compress.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001944
1945 image = control.images['image']
1946 entries = image.GetEntries()
1947 files = entries['files']
Simon Glass8beb11e2019-07-08 14:25:47 -06001948 entries = files._entries
Simon Glass0a98b282018-09-14 04:57:28 -06001949
Simon Glassc6c10e72019-05-17 22:00:46 -06001950 orig = b''
Simon Glass0a98b282018-09-14 04:57:28 -06001951 for i in range(1, 3):
1952 key = '%d.dat' % i
1953 start = entries[key].image_pos
1954 len = entries[key].size
1955 chunk = data[start:start + len]
1956 orig += self._decompress(chunk)
1957
1958 self.assertEqual(FILES_DATA, orig)
1959
1960 def testFilesMissing(self):
1961 """Test missing files"""
1962 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001963 data = self._DoReadFile('086_files_none.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001964 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1965 'no files', str(e.exception))
1966
1967 def testFilesNoPattern(self):
1968 """Test missing files"""
1969 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001970 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001971 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1972 str(e.exception))
1973
Simon Glassba64a0b2018-09-14 04:57:29 -06001974 def testExpandSize(self):
1975 """Test an expanding entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001976 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
Simon Glassba64a0b2018-09-14 04:57:29 -06001977 map=True)
Simon Glassc6c10e72019-05-17 22:00:46 -06001978 expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA +
1979 MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA +
1980 tools.GetBytes(ord('c'), 8) + U_BOOT_DATA +
1981 tools.GetBytes(ord('d'), 8))
Simon Glassba64a0b2018-09-14 04:57:29 -06001982 self.assertEqual(expect, data)
1983 self.assertEqual('''ImagePos Offset Size Name
198400000000 00000000 00000028 main-section
198500000000 00000000 00000008 fill
198600000008 00000008 00000004 u-boot
19870000000c 0000000c 00000004 section
19880000000c 00000000 00000003 intel-mrc
198900000010 00000010 00000004 u-boot2
199000000014 00000014 0000000c section2
199100000014 00000000 00000008 fill
19920000001c 00000008 00000004 u-boot
199300000020 00000020 00000008 fill2
1994''', map_data)
1995
1996 def testExpandSizeBad(self):
1997 """Test an expanding entry which fails to provide contents"""
Simon Glass163ed6c2018-09-14 04:57:36 -06001998 with test_util.capture_sys_output() as (stdout, stderr):
1999 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002000 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
Simon Glassba64a0b2018-09-14 04:57:29 -06002001 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
2002 'expanding entry', str(e.exception))
2003
Simon Glasse0e5df92018-09-14 04:57:31 -06002004 def testHash(self):
2005 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06002006 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06002007 use_real_dtb=True, update_dtb=True)
2008 dtb = fdt.Fdt(out_dtb_fname)
2009 dtb.Scan()
2010 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
2011 m = hashlib.sha256()
2012 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06002013 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06002014
2015 def testHashNoAlgo(self):
2016 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002017 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06002018 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2019 'hash node', str(e.exception))
2020
2021 def testHashBadAlgo(self):
2022 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002023 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06002024 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
2025 str(e.exception))
2026
2027 def testHashSection(self):
2028 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06002029 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06002030 use_real_dtb=True, update_dtb=True)
2031 dtb = fdt.Fdt(out_dtb_fname)
2032 dtb.Scan()
2033 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2034 m = hashlib.sha256()
2035 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06002036 m.update(tools.GetBytes(ord('a'), 16))
2037 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06002038
Simon Glassf0253632018-09-14 04:57:32 -06002039 def testPackUBootTplMicrocode(self):
2040 """Test that x86 microcode can be handled correctly in TPL
2041
2042 We expect to see the following in the image, in order:
2043 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2044 place
2045 u-boot-tpl.dtb with the microcode removed
2046 the microcode
2047 """
Simon Glass2090f1e2019-08-24 07:23:00 -06002048 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass741f2d62018-10-01 12:22:30 -06002049 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glassf0253632018-09-14 04:57:32 -06002050 U_BOOT_TPL_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06002051 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2052 b'ter somewhere in here', first)
Simon Glassf0253632018-09-14 04:57:32 -06002053
Simon Glassf8f8df62018-09-14 04:57:34 -06002054 def testFmapX86(self):
2055 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06002056 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassf8f8df62018-09-14 04:57:34 -06002057 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc6c10e72019-05-17 22:00:46 -06002058 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06002059 self.assertEqual(expected, data[:32])
2060 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2061
2062 self.assertEqual(0x100, fhdr.image_size)
2063
2064 self.assertEqual(0, fentries[0].offset)
2065 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06002066 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06002067
2068 self.assertEqual(4, fentries[1].offset)
2069 self.assertEqual(3, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06002070 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06002071
2072 self.assertEqual(32, fentries[2].offset)
2073 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2074 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06002075 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06002076
2077 def testFmapX86Section(self):
2078 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06002079 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glassc6c10e72019-05-17 22:00:46 -06002080 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06002081 self.assertEqual(expected, data[:32])
2082 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2083
Simon Glass17365752021-04-03 11:05:10 +13002084 self.assertEqual(0x180, fhdr.image_size)
2085 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
Simon Glassc7722e82021-04-03 11:05:09 +13002086 fiter = iter(fentries)
Simon Glassf8f8df62018-09-14 04:57:34 -06002087
Simon Glassc7722e82021-04-03 11:05:09 +13002088 fentry = next(fiter)
2089 self.assertEqual(b'U_BOOT', fentry.name)
2090 self.assertEqual(0, fentry.offset)
2091 self.assertEqual(4, fentry.size)
Simon Glassf8f8df62018-09-14 04:57:34 -06002092
Simon Glassc7722e82021-04-03 11:05:09 +13002093 fentry = next(fiter)
Simon Glass17365752021-04-03 11:05:10 +13002094 self.assertEqual(b'SECTION', fentry.name)
2095 self.assertEqual(4, fentry.offset)
2096 self.assertEqual(0x20 + expect_size, fentry.size)
2097
2098 fentry = next(fiter)
Simon Glassc7722e82021-04-03 11:05:09 +13002099 self.assertEqual(b'INTEL_MRC', fentry.name)
2100 self.assertEqual(4, fentry.offset)
2101 self.assertEqual(3, fentry.size)
Simon Glassf8f8df62018-09-14 04:57:34 -06002102
Simon Glassc7722e82021-04-03 11:05:09 +13002103 fentry = next(fiter)
2104 self.assertEqual(b'FMAP', fentry.name)
2105 self.assertEqual(36, fentry.offset)
2106 self.assertEqual(expect_size, fentry.size)
Simon Glassf8f8df62018-09-14 04:57:34 -06002107
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002108 def testElf(self):
2109 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06002110 self._SetupSplElf()
Simon Glass2090f1e2019-08-24 07:23:00 -06002111 self._SetupTplElf()
Simon Glass53e22bf2019-08-24 07:22:53 -06002112 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002113 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06002114 data = self._DoReadFile('096_elf.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002115
Simon Glass093d1682019-07-08 13:18:25 -06002116 def testElfStrip(self):
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002117 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06002118 self._SetupSplElf()
Simon Glass53e22bf2019-08-24 07:22:53 -06002119 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002120 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06002121 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002122
Simon Glass163ed6c2018-09-14 04:57:36 -06002123 def testPackOverlapMap(self):
2124 """Test that overlapping regions are detected"""
2125 with test_util.capture_sys_output() as (stdout, stderr):
2126 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002127 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glass163ed6c2018-09-14 04:57:36 -06002128 map_fname = tools.GetOutputFilename('image.map')
2129 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2130 stdout.getvalue())
2131
2132 # We should not get an inmage, but there should be a map file
2133 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
2134 self.assertTrue(os.path.exists(map_fname))
Simon Glasseb546ac2019-05-17 22:00:51 -06002135 map_data = tools.ReadFile(map_fname, binary=False)
Simon Glass163ed6c2018-09-14 04:57:36 -06002136 self.assertEqual('''ImagePos Offset Size Name
Simon Glass0ff83da2020-10-26 17:40:24 -06002137<none> 00000000 00000008 main-section
Simon Glass163ed6c2018-09-14 04:57:36 -06002138<none> 00000000 00000004 u-boot
2139<none> 00000003 00000004 u-boot-align
2140''', map_data)
2141
Simon Glass093d1682019-07-08 13:18:25 -06002142 def testPackRefCode(self):
Simon Glass3ae192c2018-10-01 12:22:31 -06002143 """Test that an image with an Intel Reference code binary works"""
2144 data = self._DoReadFile('100_intel_refcode.dts')
2145 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2146
Simon Glass9481c802019-04-25 21:58:39 -06002147 def testSectionOffset(self):
2148 """Tests use of a section with an offset"""
2149 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2150 map=True)
2151 self.assertEqual('''ImagePos Offset Size Name
215200000000 00000000 00000038 main-section
215300000004 00000004 00000010 section@0
215400000004 00000000 00000004 u-boot
215500000018 00000018 00000010 section@1
215600000018 00000000 00000004 u-boot
21570000002c 0000002c 00000004 section@2
21580000002c 00000000 00000004 u-boot
2159''', map_data)
2160 self.assertEqual(data,
Simon Glasse6d85ff2019-05-14 15:53:47 -06002161 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2162 tools.GetBytes(0x21, 12) +
2163 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2164 tools.GetBytes(0x61, 12) +
2165 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2166 tools.GetBytes(0x26, 8))
Simon Glass9481c802019-04-25 21:58:39 -06002167
Simon Glassac62fba2019-07-08 13:18:53 -06002168 def testCbfsRaw(self):
2169 """Test base handling of a Coreboot Filesystem (CBFS)
2170
2171 The exact contents of the CBFS is verified by similar tests in
2172 cbfs_util_test.py. The tests here merely check that the files added to
2173 the CBFS can be found in the final image.
2174 """
2175 data = self._DoReadFile('102_cbfs_raw.dts')
2176 size = 0xb0
2177
2178 cbfs = cbfs_util.CbfsReader(data)
2179 self.assertEqual(size, cbfs.rom_size)
2180
2181 self.assertIn('u-boot-dtb', cbfs.files)
2182 cfile = cbfs.files['u-boot-dtb']
2183 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2184
2185 def testCbfsArch(self):
2186 """Test on non-x86 architecture"""
2187 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2188 size = 0x100
2189
2190 cbfs = cbfs_util.CbfsReader(data)
2191 self.assertEqual(size, cbfs.rom_size)
2192
2193 self.assertIn('u-boot-dtb', cbfs.files)
2194 cfile = cbfs.files['u-boot-dtb']
2195 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2196
2197 def testCbfsStage(self):
2198 """Tests handling of a Coreboot Filesystem (CBFS)"""
2199 if not elf.ELF_TOOLS:
2200 self.skipTest('Python elftools not available')
2201 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2202 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2203 size = 0xb0
2204
2205 data = self._DoReadFile('104_cbfs_stage.dts')
2206 cbfs = cbfs_util.CbfsReader(data)
2207 self.assertEqual(size, cbfs.rom_size)
2208
2209 self.assertIn('u-boot', cbfs.files)
2210 cfile = cbfs.files['u-boot']
2211 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2212
2213 def testCbfsRawCompress(self):
2214 """Test handling of compressing raw files"""
2215 self._CheckLz4()
2216 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2217 size = 0x140
2218
2219 cbfs = cbfs_util.CbfsReader(data)
2220 self.assertIn('u-boot', cbfs.files)
2221 cfile = cbfs.files['u-boot']
2222 self.assertEqual(COMPRESS_DATA, cfile.data)
2223
2224 def testCbfsBadArch(self):
2225 """Test handling of a bad architecture"""
2226 with self.assertRaises(ValueError) as e:
2227 self._DoReadFile('106_cbfs_bad_arch.dts')
2228 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2229
2230 def testCbfsNoSize(self):
2231 """Test handling of a missing size property"""
2232 with self.assertRaises(ValueError) as e:
2233 self._DoReadFile('107_cbfs_no_size.dts')
2234 self.assertIn('entry must have a size property', str(e.exception))
2235
2236 def testCbfsNoCOntents(self):
2237 """Test handling of a CBFS entry which does not provide contentsy"""
2238 with self.assertRaises(ValueError) as e:
2239 self._DoReadFile('108_cbfs_no_contents.dts')
2240 self.assertIn('Could not complete processing of contents',
2241 str(e.exception))
2242
2243 def testCbfsBadCompress(self):
2244 """Test handling of a bad architecture"""
2245 with self.assertRaises(ValueError) as e:
2246 self._DoReadFile('109_cbfs_bad_compress.dts')
2247 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2248 str(e.exception))
2249
2250 def testCbfsNamedEntries(self):
2251 """Test handling of named entries"""
2252 data = self._DoReadFile('110_cbfs_name.dts')
2253
2254 cbfs = cbfs_util.CbfsReader(data)
2255 self.assertIn('FRED', cbfs.files)
2256 cfile1 = cbfs.files['FRED']
2257 self.assertEqual(U_BOOT_DATA, cfile1.data)
2258
2259 self.assertIn('hello', cbfs.files)
2260 cfile2 = cbfs.files['hello']
2261 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2262
Simon Glassc5ac1382019-07-08 13:18:54 -06002263 def _SetupIfwi(self, fname):
2264 """Set up to run an IFWI test
2265
2266 Args:
2267 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2268 """
2269 self._SetupSplElf()
Simon Glass2090f1e2019-08-24 07:23:00 -06002270 self._SetupTplElf()
Simon Glassc5ac1382019-07-08 13:18:54 -06002271
2272 # Intel Integrated Firmware Image (IFWI) file
2273 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2274 data = fd.read()
2275 TestFunctional._MakeInputFile(fname,data)
2276
2277 def _CheckIfwi(self, data):
2278 """Check that an image with an IFWI contains the correct output
2279
2280 Args:
2281 data: Conents of output file
2282 """
2283 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
2284 if data[:0x1000] != expected_desc:
2285 self.fail('Expected descriptor binary at start of image')
2286
2287 # We expect to find the TPL wil in subpart IBBP entry IBBL
2288 image_fname = tools.GetOutputFilename('image.bin')
2289 tpl_fname = tools.GetOutputFilename('tpl.out')
2290 tools.RunIfwiTool(image_fname, tools.CMD_EXTRACT, fname=tpl_fname,
2291 subpart='IBBP', entry_name='IBBL')
2292
2293 tpl_data = tools.ReadFile(tpl_fname)
Simon Glasse95be632019-08-24 07:22:51 -06002294 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glassc5ac1382019-07-08 13:18:54 -06002295
2296 def testPackX86RomIfwi(self):
2297 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2298 self._SetupIfwi('fitimage.bin')
Simon Glass9255f3c2019-08-24 07:23:01 -06002299 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002300 self._CheckIfwi(data)
2301
2302 def testPackX86RomIfwiNoDesc(self):
2303 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2304 self._SetupIfwi('ifwi.bin')
Simon Glass9255f3c2019-08-24 07:23:01 -06002305 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002306 self._CheckIfwi(data)
2307
2308 def testPackX86RomIfwiNoData(self):
2309 """Test that an x86 ROM with IFWI handles missing data"""
2310 self._SetupIfwi('ifwi.bin')
2311 with self.assertRaises(ValueError) as e:
Simon Glass9255f3c2019-08-24 07:23:01 -06002312 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002313 self.assertIn('Could not complete processing of contents',
2314 str(e.exception))
Simon Glass53af22a2018-07-17 13:25:32 -06002315
Simon Glasse073d4e2019-07-08 13:18:56 -06002316 def testCbfsOffset(self):
2317 """Test a CBFS with files at particular offsets
2318
2319 Like all CFBS tests, this is just checking the logic that calls
2320 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2321 """
2322 data = self._DoReadFile('114_cbfs_offset.dts')
2323 size = 0x200
2324
2325 cbfs = cbfs_util.CbfsReader(data)
2326 self.assertEqual(size, cbfs.rom_size)
2327
2328 self.assertIn('u-boot', cbfs.files)
2329 cfile = cbfs.files['u-boot']
2330 self.assertEqual(U_BOOT_DATA, cfile.data)
2331 self.assertEqual(0x40, cfile.cbfs_offset)
2332
2333 self.assertIn('u-boot-dtb', cbfs.files)
2334 cfile2 = cbfs.files['u-boot-dtb']
2335 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2336 self.assertEqual(0x140, cfile2.cbfs_offset)
2337
Simon Glass086cec92019-07-08 14:25:27 -06002338 def testFdtmap(self):
2339 """Test an FDT map can be inserted in the image"""
2340 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2341 fdtmap_data = data[len(U_BOOT_DATA):]
2342 magic = fdtmap_data[:8]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002343 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass086cec92019-07-08 14:25:27 -06002344 self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
2345
2346 fdt_data = fdtmap_data[16:]
2347 dtb = fdt.Fdt.FromData(fdt_data)
2348 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002349 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass086cec92019-07-08 14:25:27 -06002350 self.assertEqual({
2351 'image-pos': 0,
2352 'offset': 0,
2353 'u-boot:offset': 0,
2354 'u-boot:size': len(U_BOOT_DATA),
2355 'u-boot:image-pos': 0,
2356 'fdtmap:image-pos': 4,
2357 'fdtmap:offset': 4,
2358 'fdtmap:size': len(fdtmap_data),
2359 'size': len(data),
2360 }, props)
2361
2362 def testFdtmapNoMatch(self):
2363 """Check handling of an FDT map when the section cannot be found"""
2364 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2365
2366 # Mangle the section name, which should cause a mismatch between the
2367 # correct FDT path and the one expected by the section
2368 image = control.images['image']
Simon Glasscf228942019-07-08 14:25:28 -06002369 image._node.path += '-suffix'
Simon Glass086cec92019-07-08 14:25:27 -06002370 entries = image.GetEntries()
2371 fdtmap = entries['fdtmap']
2372 with self.assertRaises(ValueError) as e:
2373 fdtmap._GetFdtmap()
2374 self.assertIn("Cannot locate node for path '/binman-suffix'",
2375 str(e.exception))
2376
Simon Glasscf228942019-07-08 14:25:28 -06002377 def testFdtmapHeader(self):
2378 """Test an FDT map and image header can be inserted in the image"""
2379 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2380 fdtmap_pos = len(U_BOOT_DATA)
2381 fdtmap_data = data[fdtmap_pos:]
2382 fdt_data = fdtmap_data[16:]
2383 dtb = fdt.Fdt.FromData(fdt_data)
2384 fdt_size = dtb.GetFdtObj().totalsize()
2385 hdr_data = data[-8:]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002386 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002387 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2388 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2389
2390 def testFdtmapHeaderStart(self):
2391 """Test an image header can be inserted at the image start"""
2392 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2393 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2394 hdr_data = data[:8]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002395 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002396 offset = struct.unpack('<I', hdr_data[4:])[0]
2397 self.assertEqual(fdtmap_pos, offset)
2398
2399 def testFdtmapHeaderPos(self):
2400 """Test an image header can be inserted at a chosen position"""
2401 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2402 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2403 hdr_data = data[0x80:0x88]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002404 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002405 offset = struct.unpack('<I', hdr_data[4:])[0]
2406 self.assertEqual(fdtmap_pos, offset)
2407
2408 def testHeaderMissingFdtmap(self):
2409 """Test an image header requires an fdtmap"""
2410 with self.assertRaises(ValueError) as e:
2411 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2412 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2413 str(e.exception))
2414
2415 def testHeaderNoLocation(self):
2416 """Test an image header with a no specified location is detected"""
2417 with self.assertRaises(ValueError) as e:
2418 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2419 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2420 str(e.exception))
2421
Simon Glassc52c9e72019-07-08 14:25:37 -06002422 def testEntryExpand(self):
2423 """Test expanding an entry after it is packed"""
2424 data = self._DoReadFile('121_entry_expand.dts')
Simon Glass79d3c582019-07-20 12:23:57 -06002425 self.assertEqual(b'aaa', data[:3])
2426 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2427 self.assertEqual(b'aaa', data[-3:])
Simon Glassc52c9e72019-07-08 14:25:37 -06002428
2429 def testEntryExpandBad(self):
2430 """Test expanding an entry after it is packed, twice"""
2431 with self.assertRaises(ValueError) as e:
2432 self._DoReadFile('122_entry_expand_twice.dts')
Simon Glass61ec04f2019-07-20 12:23:58 -06002433 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glassc52c9e72019-07-08 14:25:37 -06002434 str(e.exception))
2435
2436 def testEntryExpandSection(self):
2437 """Test expanding an entry within a section after it is packed"""
2438 data = self._DoReadFile('123_entry_expand_section.dts')
Simon Glass79d3c582019-07-20 12:23:57 -06002439 self.assertEqual(b'aaa', data[:3])
2440 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2441 self.assertEqual(b'aaa', data[-3:])
Simon Glassc52c9e72019-07-08 14:25:37 -06002442
Simon Glass6c223fd2019-07-08 14:25:38 -06002443 def testCompressDtb(self):
2444 """Test that compress of device-tree files is supported"""
2445 self._CheckLz4()
2446 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2447 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2448 comp_data = data[len(U_BOOT_DATA):]
2449 orig = self._decompress(comp_data)
2450 dtb = fdt.Fdt.FromData(orig)
2451 dtb.Scan()
2452 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2453 expected = {
2454 'u-boot:size': len(U_BOOT_DATA),
2455 'u-boot-dtb:uncomp-size': len(orig),
2456 'u-boot-dtb:size': len(comp_data),
2457 'size': len(data),
2458 }
2459 self.assertEqual(expected, props)
2460
Simon Glass69f7cb32019-07-08 14:25:41 -06002461 def testCbfsUpdateFdt(self):
2462 """Test that we can update the device tree with CBFS offset/size info"""
2463 self._CheckLz4()
2464 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2465 update_dtb=True)
2466 dtb = fdt.Fdt(out_dtb_fname)
2467 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002468 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass69f7cb32019-07-08 14:25:41 -06002469 del props['cbfs/u-boot:size']
2470 self.assertEqual({
2471 'offset': 0,
2472 'size': len(data),
2473 'image-pos': 0,
2474 'cbfs:offset': 0,
2475 'cbfs:size': len(data),
2476 'cbfs:image-pos': 0,
2477 'cbfs/u-boot:offset': 0x38,
2478 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2479 'cbfs/u-boot:image-pos': 0x38,
2480 'cbfs/u-boot-dtb:offset': 0xb8,
2481 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2482 'cbfs/u-boot-dtb:image-pos': 0xb8,
2483 }, props)
2484
Simon Glass8a1ad062019-07-08 14:25:42 -06002485 def testCbfsBadType(self):
2486 """Test an image header with a no specified location is detected"""
2487 with self.assertRaises(ValueError) as e:
2488 self._DoReadFile('126_cbfs_bad_type.dts')
2489 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2490
Simon Glass41b8ba02019-07-08 14:25:43 -06002491 def testList(self):
2492 """Test listing the files in an image"""
2493 self._CheckLz4()
2494 data = self._DoReadFile('127_list.dts')
2495 image = control.images['image']
2496 entries = image.BuildEntryList()
2497 self.assertEqual(7, len(entries))
2498
2499 ent = entries[0]
2500 self.assertEqual(0, ent.indent)
2501 self.assertEqual('main-section', ent.name)
2502 self.assertEqual('section', ent.etype)
2503 self.assertEqual(len(data), ent.size)
2504 self.assertEqual(0, ent.image_pos)
2505 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002506 self.assertEqual(0, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002507
2508 ent = entries[1]
2509 self.assertEqual(1, ent.indent)
2510 self.assertEqual('u-boot', ent.name)
2511 self.assertEqual('u-boot', ent.etype)
2512 self.assertEqual(len(U_BOOT_DATA), ent.size)
2513 self.assertEqual(0, ent.image_pos)
2514 self.assertEqual(None, ent.uncomp_size)
2515 self.assertEqual(0, ent.offset)
2516
2517 ent = entries[2]
2518 self.assertEqual(1, ent.indent)
2519 self.assertEqual('section', ent.name)
2520 self.assertEqual('section', ent.etype)
2521 section_size = ent.size
2522 self.assertEqual(0x100, ent.image_pos)
2523 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002524 self.assertEqual(0x100, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002525
2526 ent = entries[3]
2527 self.assertEqual(2, ent.indent)
2528 self.assertEqual('cbfs', ent.name)
2529 self.assertEqual('cbfs', ent.etype)
2530 self.assertEqual(0x400, ent.size)
2531 self.assertEqual(0x100, ent.image_pos)
2532 self.assertEqual(None, ent.uncomp_size)
2533 self.assertEqual(0, ent.offset)
2534
2535 ent = entries[4]
2536 self.assertEqual(3, ent.indent)
2537 self.assertEqual('u-boot', ent.name)
2538 self.assertEqual('u-boot', ent.etype)
2539 self.assertEqual(len(U_BOOT_DATA), ent.size)
2540 self.assertEqual(0x138, ent.image_pos)
2541 self.assertEqual(None, ent.uncomp_size)
2542 self.assertEqual(0x38, ent.offset)
2543
2544 ent = entries[5]
2545 self.assertEqual(3, ent.indent)
2546 self.assertEqual('u-boot-dtb', ent.name)
2547 self.assertEqual('text', ent.etype)
2548 self.assertGreater(len(COMPRESS_DATA), ent.size)
2549 self.assertEqual(0x178, ent.image_pos)
2550 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2551 self.assertEqual(0x78, ent.offset)
2552
2553 ent = entries[6]
2554 self.assertEqual(2, ent.indent)
2555 self.assertEqual('u-boot-dtb', ent.name)
2556 self.assertEqual('u-boot-dtb', ent.etype)
2557 self.assertEqual(0x500, ent.image_pos)
2558 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2559 dtb_size = ent.size
2560 # Compressing this data expands it since headers are added
2561 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2562 self.assertEqual(0x400, ent.offset)
2563
2564 self.assertEqual(len(data), 0x100 + section_size)
2565 self.assertEqual(section_size, 0x400 + dtb_size)
2566
Simon Glasse1925fa2019-07-08 14:25:44 -06002567 def testFindFdtmap(self):
2568 """Test locating an FDT map in an image"""
2569 self._CheckLz4()
2570 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2571 image = control.images['image']
2572 entries = image.GetEntries()
2573 entry = entries['fdtmap']
2574 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2575
2576 def testFindFdtmapMissing(self):
2577 """Test failing to locate an FDP map"""
2578 data = self._DoReadFile('005_simple.dts')
2579 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2580
Simon Glass2d260032019-07-08 14:25:45 -06002581 def testFindImageHeader(self):
2582 """Test locating a image header"""
2583 self._CheckLz4()
Simon Glassffded752019-07-08 14:25:46 -06002584 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002585 image = control.images['image']
2586 entries = image.GetEntries()
2587 entry = entries['fdtmap']
2588 # The header should point to the FDT map
2589 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2590
2591 def testFindImageHeaderStart(self):
2592 """Test locating a image header located at the start of an image"""
Simon Glassffded752019-07-08 14:25:46 -06002593 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002594 image = control.images['image']
2595 entries = image.GetEntries()
2596 entry = entries['fdtmap']
2597 # The header should point to the FDT map
2598 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2599
2600 def testFindImageHeaderMissing(self):
2601 """Test failing to locate an image header"""
2602 data = self._DoReadFile('005_simple.dts')
2603 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2604
Simon Glassffded752019-07-08 14:25:46 -06002605 def testReadImage(self):
2606 """Test reading an image and accessing its FDT map"""
2607 self._CheckLz4()
2608 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2609 image_fname = tools.GetOutputFilename('image.bin')
2610 orig_image = control.images['image']
2611 image = Image.FromFile(image_fname)
2612 self.assertEqual(orig_image.GetEntries().keys(),
2613 image.GetEntries().keys())
2614
2615 orig_entry = orig_image.GetEntries()['fdtmap']
2616 entry = image.GetEntries()['fdtmap']
2617 self.assertEquals(orig_entry.offset, entry.offset)
2618 self.assertEquals(orig_entry.size, entry.size)
2619 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2620
2621 def testReadImageNoHeader(self):
2622 """Test accessing an image's FDT map without an image header"""
2623 self._CheckLz4()
2624 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
2625 image_fname = tools.GetOutputFilename('image.bin')
2626 image = Image.FromFile(image_fname)
2627 self.assertTrue(isinstance(image, Image))
Simon Glass10f9d002019-07-20 12:23:50 -06002628 self.assertEqual('image', image.image_name[-5:])
Simon Glassffded752019-07-08 14:25:46 -06002629
2630 def testReadImageFail(self):
2631 """Test failing to read an image image's FDT map"""
2632 self._DoReadFile('005_simple.dts')
2633 image_fname = tools.GetOutputFilename('image.bin')
2634 with self.assertRaises(ValueError) as e:
2635 image = Image.FromFile(image_fname)
2636 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glasse073d4e2019-07-08 13:18:56 -06002637
Simon Glass61f564d2019-07-08 14:25:48 -06002638 def testListCmd(self):
2639 """Test listing the files in an image using an Fdtmap"""
2640 self._CheckLz4()
2641 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2642
2643 # lz4 compression size differs depending on the version
2644 image = control.images['image']
2645 entries = image.GetEntries()
2646 section_size = entries['section'].size
2647 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2648 fdtmap_offset = entries['fdtmap'].offset
2649
Simon Glassf86a7362019-07-20 12:24:10 -06002650 try:
2651 tmpdir, updated_fname = self._SetupImageInTmpdir()
2652 with test_util.capture_sys_output() as (stdout, stderr):
2653 self._DoBinman('ls', '-i', updated_fname)
2654 finally:
2655 shutil.rmtree(tmpdir)
Simon Glass61f564d2019-07-08 14:25:48 -06002656 lines = stdout.getvalue().splitlines()
2657 expected = [
2658'Name Image-pos Size Entry-type Offset Uncomp-size',
2659'----------------------------------------------------------------------',
2660'main-section 0 c00 section 0',
2661' u-boot 0 4 u-boot 0',
2662' section 100 %x section 100' % section_size,
2663' cbfs 100 400 cbfs 0',
2664' u-boot 138 4 u-boot 38',
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002665' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glass61f564d2019-07-08 14:25:48 -06002666' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002667' fdtmap %x 3bd fdtmap %x' %
Simon Glass61f564d2019-07-08 14:25:48 -06002668 (fdtmap_offset, fdtmap_offset),
2669' image-header bf8 8 image-header bf8',
2670 ]
2671 self.assertEqual(expected, lines)
2672
2673 def testListCmdFail(self):
2674 """Test failing to list an image"""
2675 self._DoReadFile('005_simple.dts')
Simon Glassf86a7362019-07-20 12:24:10 -06002676 try:
2677 tmpdir, updated_fname = self._SetupImageInTmpdir()
2678 with self.assertRaises(ValueError) as e:
2679 self._DoBinman('ls', '-i', updated_fname)
2680 finally:
2681 shutil.rmtree(tmpdir)
Simon Glass61f564d2019-07-08 14:25:48 -06002682 self.assertIn("Cannot find FDT map in image", str(e.exception))
2683
2684 def _RunListCmd(self, paths, expected):
2685 """List out entries and check the result
2686
2687 Args:
2688 paths: List of paths to pass to the list command
2689 expected: Expected list of filenames to be returned, in order
2690 """
2691 self._CheckLz4()
2692 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2693 image_fname = tools.GetOutputFilename('image.bin')
2694 image = Image.FromFile(image_fname)
2695 lines = image.GetListEntries(paths)[1]
2696 files = [line[0].strip() for line in lines[1:]]
2697 self.assertEqual(expected, files)
2698
2699 def testListCmdSection(self):
2700 """Test listing the files in a section"""
2701 self._RunListCmd(['section'],
2702 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2703
2704 def testListCmdFile(self):
2705 """Test listing a particular file"""
2706 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2707
2708 def testListCmdWildcard(self):
2709 """Test listing a wildcarded file"""
2710 self._RunListCmd(['*boot*'],
2711 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2712
2713 def testListCmdWildcardMulti(self):
2714 """Test listing a wildcarded file"""
2715 self._RunListCmd(['*cb*', '*head*'],
2716 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2717
2718 def testListCmdEmpty(self):
2719 """Test listing a wildcarded file"""
2720 self._RunListCmd(['nothing'], [])
2721
2722 def testListCmdPath(self):
2723 """Test listing the files in a sub-entry of a section"""
2724 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2725
Simon Glassf667e452019-07-08 14:25:50 -06002726 def _RunExtractCmd(self, entry_name, decomp=True):
2727 """Extract an entry from an image
2728
2729 Args:
2730 entry_name: Entry name to extract
2731 decomp: True to decompress the data if compressed, False to leave
2732 it in its raw uncompressed format
2733
2734 Returns:
2735 data from entry
2736 """
2737 self._CheckLz4()
2738 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2739 image_fname = tools.GetOutputFilename('image.bin')
2740 return control.ReadEntry(image_fname, entry_name, decomp)
2741
2742 def testExtractSimple(self):
2743 """Test extracting a single file"""
2744 data = self._RunExtractCmd('u-boot')
2745 self.assertEqual(U_BOOT_DATA, data)
2746
Simon Glass71ce0ba2019-07-08 14:25:52 -06002747 def testExtractSection(self):
2748 """Test extracting the files in a section"""
2749 data = self._RunExtractCmd('section')
2750 cbfs_data = data[:0x400]
2751 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002752 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass71ce0ba2019-07-08 14:25:52 -06002753 dtb_data = data[0x400:]
2754 dtb = self._decompress(dtb_data)
2755 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2756
2757 def testExtractCompressed(self):
2758 """Test extracting compressed data"""
2759 data = self._RunExtractCmd('section/u-boot-dtb')
2760 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2761
2762 def testExtractRaw(self):
2763 """Test extracting compressed data without decompressing it"""
2764 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2765 dtb = self._decompress(data)
2766 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2767
2768 def testExtractCbfs(self):
2769 """Test extracting CBFS data"""
2770 data = self._RunExtractCmd('section/cbfs/u-boot')
2771 self.assertEqual(U_BOOT_DATA, data)
2772
2773 def testExtractCbfsCompressed(self):
2774 """Test extracting CBFS compressed data"""
2775 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2776 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2777
2778 def testExtractCbfsRaw(self):
2779 """Test extracting CBFS compressed data without decompressing it"""
2780 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Simon Glasseb0f4a42019-07-20 12:24:06 -06002781 dtb = tools.Decompress(data, 'lzma', with_header=False)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002782 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2783
Simon Glassf667e452019-07-08 14:25:50 -06002784 def testExtractBadEntry(self):
2785 """Test extracting a bad section path"""
2786 with self.assertRaises(ValueError) as e:
2787 self._RunExtractCmd('section/does-not-exist')
2788 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2789 str(e.exception))
2790
2791 def testExtractMissingFile(self):
2792 """Test extracting file that does not exist"""
2793 with self.assertRaises(IOError) as e:
2794 control.ReadEntry('missing-file', 'name')
2795
2796 def testExtractBadFile(self):
2797 """Test extracting an invalid file"""
2798 fname = os.path.join(self._indir, 'badfile')
2799 tools.WriteFile(fname, b'')
2800 with self.assertRaises(ValueError) as e:
2801 control.ReadEntry(fname, 'name')
2802
Simon Glass71ce0ba2019-07-08 14:25:52 -06002803 def testExtractCmd(self):
2804 """Test extracting a file fron an image on the command line"""
2805 self._CheckLz4()
2806 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass71ce0ba2019-07-08 14:25:52 -06002807 fname = os.path.join(self._indir, 'output.extact')
Simon Glassf86a7362019-07-20 12:24:10 -06002808 try:
2809 tmpdir, updated_fname = self._SetupImageInTmpdir()
2810 with test_util.capture_sys_output() as (stdout, stderr):
2811 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2812 '-f', fname)
2813 finally:
2814 shutil.rmtree(tmpdir)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002815 data = tools.ReadFile(fname)
2816 self.assertEqual(U_BOOT_DATA, data)
2817
2818 def testExtractOneEntry(self):
2819 """Test extracting a single entry fron an image """
2820 self._CheckLz4()
2821 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2822 image_fname = tools.GetOutputFilename('image.bin')
2823 fname = os.path.join(self._indir, 'output.extact')
2824 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
2825 data = tools.ReadFile(fname)
2826 self.assertEqual(U_BOOT_DATA, data)
2827
2828 def _CheckExtractOutput(self, decomp):
2829 """Helper to test file output with and without decompression
2830
2831 Args:
2832 decomp: True to decompress entry data, False to output it raw
2833 """
2834 def _CheckPresent(entry_path, expect_data, expect_size=None):
2835 """Check and remove expected file
2836
2837 This checks the data/size of a file and removes the file both from
2838 the outfiles set and from the output directory. Once all files are
2839 processed, both the set and directory should be empty.
2840
2841 Args:
2842 entry_path: Entry path
2843 expect_data: Data to expect in file, or None to skip check
2844 expect_size: Size of data to expect in file, or None to skip
2845 """
2846 path = os.path.join(outdir, entry_path)
2847 data = tools.ReadFile(path)
2848 os.remove(path)
2849 if expect_data:
2850 self.assertEqual(expect_data, data)
2851 elif expect_size:
2852 self.assertEqual(expect_size, len(data))
2853 outfiles.remove(path)
2854
2855 def _CheckDirPresent(name):
2856 """Remove expected directory
2857
2858 This gives an error if the directory does not exist as expected
2859
2860 Args:
2861 name: Name of directory to remove
2862 """
2863 path = os.path.join(outdir, name)
2864 os.rmdir(path)
2865
2866 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2867 image_fname = tools.GetOutputFilename('image.bin')
2868 outdir = os.path.join(self._indir, 'extract')
2869 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2870
2871 # Create a set of all file that were output (should be 9)
2872 outfiles = set()
2873 for root, dirs, files in os.walk(outdir):
2874 outfiles |= set([os.path.join(root, fname) for fname in files])
2875 self.assertEqual(9, len(outfiles))
2876 self.assertEqual(9, len(einfos))
2877
2878 image = control.images['image']
2879 entries = image.GetEntries()
2880
2881 # Check the 9 files in various ways
2882 section = entries['section']
2883 section_entries = section.GetEntries()
2884 cbfs_entries = section_entries['cbfs'].GetEntries()
2885 _CheckPresent('u-boot', U_BOOT_DATA)
2886 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
2887 dtb_len = EXTRACT_DTB_SIZE
2888 if not decomp:
2889 dtb_len = cbfs_entries['u-boot-dtb'].size
2890 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
2891 if not decomp:
2892 dtb_len = section_entries['u-boot-dtb'].size
2893 _CheckPresent('section/u-boot-dtb', None, dtb_len)
2894
2895 fdtmap = entries['fdtmap']
2896 _CheckPresent('fdtmap', fdtmap.data)
2897 hdr = entries['image-header']
2898 _CheckPresent('image-header', hdr.data)
2899
2900 _CheckPresent('section/root', section.data)
2901 cbfs = section_entries['cbfs']
2902 _CheckPresent('section/cbfs/root', cbfs.data)
2903 data = tools.ReadFile(image_fname)
2904 _CheckPresent('root', data)
2905
2906 # There should be no files left. Remove all the directories to check.
2907 # If there are any files/dirs remaining, one of these checks will fail.
2908 self.assertEqual(0, len(outfiles))
2909 _CheckDirPresent('section/cbfs')
2910 _CheckDirPresent('section')
2911 _CheckDirPresent('')
2912 self.assertFalse(os.path.exists(outdir))
2913
2914 def testExtractAllEntries(self):
2915 """Test extracting all entries"""
2916 self._CheckLz4()
2917 self._CheckExtractOutput(decomp=True)
2918
2919 def testExtractAllEntriesRaw(self):
2920 """Test extracting all entries without decompressing them"""
2921 self._CheckLz4()
2922 self._CheckExtractOutput(decomp=False)
2923
2924 def testExtractSelectedEntries(self):
2925 """Test extracting some entries"""
2926 self._CheckLz4()
2927 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2928 image_fname = tools.GetOutputFilename('image.bin')
2929 outdir = os.path.join(self._indir, 'extract')
2930 einfos = control.ExtractEntries(image_fname, None, outdir,
2931 ['*cb*', '*head*'])
2932
2933 # File output is tested by testExtractAllEntries(), so just check that
2934 # the expected entries are selected
2935 names = [einfo.name for einfo in einfos]
2936 self.assertEqual(names,
2937 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2938
2939 def testExtractNoEntryPaths(self):
2940 """Test extracting some entries"""
2941 self._CheckLz4()
2942 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2943 image_fname = tools.GetOutputFilename('image.bin')
2944 with self.assertRaises(ValueError) as e:
2945 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassbb5edc12019-07-20 12:24:14 -06002946 self.assertIn('Must specify an entry path to write with -f',
Simon Glass71ce0ba2019-07-08 14:25:52 -06002947 str(e.exception))
2948
2949 def testExtractTooManyEntryPaths(self):
2950 """Test extracting some entries"""
2951 self._CheckLz4()
2952 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2953 image_fname = tools.GetOutputFilename('image.bin')
2954 with self.assertRaises(ValueError) as e:
2955 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassbb5edc12019-07-20 12:24:14 -06002956 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass71ce0ba2019-07-08 14:25:52 -06002957 str(e.exception))
2958
Simon Glasse2705fa2019-07-08 14:25:53 -06002959 def testPackAlignSection(self):
2960 """Test that sections can have alignment"""
2961 self._DoReadFile('131_pack_align_section.dts')
2962
2963 self.assertIn('image', control.images)
2964 image = control.images['image']
2965 entries = image.GetEntries()
2966 self.assertEqual(3, len(entries))
2967
2968 # First u-boot
2969 self.assertIn('u-boot', entries)
2970 entry = entries['u-boot']
2971 self.assertEqual(0, entry.offset)
2972 self.assertEqual(0, entry.image_pos)
2973 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2974 self.assertEqual(len(U_BOOT_DATA), entry.size)
2975
2976 # Section0
2977 self.assertIn('section0', entries)
2978 section0 = entries['section0']
2979 self.assertEqual(0x10, section0.offset)
2980 self.assertEqual(0x10, section0.image_pos)
2981 self.assertEqual(len(U_BOOT_DATA), section0.size)
2982
2983 # Second u-boot
2984 section_entries = section0.GetEntries()
2985 self.assertIn('u-boot', section_entries)
2986 entry = section_entries['u-boot']
2987 self.assertEqual(0, entry.offset)
2988 self.assertEqual(0x10, entry.image_pos)
2989 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2990 self.assertEqual(len(U_BOOT_DATA), entry.size)
2991
2992 # Section1
2993 self.assertIn('section1', entries)
2994 section1 = entries['section1']
2995 self.assertEqual(0x14, section1.offset)
2996 self.assertEqual(0x14, section1.image_pos)
2997 self.assertEqual(0x20, section1.size)
2998
2999 # Second u-boot
3000 section_entries = section1.GetEntries()
3001 self.assertIn('u-boot', section_entries)
3002 entry = section_entries['u-boot']
3003 self.assertEqual(0, entry.offset)
3004 self.assertEqual(0x14, entry.image_pos)
3005 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3006 self.assertEqual(len(U_BOOT_DATA), entry.size)
3007
3008 # Section2
3009 self.assertIn('section2', section_entries)
3010 section2 = section_entries['section2']
3011 self.assertEqual(0x4, section2.offset)
3012 self.assertEqual(0x18, section2.image_pos)
3013 self.assertEqual(4, section2.size)
3014
3015 # Third u-boot
3016 section_entries = section2.GetEntries()
3017 self.assertIn('u-boot', section_entries)
3018 entry = section_entries['u-boot']
3019 self.assertEqual(0, entry.offset)
3020 self.assertEqual(0x18, entry.image_pos)
3021 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3022 self.assertEqual(len(U_BOOT_DATA), entry.size)
3023
Simon Glass51014aa2019-07-20 12:23:56 -06003024 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3025 dts='132_replace.dts'):
Simon Glass10f9d002019-07-20 12:23:50 -06003026 """Replace an entry in an image
3027
3028 This writes the entry data to update it, then opens the updated file and
3029 returns the value that it now finds there.
3030
3031 Args:
3032 entry_name: Entry name to replace
3033 data: Data to replace it with
3034 decomp: True to compress the data if needed, False if data is
3035 already compressed so should be used as is
Simon Glass51014aa2019-07-20 12:23:56 -06003036 allow_resize: True to allow entries to change size, False to raise
3037 an exception
Simon Glass10f9d002019-07-20 12:23:50 -06003038
3039 Returns:
3040 Tuple:
3041 data from entry
3042 data from fdtmap (excluding header)
Simon Glass51014aa2019-07-20 12:23:56 -06003043 Image object that was modified
Simon Glass10f9d002019-07-20 12:23:50 -06003044 """
Simon Glass51014aa2019-07-20 12:23:56 -06003045 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass10f9d002019-07-20 12:23:50 -06003046 update_dtb=True)[1]
3047
3048 self.assertIn('image', control.images)
3049 image = control.images['image']
3050 entries = image.GetEntries()
3051 orig_dtb_data = entries['u-boot-dtb'].data
3052 orig_fdtmap_data = entries['fdtmap'].data
3053
3054 image_fname = tools.GetOutputFilename('image.bin')
3055 updated_fname = tools.GetOutputFilename('image-updated.bin')
3056 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
Simon Glass51014aa2019-07-20 12:23:56 -06003057 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3058 allow_resize)
Simon Glass10f9d002019-07-20 12:23:50 -06003059 data = control.ReadEntry(updated_fname, entry_name, decomp)
3060
Simon Glass51014aa2019-07-20 12:23:56 -06003061 # The DT data should not change unless resized:
3062 if not allow_resize:
3063 new_dtb_data = entries['u-boot-dtb'].data
3064 self.assertEqual(new_dtb_data, orig_dtb_data)
3065 new_fdtmap_data = entries['fdtmap'].data
3066 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass10f9d002019-07-20 12:23:50 -06003067
Simon Glass51014aa2019-07-20 12:23:56 -06003068 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass10f9d002019-07-20 12:23:50 -06003069
3070 def testReplaceSimple(self):
3071 """Test replacing a single file"""
3072 expected = b'x' * len(U_BOOT_DATA)
Simon Glass51014aa2019-07-20 12:23:56 -06003073 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3074 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06003075 self.assertEqual(expected, data)
3076
3077 # Test that the state looks right. There should be an FDT for the fdtmap
3078 # that we jsut read back in, and it should match what we find in the
3079 # 'control' tables. Checking for an FDT that does not exist should
3080 # return None.
3081 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glass51014aa2019-07-20 12:23:56 -06003082 self.assertIsNotNone(path)
Simon Glass10f9d002019-07-20 12:23:50 -06003083 self.assertEqual(expected_fdtmap, fdtmap)
3084
3085 dtb = state.GetFdtForEtype('fdtmap')
3086 self.assertEqual(dtb.GetContents(), fdtmap)
3087
3088 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3089 self.assertIsNone(missing_path)
3090 self.assertIsNone(missing_fdtmap)
3091
3092 missing_dtb = state.GetFdtForEtype('missing')
3093 self.assertIsNone(missing_dtb)
3094
3095 self.assertEqual('/binman', state.fdt_path_prefix)
3096
3097 def testReplaceResizeFail(self):
3098 """Test replacing a file by something larger"""
3099 expected = U_BOOT_DATA + b'x'
3100 with self.assertRaises(ValueError) as e:
Simon Glass51014aa2019-07-20 12:23:56 -06003101 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3102 dts='139_replace_repack.dts')
Simon Glass10f9d002019-07-20 12:23:50 -06003103 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3104 str(e.exception))
3105
3106 def testReplaceMulti(self):
3107 """Test replacing entry data where multiple images are generated"""
3108 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3109 update_dtb=True)[0]
3110 expected = b'x' * len(U_BOOT_DATA)
3111 updated_fname = tools.GetOutputFilename('image-updated.bin')
3112 tools.WriteFile(updated_fname, data)
3113 entry_name = 'u-boot'
Simon Glass51014aa2019-07-20 12:23:56 -06003114 control.WriteEntry(updated_fname, entry_name, expected,
3115 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06003116 data = control.ReadEntry(updated_fname, entry_name)
3117 self.assertEqual(expected, data)
3118
3119 # Check the state looks right.
3120 self.assertEqual('/binman/image', state.fdt_path_prefix)
3121
3122 # Now check we can write the first image
3123 image_fname = tools.GetOutputFilename('first-image.bin')
3124 updated_fname = tools.GetOutputFilename('first-updated.bin')
3125 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
3126 entry_name = 'u-boot'
Simon Glass51014aa2019-07-20 12:23:56 -06003127 control.WriteEntry(updated_fname, entry_name, expected,
3128 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06003129 data = control.ReadEntry(updated_fname, entry_name)
3130 self.assertEqual(expected, data)
3131
3132 # Check the state looks right.
3133 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass8beb11e2019-07-08 14:25:47 -06003134
Simon Glass12bb1a92019-07-20 12:23:51 -06003135 def testUpdateFdtAllRepack(self):
3136 """Test that all device trees are updated with offset/size info"""
3137 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3138 SECTION_SIZE = 0x300
3139 DTB_SIZE = 602
3140 FDTMAP_SIZE = 608
3141 base_expected = {
3142 'offset': 0,
3143 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3144 'image-pos': 0,
3145 'section:offset': 0,
3146 'section:size': SECTION_SIZE,
3147 'section:image-pos': 0,
3148 'section/u-boot-dtb:offset': 4,
3149 'section/u-boot-dtb:size': 636,
3150 'section/u-boot-dtb:image-pos': 4,
3151 'u-boot-spl-dtb:offset': SECTION_SIZE,
3152 'u-boot-spl-dtb:size': DTB_SIZE,
3153 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3154 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3155 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3156 'u-boot-tpl-dtb:size': DTB_SIZE,
3157 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3158 'fdtmap:size': FDTMAP_SIZE,
3159 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3160 }
3161 main_expected = {
3162 'section:orig-size': SECTION_SIZE,
3163 'section/u-boot-dtb:orig-offset': 4,
3164 }
3165
3166 # We expect three device-tree files in the output, with the first one
3167 # within a fixed-size section.
3168 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3169 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3170 # main U-Boot tree. All three should have the same positions and offset
3171 # except that the main tree should include the main_expected properties
3172 start = 4
3173 for item in ['', 'spl', 'tpl', None]:
3174 if item is None:
3175 start += 16 # Move past fdtmap header
3176 dtb = fdt.Fdt.FromData(data[start:])
3177 dtb.Scan()
3178 props = self._GetPropTree(dtb,
3179 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3180 prefix='/' if item is None else '/binman/')
3181 expected = dict(base_expected)
3182 if item:
3183 expected[item] = 0
3184 else:
3185 # Main DTB and fdtdec should include the 'orig-' properties
3186 expected.update(main_expected)
3187 # Helpful for debugging:
3188 #for prop in sorted(props):
3189 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3190 self.assertEqual(expected, props)
3191 if item == '':
3192 start = SECTION_SIZE
3193 else:
3194 start += dtb._fdt_obj.totalsize()
3195
Simon Glasseba1f0c2019-07-20 12:23:55 -06003196 def testFdtmapHeaderMiddle(self):
3197 """Test an FDT map in the middle of an image when it should be at end"""
3198 with self.assertRaises(ValueError) as e:
3199 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3200 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3201 str(e.exception))
3202
3203 def testFdtmapHeaderStartBad(self):
3204 """Test an FDT map in middle of an image when it should be at start"""
3205 with self.assertRaises(ValueError) as e:
3206 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3207 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3208 str(e.exception))
3209
3210 def testFdtmapHeaderEndBad(self):
3211 """Test an FDT map at the start of an image when it should be at end"""
3212 with self.assertRaises(ValueError) as e:
3213 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3214 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3215 str(e.exception))
3216
3217 def testFdtmapHeaderNoSize(self):
3218 """Test an image header at the end of an image with undefined size"""
3219 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3220
Simon Glass51014aa2019-07-20 12:23:56 -06003221 def testReplaceResize(self):
3222 """Test replacing a single file in an entry with a larger file"""
3223 expected = U_BOOT_DATA + b'x'
3224 data, _, image = self._RunReplaceCmd('u-boot', expected,
3225 dts='139_replace_repack.dts')
3226 self.assertEqual(expected, data)
3227
3228 entries = image.GetEntries()
3229 dtb_data = entries['u-boot-dtb'].data
3230 dtb = fdt.Fdt.FromData(dtb_data)
3231 dtb.Scan()
3232
3233 # The u-boot section should now be larger in the dtb
3234 node = dtb.GetNode('/binman/u-boot')
3235 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3236
3237 # Same for the fdtmap
3238 fdata = entries['fdtmap'].data
3239 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3240 fdtb.Scan()
3241 fnode = fdtb.GetNode('/u-boot')
3242 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3243
3244 def testReplaceResizeNoRepack(self):
3245 """Test replacing an entry with a larger file when not allowed"""
3246 expected = U_BOOT_DATA + b'x'
3247 with self.assertRaises(ValueError) as e:
3248 self._RunReplaceCmd('u-boot', expected)
3249 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3250 str(e.exception))
3251
Simon Glass61ec04f2019-07-20 12:23:58 -06003252 def testEntryShrink(self):
3253 """Test contracting an entry after it is packed"""
3254 try:
3255 state.SetAllowEntryContraction(True)
3256 data = self._DoReadFileDtb('140_entry_shrink.dts',
3257 update_dtb=True)[0]
3258 finally:
3259 state.SetAllowEntryContraction(False)
3260 self.assertEqual(b'a', data[:1])
3261 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3262 self.assertEqual(b'a', data[-1:])
3263
3264 def testEntryShrinkFail(self):
3265 """Test not being allowed to contract an entry after it is packed"""
3266 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3267
3268 # In this case there is a spare byte at the end of the data. The size of
3269 # the contents is only 1 byte but we still have the size before it
3270 # shrunk.
3271 self.assertEqual(b'a\0', data[:2])
3272 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3273 self.assertEqual(b'a\0', data[-2:])
3274
Simon Glass27145fd2019-07-20 12:24:01 -06003275 def testDescriptorOffset(self):
3276 """Test that the Intel descriptor is always placed at at the start"""
3277 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3278 image = control.images['image']
3279 entries = image.GetEntries()
3280 desc = entries['intel-descriptor']
3281 self.assertEqual(0xff800000, desc.offset);
3282 self.assertEqual(0xff800000, desc.image_pos);
3283
Simon Glasseb0f4a42019-07-20 12:24:06 -06003284 def testReplaceCbfs(self):
3285 """Test replacing a single file in CBFS without changing the size"""
3286 self._CheckLz4()
3287 expected = b'x' * len(U_BOOT_DATA)
3288 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3289 updated_fname = tools.GetOutputFilename('image-updated.bin')
3290 tools.WriteFile(updated_fname, data)
3291 entry_name = 'section/cbfs/u-boot'
3292 control.WriteEntry(updated_fname, entry_name, expected,
3293 allow_resize=True)
3294 data = control.ReadEntry(updated_fname, entry_name)
3295 self.assertEqual(expected, data)
3296
3297 def testReplaceResizeCbfs(self):
3298 """Test replacing a single file in CBFS with one of a different size"""
3299 self._CheckLz4()
3300 expected = U_BOOT_DATA + b'x'
3301 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3302 updated_fname = tools.GetOutputFilename('image-updated.bin')
3303 tools.WriteFile(updated_fname, data)
3304 entry_name = 'section/cbfs/u-boot'
3305 control.WriteEntry(updated_fname, entry_name, expected,
3306 allow_resize=True)
3307 data = control.ReadEntry(updated_fname, entry_name)
3308 self.assertEqual(expected, data)
3309
Simon Glassa6cb9952019-07-20 12:24:15 -06003310 def _SetupForReplace(self):
3311 """Set up some files to use to replace entries
3312
3313 This generates an image, copies it to a new file, extracts all the files
3314 in it and updates some of them
3315
3316 Returns:
3317 List
3318 Image filename
3319 Output directory
3320 Expected values for updated entries, each a string
3321 """
3322 data = self._DoReadFileRealDtb('143_replace_all.dts')
3323
3324 updated_fname = tools.GetOutputFilename('image-updated.bin')
3325 tools.WriteFile(updated_fname, data)
3326
3327 outdir = os.path.join(self._indir, 'extract')
3328 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3329
3330 expected1 = b'x' + U_BOOT_DATA + b'y'
3331 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3332 tools.WriteFile(u_boot_fname1, expected1)
3333
3334 expected2 = b'a' + U_BOOT_DATA + b'b'
3335 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
3336 tools.WriteFile(u_boot_fname2, expected2)
3337
3338 expected_text = b'not the same text'
3339 text_fname = os.path.join(outdir, 'text')
3340 tools.WriteFile(text_fname, expected_text)
3341
3342 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3343 dtb = fdt.FdtScan(dtb_fname)
3344 node = dtb.GetNode('/binman/text')
3345 node.AddString('my-property', 'the value')
3346 dtb.Sync(auto_resize=True)
3347 dtb.Flush()
3348
3349 return updated_fname, outdir, expected1, expected2, expected_text
3350
3351 def _CheckReplaceMultiple(self, entry_paths):
3352 """Handle replacing the contents of multiple entries
3353
3354 Args:
3355 entry_paths: List of entry paths to replace
3356
3357 Returns:
3358 List
3359 Dict of entries in the image:
3360 key: Entry name
3361 Value: Entry object
3362 Expected values for updated entries, each a string
3363 """
3364 updated_fname, outdir, expected1, expected2, expected_text = (
3365 self._SetupForReplace())
3366 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3367
3368 image = Image.FromFile(updated_fname)
3369 image.LoadData()
3370 return image.GetEntries(), expected1, expected2, expected_text
3371
3372 def testReplaceAll(self):
3373 """Test replacing the contents of all entries"""
3374 entries, expected1, expected2, expected_text = (
3375 self._CheckReplaceMultiple([]))
3376 data = entries['u-boot'].data
3377 self.assertEqual(expected1, data)
3378
3379 data = entries['u-boot2'].data
3380 self.assertEqual(expected2, data)
3381
3382 data = entries['text'].data
3383 self.assertEqual(expected_text, data)
3384
3385 # Check that the device tree is updated
3386 data = entries['u-boot-dtb'].data
3387 dtb = fdt.Fdt.FromData(data)
3388 dtb.Scan()
3389 node = dtb.GetNode('/binman/text')
3390 self.assertEqual('the value', node.props['my-property'].value)
3391
3392 def testReplaceSome(self):
3393 """Test replacing the contents of a few entries"""
3394 entries, expected1, expected2, expected_text = (
3395 self._CheckReplaceMultiple(['u-boot2', 'text']))
3396
3397 # This one should not change
3398 data = entries['u-boot'].data
3399 self.assertEqual(U_BOOT_DATA, data)
3400
3401 data = entries['u-boot2'].data
3402 self.assertEqual(expected2, data)
3403
3404 data = entries['text'].data
3405 self.assertEqual(expected_text, data)
3406
3407 def testReplaceCmd(self):
3408 """Test replacing a file fron an image on the command line"""
3409 self._DoReadFileRealDtb('143_replace_all.dts')
3410
3411 try:
3412 tmpdir, updated_fname = self._SetupImageInTmpdir()
3413
3414 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3415 expected = b'x' * len(U_BOOT_DATA)
3416 tools.WriteFile(fname, expected)
3417
3418 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
3419 data = tools.ReadFile(updated_fname)
3420 self.assertEqual(expected, data[:len(expected)])
3421 map_fname = os.path.join(tmpdir, 'image-updated.map')
3422 self.assertFalse(os.path.exists(map_fname))
3423 finally:
3424 shutil.rmtree(tmpdir)
3425
3426 def testReplaceCmdSome(self):
3427 """Test replacing some files fron an image on the command line"""
3428 updated_fname, outdir, expected1, expected2, expected_text = (
3429 self._SetupForReplace())
3430
3431 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3432 'u-boot2', 'text')
3433
3434 tools.PrepareOutputDir(None)
3435 image = Image.FromFile(updated_fname)
3436 image.LoadData()
3437 entries = image.GetEntries()
3438
3439 # This one should not change
3440 data = entries['u-boot'].data
3441 self.assertEqual(U_BOOT_DATA, data)
3442
3443 data = entries['u-boot2'].data
3444 self.assertEqual(expected2, data)
3445
3446 data = entries['text'].data
3447 self.assertEqual(expected_text, data)
3448
3449 def testReplaceMissing(self):
3450 """Test replacing entries where the file is missing"""
3451 updated_fname, outdir, expected1, expected2, expected_text = (
3452 self._SetupForReplace())
3453
3454 # Remove one of the files, to generate a warning
3455 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3456 os.remove(u_boot_fname1)
3457
3458 with test_util.capture_sys_output() as (stdout, stderr):
3459 control.ReplaceEntries(updated_fname, None, outdir, [])
3460 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass38fdb4c2020-07-09 18:39:39 -06003461 stderr.getvalue())
Simon Glassa6cb9952019-07-20 12:24:15 -06003462
3463 def testReplaceCmdMap(self):
3464 """Test replacing a file fron an image on the command line"""
3465 self._DoReadFileRealDtb('143_replace_all.dts')
3466
3467 try:
3468 tmpdir, updated_fname = self._SetupImageInTmpdir()
3469
3470 fname = os.path.join(self._indir, 'update-u-boot.bin')
3471 expected = b'x' * len(U_BOOT_DATA)
3472 tools.WriteFile(fname, expected)
3473
3474 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3475 '-f', fname, '-m')
3476 map_fname = os.path.join(tmpdir, 'image-updated.map')
3477 self.assertTrue(os.path.exists(map_fname))
3478 finally:
3479 shutil.rmtree(tmpdir)
3480
3481 def testReplaceNoEntryPaths(self):
3482 """Test replacing an entry without an entry path"""
3483 self._DoReadFileRealDtb('143_replace_all.dts')
3484 image_fname = tools.GetOutputFilename('image.bin')
3485 with self.assertRaises(ValueError) as e:
3486 control.ReplaceEntries(image_fname, 'fname', None, [])
3487 self.assertIn('Must specify an entry path to read with -f',
3488 str(e.exception))
3489
3490 def testReplaceTooManyEntryPaths(self):
3491 """Test extracting some entries"""
3492 self._DoReadFileRealDtb('143_replace_all.dts')
3493 image_fname = tools.GetOutputFilename('image.bin')
3494 with self.assertRaises(ValueError) as e:
3495 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3496 self.assertIn('Must specify exactly one entry path to write with -f',
3497 str(e.exception))
3498
Simon Glass2250ee62019-08-24 07:22:48 -06003499 def testPackReset16(self):
3500 """Test that an image with an x86 reset16 region can be created"""
3501 data = self._DoReadFile('144_x86_reset16.dts')
3502 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3503
3504 def testPackReset16Spl(self):
3505 """Test that an image with an x86 reset16-spl region can be created"""
3506 data = self._DoReadFile('145_x86_reset16_spl.dts')
3507 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3508
3509 def testPackReset16Tpl(self):
3510 """Test that an image with an x86 reset16-tpl region can be created"""
3511 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3512 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3513
Simon Glass5af12072019-08-24 07:22:50 -06003514 def testPackIntelFit(self):
3515 """Test that an image with an Intel FIT and pointer can be created"""
3516 data = self._DoReadFile('147_intel_fit.dts')
3517 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3518 fit = data[16:32];
3519 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3520 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3521
3522 image = control.images['image']
3523 entries = image.GetEntries()
3524 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3525 self.assertEqual(expected_ptr, ptr)
3526
3527 def testPackIntelFitMissing(self):
3528 """Test detection of a FIT pointer with not FIT region"""
3529 with self.assertRaises(ValueError) as e:
3530 self._DoReadFile('148_intel_fit_missing.dts')
3531 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3532 str(e.exception))
3533
Simon Glass7c150132019-11-06 17:22:44 -07003534 def _CheckSymbolsTplSection(self, dts, expected_vals):
3535 data = self._DoReadFile(dts)
3536 sym_values = struct.pack('<LQLL', *expected_vals)
Simon Glass2090f1e2019-08-24 07:23:00 -06003537 upto1 = 4 + len(U_BOOT_SPL_DATA)
Simon Glassb87064c2019-08-24 07:23:05 -06003538 expected1 = tools.GetBytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[20:]
Simon Glass2090f1e2019-08-24 07:23:00 -06003539 self.assertEqual(expected1, data[:upto1])
3540
3541 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Simon Glassb87064c2019-08-24 07:23:05 -06003542 expected2 = tools.GetBytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[20:]
Simon Glass2090f1e2019-08-24 07:23:00 -06003543 self.assertEqual(expected2, data[upto1:upto2])
3544
Simon Glasseb0086f2019-08-24 07:23:04 -06003545 upto3 = 0x34 + len(U_BOOT_DATA)
3546 expected3 = tools.GetBytes(0xff, 1) + U_BOOT_DATA
Simon Glass2090f1e2019-08-24 07:23:00 -06003547 self.assertEqual(expected3, data[upto2:upto3])
3548
Simon Glassb87064c2019-08-24 07:23:05 -06003549 expected4 = sym_values + U_BOOT_TPL_DATA[20:]
Simon Glass7c150132019-11-06 17:22:44 -07003550 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3551
3552 def testSymbolsTplSection(self):
3553 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3554 self._SetupSplElf('u_boot_binman_syms')
3555 self._SetupTplElf('u_boot_binman_syms')
3556 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
3557 [0x04, 0x1c, 0x10 + 0x34, 0x04])
3558
3559 def testSymbolsTplSectionX86(self):
3560 """Test binman can assign symbols in a section with end-at-4gb"""
3561 self._SetupSplElf('u_boot_binman_syms_x86')
3562 self._SetupTplElf('u_boot_binman_syms_x86')
3563 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
3564 [0xffffff04, 0xffffff1c, 0xffffff34,
3565 0x04])
Simon Glass2090f1e2019-08-24 07:23:00 -06003566
Simon Glassbf4d0e22019-08-24 07:23:03 -06003567 def testPackX86RomIfwiSectiom(self):
3568 """Test that a section can be placed in an IFWI region"""
3569 self._SetupIfwi('fitimage.bin')
3570 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3571 self._CheckIfwi(data)
3572
Simon Glassea0fff92019-08-24 07:23:07 -06003573 def testPackFspM(self):
3574 """Test that an image with a FSP memory-init binary can be created"""
3575 data = self._DoReadFile('152_intel_fsp_m.dts')
3576 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3577
Simon Glassbc6a88f2019-10-20 21:31:35 -06003578 def testPackFspS(self):
3579 """Test that an image with a FSP silicon-init binary can be created"""
3580 data = self._DoReadFile('153_intel_fsp_s.dts')
3581 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassea0fff92019-08-24 07:23:07 -06003582
Simon Glass998d1482019-10-20 21:31:36 -06003583 def testPackFspT(self):
3584 """Test that an image with a FSP temp-ram-init binary can be created"""
3585 data = self._DoReadFile('154_intel_fsp_t.dts')
3586 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3587
Simon Glass0dc706f2020-07-09 18:39:31 -06003588 def testMkimage(self):
3589 """Test using mkimage to build an image"""
3590 data = self._DoReadFile('156_mkimage.dts')
3591
3592 # Just check that the data appears in the file somewhere
3593 self.assertIn(U_BOOT_SPL_DATA, data)
3594
Simon Glassce867ad2020-07-09 18:39:36 -06003595 def testExtblob(self):
3596 """Test an image with an external blob"""
3597 data = self._DoReadFile('157_blob_ext.dts')
3598 self.assertEqual(REFCODE_DATA, data)
3599
3600 def testExtblobMissing(self):
3601 """Test an image with a missing external blob"""
3602 with self.assertRaises(ValueError) as e:
3603 self._DoReadFile('158_blob_ext_missing.dts')
3604 self.assertIn("Filename 'missing-file' not found in input path",
3605 str(e.exception))
3606
Simon Glass4f9f1052020-07-09 18:39:38 -06003607 def testExtblobMissingOk(self):
3608 """Test an image with an missing external blob that is allowed"""
Simon Glassb1cca952020-07-09 18:39:40 -06003609 with test_util.capture_sys_output() as (stdout, stderr):
3610 self._DoTestFile('158_blob_ext_missing.dts', allow_missing=True)
3611 err = stderr.getvalue()
3612 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
3613
3614 def testExtblobMissingOkSect(self):
3615 """Test an image with an missing external blob that is allowed"""
3616 with test_util.capture_sys_output() as (stdout, stderr):
3617 self._DoTestFile('159_blob_ext_missing_sect.dts',
3618 allow_missing=True)
3619 err = stderr.getvalue()
3620 self.assertRegex(err, "Image 'main-section'.*missing.*: "
3621 "blob-ext blob-ext2")
Simon Glass4f9f1052020-07-09 18:39:38 -06003622
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003623 def testPackX86RomMeMissingDesc(self):
3624 """Test that an missing Intel descriptor entry is allowed"""
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003625 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass52b10dd2020-07-25 15:11:19 -06003626 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003627 err = stderr.getvalue()
3628 self.assertRegex(err,
3629 "Image 'main-section'.*missing.*: intel-descriptor")
3630
3631 def testPackX86RomMissingIfwi(self):
3632 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3633 self._SetupIfwi('fitimage.bin')
3634 pathname = os.path.join(self._indir, 'fitimage.bin')
3635 os.remove(pathname)
3636 with test_util.capture_sys_output() as (stdout, stderr):
3637 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3638 err = stderr.getvalue()
3639 self.assertRegex(err, "Image 'main-section'.*missing.*: intel-ifwi")
3640
Simon Glassb3295fd2020-07-09 18:39:42 -06003641 def testPackOverlap(self):
3642 """Test that zero-size overlapping regions are ignored"""
3643 self._DoTestFile('160_pack_overlap_zero.dts')
3644
Simon Glassfdc34362020-07-09 18:39:45 -06003645 def testSimpleFit(self):
3646 """Test an image with a FIT inside"""
3647 data = self._DoReadFile('161_fit.dts')
3648 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3649 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3650 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3651
3652 # The data should be inside the FIT
3653 dtb = fdt.Fdt.FromData(fit_data)
3654 dtb.Scan()
3655 fnode = dtb.GetNode('/images/kernel')
3656 self.assertIn('data', fnode.props)
3657
3658 fname = os.path.join(self._indir, 'fit_data.fit')
3659 tools.WriteFile(fname, fit_data)
3660 out = tools.Run('dumpimage', '-l', fname)
3661
3662 # Check a few features to make sure the plumbing works. We don't need
3663 # to test the operation of mkimage or dumpimage here. First convert the
3664 # output into a dict where the keys are the fields printed by dumpimage
3665 # and the values are a list of values for each field
3666 lines = out.splitlines()
3667
3668 # Converts "Compression: gzip compressed" into two groups:
3669 # 'Compression' and 'gzip compressed'
3670 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3671 vals = collections.defaultdict(list)
3672 for line in lines:
3673 mat = re_line.match(line)
3674 vals[mat.group(1)].append(mat.group(2))
3675
3676 self.assertEquals('FIT description: test-desc', lines[0])
3677 self.assertIn('Created:', lines[1])
3678 self.assertIn('Image 0 (kernel)', vals)
3679 self.assertIn('Hash value', vals)
3680 data_sizes = vals.get('Data Size')
3681 self.assertIsNotNone(data_sizes)
3682 self.assertEqual(2, len(data_sizes))
3683 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
3684 self.assertEqual(len(U_BOOT_DATA), int(data_sizes[0].split()[0]))
3685 self.assertEqual(len(U_BOOT_SPL_DTB_DATA), int(data_sizes[1].split()[0]))
3686
3687 def testFitExternal(self):
Simon Glasse9d336d2020-09-01 05:13:55 -06003688 """Test an image with an FIT with external images"""
Simon Glassfdc34362020-07-09 18:39:45 -06003689 data = self._DoReadFile('162_fit_external.dts')
3690 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3691
3692 # The data should be outside the FIT
3693 dtb = fdt.Fdt.FromData(fit_data)
3694 dtb.Scan()
3695 fnode = dtb.GetNode('/images/kernel')
3696 self.assertNotIn('data', fnode.props)
Simon Glass12bb1a92019-07-20 12:23:51 -06003697
Alper Nebi Yasak8001d0b2020-08-31 12:58:18 +03003698 def testSectionIgnoreHashSignature(self):
3699 """Test that sections ignore hash, signature nodes for its data"""
3700 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
3701 expected = (U_BOOT_DATA + U_BOOT_DATA)
3702 self.assertEqual(expected, data)
3703
Alper Nebi Yasak3fdeb142020-08-31 12:58:19 +03003704 def testPadInSections(self):
3705 """Test pad-before, pad-after for entries in sections"""
Simon Glassf90d9062020-10-26 17:40:09 -06003706 data, _, _, out_dtb_fname = self._DoReadFileDtb(
3707 '166_pad_in_sections.dts', update_dtb=True)
Alper Nebi Yasak3fdeb142020-08-31 12:58:19 +03003708 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
3709 U_BOOT_DATA + tools.GetBytes(ord('!'), 6) +
3710 U_BOOT_DATA)
3711 self.assertEqual(expected, data)
3712
Simon Glassf90d9062020-10-26 17:40:09 -06003713 dtb = fdt.Fdt(out_dtb_fname)
3714 dtb.Scan()
3715 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
3716 expected = {
3717 'image-pos': 0,
3718 'offset': 0,
3719 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
3720
3721 'section:image-pos': 0,
3722 'section:offset': 0,
3723 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
3724
3725 'section/before:image-pos': 0,
3726 'section/before:offset': 0,
3727 'section/before:size': len(U_BOOT_DATA),
3728
3729 'section/u-boot:image-pos': 4,
3730 'section/u-boot:offset': 4,
3731 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
3732
3733 'section/after:image-pos': 26,
3734 'section/after:offset': 26,
3735 'section/after:size': len(U_BOOT_DATA),
3736 }
3737 self.assertEqual(expected, props)
3738
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03003739 def testFitImageSubentryAlignment(self):
3740 """Test relative alignability of FIT image subentries"""
3741 entry_args = {
3742 'test-id': TEXT_DATA,
3743 }
3744 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
3745 entry_args=entry_args)
3746 dtb = fdt.Fdt.FromData(data)
3747 dtb.Scan()
3748
3749 node = dtb.GetNode('/images/kernel')
3750 data = dtb.GetProps(node)["data"].bytes
3751 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
3752 expected = (tools.GetBytes(0, 0x20) + U_BOOT_SPL_DATA +
3753 tools.GetBytes(0, align_pad) + U_BOOT_DATA)
3754 self.assertEqual(expected, data)
3755
3756 node = dtb.GetNode('/images/fdt-1')
3757 data = dtb.GetProps(node)["data"].bytes
3758 expected = (U_BOOT_SPL_DTB_DATA + tools.GetBytes(0, 20) +
3759 tools.ToBytes(TEXT_DATA) + tools.GetBytes(0, 30) +
3760 U_BOOT_DTB_DATA)
3761 self.assertEqual(expected, data)
3762
3763 def testFitExtblobMissingOk(self):
3764 """Test a FIT with a missing external blob that is allowed"""
3765 with test_util.capture_sys_output() as (stdout, stderr):
3766 self._DoTestFile('168_fit_missing_blob.dts',
3767 allow_missing=True)
3768 err = stderr.getvalue()
Simon Glassb2381432020-09-06 10:39:09 -06003769 self.assertRegex(err, "Image 'main-section'.*missing.*: atf-bl31")
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03003770
Simon Glass3decfa32020-09-01 05:13:54 -06003771 def testBlobNamedByArgMissing(self):
3772 """Test handling of a missing entry arg"""
3773 with self.assertRaises(ValueError) as e:
3774 self._DoReadFile('068_blob_named_by_arg.dts')
3775 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
3776 str(e.exception))
3777
Simon Glassdc2f81a2020-09-01 05:13:58 -06003778 def testPackBl31(self):
3779 """Test that an image with an ATF BL31 binary can be created"""
3780 data = self._DoReadFile('169_atf_bl31.dts')
3781 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
3782
Samuel Holland18bd4552020-10-21 21:12:15 -05003783 def testPackScp(self):
3784 """Test that an image with an SCP binary can be created"""
3785 data = self._DoReadFile('172_scp.dts')
3786 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
3787
Simon Glass6cf99532020-09-01 05:13:59 -06003788 def testFitFdt(self):
3789 """Test an image with an FIT with multiple FDT images"""
3790 def _CheckFdt(seq, expected_data):
3791 """Check the FDT nodes
3792
3793 Args:
3794 seq: Sequence number to check (0 or 1)
3795 expected_data: Expected contents of 'data' property
3796 """
3797 name = 'fdt-%d' % seq
3798 fnode = dtb.GetNode('/images/%s' % name)
3799 self.assertIsNotNone(fnode)
3800 self.assertEqual({'description','type', 'compression', 'data'},
3801 set(fnode.props.keys()))
3802 self.assertEqual(expected_data, fnode.props['data'].bytes)
3803 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
3804 fnode.props['description'].value)
3805
3806 def _CheckConfig(seq, expected_data):
3807 """Check the configuration nodes
3808
3809 Args:
3810 seq: Sequence number to check (0 or 1)
3811 expected_data: Expected contents of 'data' property
3812 """
3813 cnode = dtb.GetNode('/configurations')
3814 self.assertIn('default', cnode.props)
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003815 self.assertEqual('config-2', cnode.props['default'].value)
Simon Glass6cf99532020-09-01 05:13:59 -06003816
3817 name = 'config-%d' % seq
3818 fnode = dtb.GetNode('/configurations/%s' % name)
3819 self.assertIsNotNone(fnode)
3820 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
3821 set(fnode.props.keys()))
3822 self.assertEqual('conf-test-fdt%d.dtb' % seq,
3823 fnode.props['description'].value)
3824 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
3825
3826 entry_args = {
3827 'of-list': 'test-fdt1 test-fdt2',
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003828 'default-dt': 'test-fdt2',
Simon Glass6cf99532020-09-01 05:13:59 -06003829 }
3830 data = self._DoReadFileDtb(
Bin Mengaa75ce92021-05-10 20:23:32 +08003831 '170_fit_fdt.dts',
Simon Glass6cf99532020-09-01 05:13:59 -06003832 entry_args=entry_args,
3833 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3834 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3835 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3836
3837 dtb = fdt.Fdt.FromData(fit_data)
3838 dtb.Scan()
3839 fnode = dtb.GetNode('/images/kernel')
3840 self.assertIn('data', fnode.props)
3841
3842 # Check all the properties in fdt-1 and fdt-2
3843 _CheckFdt(1, TEST_FDT1_DATA)
3844 _CheckFdt(2, TEST_FDT2_DATA)
3845
3846 # Check configurations
3847 _CheckConfig(1, TEST_FDT1_DATA)
3848 _CheckConfig(2, TEST_FDT2_DATA)
3849
3850 def testFitFdtMissingList(self):
3851 """Test handling of a missing 'of-list' entry arg"""
3852 with self.assertRaises(ValueError) as e:
Bin Mengaa75ce92021-05-10 20:23:32 +08003853 self._DoReadFile('170_fit_fdt.dts')
Simon Glass6cf99532020-09-01 05:13:59 -06003854 self.assertIn("Generator node requires 'of-list' entry argument",
3855 str(e.exception))
3856
3857 def testFitFdtEmptyList(self):
3858 """Test handling of an empty 'of-list' entry arg"""
3859 entry_args = {
3860 'of-list': '',
3861 }
3862 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
3863
3864 def testFitFdtMissingProp(self):
3865 """Test handling of a missing 'fit,fdt-list' property"""
3866 with self.assertRaises(ValueError) as e:
3867 self._DoReadFile('171_fit_fdt_missing_prop.dts')
3868 self.assertIn("Generator node requires 'fit,fdt-list' property",
3869 str(e.exception))
Simon Glassdc2f81a2020-09-01 05:13:58 -06003870
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003871 def testFitFdtEmptyList(self):
3872 """Test handling of an empty 'of-list' entry arg"""
3873 entry_args = {
3874 'of-list': '',
3875 }
Bin Mengaa75ce92021-05-10 20:23:32 +08003876 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003877
3878 def testFitFdtMissing(self):
3879 """Test handling of a missing 'default-dt' entry arg"""
3880 entry_args = {
3881 'of-list': 'test-fdt1 test-fdt2',
3882 }
3883 with self.assertRaises(ValueError) as e:
3884 self._DoReadFileDtb(
Bin Mengaa75ce92021-05-10 20:23:32 +08003885 '170_fit_fdt.dts',
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003886 entry_args=entry_args,
3887 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3888 self.assertIn("Generated 'default' node requires default-dt entry argument",
3889 str(e.exception))
3890
3891 def testFitFdtNotInList(self):
3892 """Test handling of a default-dt that is not in the of-list"""
3893 entry_args = {
3894 'of-list': 'test-fdt1 test-fdt2',
3895 'default-dt': 'test-fdt3',
3896 }
3897 with self.assertRaises(ValueError) as e:
3898 self._DoReadFileDtb(
Bin Mengaa75ce92021-05-10 20:23:32 +08003899 '170_fit_fdt.dts',
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003900 entry_args=entry_args,
3901 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3902 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
3903 str(e.exception))
3904
Simon Glassb2381432020-09-06 10:39:09 -06003905 def testFitExtblobMissingHelp(self):
3906 """Test display of help messages when an external blob is missing"""
3907 control.missing_blob_help = control._ReadMissingBlobHelp()
3908 control.missing_blob_help['wibble'] = 'Wibble test'
3909 control.missing_blob_help['another'] = 'Another test'
3910 with test_util.capture_sys_output() as (stdout, stderr):
3911 self._DoTestFile('168_fit_missing_blob.dts',
3912 allow_missing=True)
3913 err = stderr.getvalue()
3914
3915 # We can get the tag from the name, the type or the missing-msg
3916 # property. Check all three.
3917 self.assertIn('You may need to build ARM Trusted', err)
3918 self.assertIn('Wibble test', err)
3919 self.assertIn('Another test', err)
3920
Simon Glass204aa782020-09-06 10:35:32 -06003921 def testMissingBlob(self):
3922 """Test handling of a blob containing a missing file"""
3923 with self.assertRaises(ValueError) as e:
3924 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
3925 self.assertIn("Filename 'missing' not found in input path",
3926 str(e.exception))
3927
Simon Glassfb91d562020-09-06 10:35:33 -06003928 def testEnvironment(self):
3929 """Test adding a U-Boot environment"""
3930 data = self._DoReadFile('174_env.dts')
3931 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3932 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3933 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3934 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
3935 env)
3936
3937 def testEnvironmentNoSize(self):
3938 """Test that a missing 'size' property is detected"""
3939 with self.assertRaises(ValueError) as e:
Simon Glassa4dfe3e2020-10-26 17:40:00 -06003940 self._DoTestFile('175_env_no_size.dts')
Simon Glassfb91d562020-09-06 10:35:33 -06003941 self.assertIn("'u-boot-env' entry must have a size property",
3942 str(e.exception))
3943
3944 def testEnvironmentTooSmall(self):
3945 """Test handling of an environment that does not fit"""
3946 with self.assertRaises(ValueError) as e:
Simon Glassa4dfe3e2020-10-26 17:40:00 -06003947 self._DoTestFile('176_env_too_small.dts')
Simon Glassfb91d562020-09-06 10:35:33 -06003948
3949 # checksum, start byte, environment with \0 terminator, final \0
3950 need = 4 + 1 + len(ENV_DATA) + 1 + 1
3951 short = need - 0x8
3952 self.assertIn("too small to hold data (need %#x more bytes)" % short,
3953 str(e.exception))
3954
Simon Glassf2c0dd82020-10-26 17:40:01 -06003955 def testSkipAtStart(self):
3956 """Test handling of skip-at-start section"""
3957 data = self._DoReadFile('177_skip_at_start.dts')
3958 self.assertEqual(U_BOOT_DATA, data)
3959
3960 image = control.images['image']
3961 entries = image.GetEntries()
3962 section = entries['section']
3963 self.assertEqual(0, section.offset)
3964 self.assertEqual(len(U_BOOT_DATA), section.size)
3965 self.assertEqual(U_BOOT_DATA, section.GetData())
3966
3967 entry = section.GetEntries()['u-boot']
3968 self.assertEqual(16, entry.offset)
3969 self.assertEqual(len(U_BOOT_DATA), entry.size)
3970 self.assertEqual(U_BOOT_DATA, entry.data)
3971
3972 def testSkipAtStartPad(self):
3973 """Test handling of skip-at-start section with padded entry"""
3974 data = self._DoReadFile('178_skip_at_start_pad.dts')
3975 before = tools.GetBytes(0, 8)
3976 after = tools.GetBytes(0, 4)
3977 all = before + U_BOOT_DATA + after
3978 self.assertEqual(all, data)
3979
3980 image = control.images['image']
3981 entries = image.GetEntries()
3982 section = entries['section']
3983 self.assertEqual(0, section.offset)
3984 self.assertEqual(len(all), section.size)
3985 self.assertEqual(all, section.GetData())
3986
3987 entry = section.GetEntries()['u-boot']
3988 self.assertEqual(16, entry.offset)
3989 self.assertEqual(len(all), entry.size)
3990 self.assertEqual(U_BOOT_DATA, entry.data)
3991
3992 def testSkipAtStartSectionPad(self):
3993 """Test handling of skip-at-start section with padding"""
3994 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
3995 before = tools.GetBytes(0, 8)
3996 after = tools.GetBytes(0, 4)
3997 all = before + U_BOOT_DATA + after
Simon Glassd1d3ad72020-10-26 17:40:13 -06003998 self.assertEqual(all, data)
Simon Glassf2c0dd82020-10-26 17:40:01 -06003999
4000 image = control.images['image']
4001 entries = image.GetEntries()
4002 section = entries['section']
4003 self.assertEqual(0, section.offset)
4004 self.assertEqual(len(all), section.size)
Simon Glass63e7ba62020-10-26 17:40:16 -06004005 self.assertEqual(U_BOOT_DATA, section.data)
Simon Glassd1d3ad72020-10-26 17:40:13 -06004006 self.assertEqual(all, section.GetPaddedData())
Simon Glassf2c0dd82020-10-26 17:40:01 -06004007
4008 entry = section.GetEntries()['u-boot']
4009 self.assertEqual(16, entry.offset)
4010 self.assertEqual(len(U_BOOT_DATA), entry.size)
4011 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassfb91d562020-09-06 10:35:33 -06004012
Simon Glass7d398bb2020-10-26 17:40:14 -06004013 def testSectionPad(self):
4014 """Testing padding with sections"""
4015 data = self._DoReadFile('180_section_pad.dts')
4016 expected = (tools.GetBytes(ord('&'), 3) +
4017 tools.GetBytes(ord('!'), 5) +
4018 U_BOOT_DATA +
4019 tools.GetBytes(ord('!'), 1) +
4020 tools.GetBytes(ord('&'), 2))
4021 self.assertEqual(expected, data)
4022
4023 def testSectionAlign(self):
4024 """Testing alignment with sections"""
4025 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4026 expected = (b'\0' + # fill section
4027 tools.GetBytes(ord('&'), 1) + # padding to section align
4028 b'\0' + # fill section
4029 tools.GetBytes(ord('!'), 3) + # padding to u-boot align
4030 U_BOOT_DATA +
4031 tools.GetBytes(ord('!'), 4) + # padding to u-boot size
4032 tools.GetBytes(ord('!'), 4)) # padding to section size
4033 self.assertEqual(expected, data)
4034
Simon Glass8f5ef892020-10-26 17:40:25 -06004035 def testCompressImage(self):
4036 """Test compression of the entire image"""
4037 self._CheckLz4()
4038 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4039 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4040 dtb = fdt.Fdt(out_dtb_fname)
4041 dtb.Scan()
4042 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4043 'uncomp-size'])
4044 orig = self._decompress(data)
4045 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4046
4047 # Do a sanity check on various fields
4048 image = control.images['image']
4049 entries = image.GetEntries()
4050 self.assertEqual(2, len(entries))
4051
4052 entry = entries['blob']
4053 self.assertEqual(COMPRESS_DATA, entry.data)
4054 self.assertEqual(len(COMPRESS_DATA), entry.size)
4055
4056 entry = entries['u-boot']
4057 self.assertEqual(U_BOOT_DATA, entry.data)
4058 self.assertEqual(len(U_BOOT_DATA), entry.size)
4059
4060 self.assertEqual(len(data), image.size)
4061 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4062 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4063 orig = self._decompress(image.data)
4064 self.assertEqual(orig, image.uncomp_data)
4065
4066 expected = {
4067 'blob:offset': 0,
4068 'blob:size': len(COMPRESS_DATA),
4069 'u-boot:offset': len(COMPRESS_DATA),
4070 'u-boot:size': len(U_BOOT_DATA),
4071 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4072 'offset': 0,
4073 'image-pos': 0,
4074 'size': len(data),
4075 }
4076 self.assertEqual(expected, props)
4077
4078 def testCompressImageLess(self):
4079 """Test compression where compression reduces the image size"""
4080 self._CheckLz4()
4081 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4082 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4083 dtb = fdt.Fdt(out_dtb_fname)
4084 dtb.Scan()
4085 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4086 'uncomp-size'])
4087 orig = self._decompress(data)
4088
4089 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
4090
4091 # Do a sanity check on various fields
4092 image = control.images['image']
4093 entries = image.GetEntries()
4094 self.assertEqual(2, len(entries))
4095
4096 entry = entries['blob']
4097 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4098 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4099
4100 entry = entries['u-boot']
4101 self.assertEqual(U_BOOT_DATA, entry.data)
4102 self.assertEqual(len(U_BOOT_DATA), entry.size)
4103
4104 self.assertEqual(len(data), image.size)
4105 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4106 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4107 image.uncomp_size)
4108 orig = self._decompress(image.data)
4109 self.assertEqual(orig, image.uncomp_data)
4110
4111 expected = {
4112 'blob:offset': 0,
4113 'blob:size': len(COMPRESS_DATA_BIG),
4114 'u-boot:offset': len(COMPRESS_DATA_BIG),
4115 'u-boot:size': len(U_BOOT_DATA),
4116 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4117 'offset': 0,
4118 'image-pos': 0,
4119 'size': len(data),
4120 }
4121 self.assertEqual(expected, props)
4122
4123 def testCompressSectionSize(self):
4124 """Test compression of a section with a fixed size"""
4125 self._CheckLz4()
4126 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4127 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4128 dtb = fdt.Fdt(out_dtb_fname)
4129 dtb.Scan()
4130 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4131 'uncomp-size'])
4132 orig = self._decompress(data)
4133 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4134 expected = {
4135 'section/blob:offset': 0,
4136 'section/blob:size': len(COMPRESS_DATA),
4137 'section/u-boot:offset': len(COMPRESS_DATA),
4138 'section/u-boot:size': len(U_BOOT_DATA),
4139 'section:offset': 0,
4140 'section:image-pos': 0,
4141 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4142 'section:size': 0x30,
4143 'offset': 0,
4144 'image-pos': 0,
4145 'size': 0x30,
4146 }
4147 self.assertEqual(expected, props)
4148
4149 def testCompressSection(self):
4150 """Test compression of a section with no fixed size"""
4151 self._CheckLz4()
4152 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4153 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4154 dtb = fdt.Fdt(out_dtb_fname)
4155 dtb.Scan()
4156 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4157 'uncomp-size'])
4158 orig = self._decompress(data)
4159 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4160 expected = {
4161 'section/blob:offset': 0,
4162 'section/blob:size': len(COMPRESS_DATA),
4163 'section/u-boot:offset': len(COMPRESS_DATA),
4164 'section/u-boot:size': len(U_BOOT_DATA),
4165 'section:offset': 0,
4166 'section:image-pos': 0,
4167 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4168 'section:size': len(data),
4169 'offset': 0,
4170 'image-pos': 0,
4171 'size': len(data),
4172 }
4173 self.assertEqual(expected, props)
4174
4175 def testCompressExtra(self):
4176 """Test compression of a section with no fixed size"""
4177 self._CheckLz4()
4178 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4179 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4180 dtb = fdt.Fdt(out_dtb_fname)
4181 dtb.Scan()
4182 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4183 'uncomp-size'])
4184
4185 base = data[len(U_BOOT_DATA):]
4186 self.assertEquals(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
4187 rest = base[len(U_BOOT_DATA):]
4188
4189 # Check compressed data
4190 section1 = self._decompress(rest)
4191 expect1 = tools.Compress(COMPRESS_DATA + U_BOOT_DATA, 'lz4')
4192 self.assertEquals(expect1, rest[:len(expect1)])
4193 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, section1)
4194 rest1 = rest[len(expect1):]
4195
4196 section2 = self._decompress(rest1)
4197 expect2 = tools.Compress(COMPRESS_DATA + COMPRESS_DATA, 'lz4')
4198 self.assertEquals(expect2, rest1[:len(expect2)])
4199 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA, section2)
4200 rest2 = rest1[len(expect2):]
4201
4202 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4203 len(expect2) + len(U_BOOT_DATA))
4204 #self.assertEquals(expect_size, len(data))
4205
4206 #self.assertEquals(U_BOOT_DATA, rest2)
4207
4208 self.maxDiff = None
4209 expected = {
4210 'u-boot:offset': 0,
4211 'u-boot:image-pos': 0,
4212 'u-boot:size': len(U_BOOT_DATA),
4213
4214 'base:offset': len(U_BOOT_DATA),
4215 'base:image-pos': len(U_BOOT_DATA),
4216 'base:size': len(data) - len(U_BOOT_DATA),
4217 'base/u-boot:offset': 0,
4218 'base/u-boot:image-pos': len(U_BOOT_DATA),
4219 'base/u-boot:size': len(U_BOOT_DATA),
4220 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4221 len(expect2),
4222 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4223 len(expect2),
4224 'base/u-boot2:size': len(U_BOOT_DATA),
4225
4226 'base/section:offset': len(U_BOOT_DATA),
4227 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4228 'base/section:size': len(expect1),
4229 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4230 'base/section/blob:offset': 0,
4231 'base/section/blob:size': len(COMPRESS_DATA),
4232 'base/section/u-boot:offset': len(COMPRESS_DATA),
4233 'base/section/u-boot:size': len(U_BOOT_DATA),
4234
4235 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4236 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4237 'base/section2:size': len(expect2),
4238 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4239 'base/section2/blob:offset': 0,
4240 'base/section2/blob:size': len(COMPRESS_DATA),
4241 'base/section2/blob2:offset': len(COMPRESS_DATA),
4242 'base/section2/blob2:size': len(COMPRESS_DATA),
4243
4244 'offset': 0,
4245 'image-pos': 0,
4246 'size': len(data),
4247 }
4248 self.assertEqual(expected, props)
4249
Simon Glass870a9ea2021-01-06 21:35:15 -07004250 def testSymbolsSubsection(self):
4251 """Test binman can assign symbols from a subsection"""
Simon Glassf5898822021-03-18 20:24:56 +13004252 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x18)
Simon Glass870a9ea2021-01-06 21:35:15 -07004253
Simon Glass939d1062021-01-06 21:35:16 -07004254 def testReadImageEntryArg(self):
4255 """Test reading an image that would need an entry arg to generate"""
4256 entry_args = {
4257 'cros-ec-rw-path': 'ecrw.bin',
4258 }
4259 data = self.data = self._DoReadFileDtb(
4260 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4261 entry_args=entry_args)
4262
4263 image_fname = tools.GetOutputFilename('image.bin')
4264 orig_image = control.images['image']
4265
4266 # This should not generate an error about the missing 'cros-ec-rw-path'
4267 # since we are reading the image from a file. Compare with
4268 # testEntryArgsRequired()
4269 image = Image.FromFile(image_fname)
4270 self.assertEqual(orig_image.GetEntries().keys(),
4271 image.GetEntries().keys())
4272
Simon Glass6eb99322021-01-06 21:35:18 -07004273 def testFilesAlign(self):
4274 """Test alignment with files"""
4275 data = self._DoReadFile('190_files_align.dts')
4276
4277 # The first string is 15 bytes so will align to 16
4278 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4279 self.assertEqual(expect, data)
4280
Simon Glass5c6ba712021-01-06 21:35:19 -07004281 def testReadImageSkip(self):
4282 """Test reading an image and accessing its FDT map"""
4283 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
4284 image_fname = tools.GetOutputFilename('image.bin')
4285 orig_image = control.images['image']
4286 image = Image.FromFile(image_fname)
4287 self.assertEqual(orig_image.GetEntries().keys(),
4288 image.GetEntries().keys())
4289
4290 orig_entry = orig_image.GetEntries()['fdtmap']
4291 entry = image.GetEntries()['fdtmap']
4292 self.assertEqual(orig_entry.offset, entry.offset)
4293 self.assertEqual(orig_entry.size, entry.size)
4294 self.assertEqual(16, entry.image_pos)
4295
4296 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4297
4298 self.assertEquals(U_BOOT_DATA, u_boot.ReadData())
4299
Simon Glass77a64e02021-03-18 20:24:57 +13004300 def testTplNoDtb(self):
4301 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
Simon Glass0fe44dc2021-04-25 08:39:32 +12004302 self._SetupTplElf()
Simon Glass77a64e02021-03-18 20:24:57 +13004303 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4304 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4305 data[:len(U_BOOT_TPL_NODTB_DATA)])
4306
Simon Glassd26efc82021-03-18 20:24:58 +13004307 def testTplBssPad(self):
4308 """Test that we can pad TPL's BSS with zeros"""
4309 # ELF file with a '__bss_size' symbol
4310 self._SetupTplElf()
4311 data = self._DoReadFile('193_tpl_bss_pad.dts')
4312 self.assertEqual(U_BOOT_TPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
4313 data)
4314
4315 def testTplBssPadMissing(self):
4316 """Test that a missing symbol is detected"""
4317 self._SetupTplElf('u_boot_ucode_ptr')
4318 with self.assertRaises(ValueError) as e:
4319 self._DoReadFile('193_tpl_bss_pad.dts')
4320 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4321 str(e.exception))
4322
Simon Glass06684922021-03-18 20:25:07 +13004323 def checkDtbSizes(self, data, pad_len, start):
4324 """Check the size arguments in a dtb embedded in an image
4325
4326 Args:
4327 data: The image data
4328 pad_len: Length of the pad section in the image, in bytes
4329 start: Start offset of the devicetree to examine, within the image
4330
4331 Returns:
4332 Size of the devicetree in bytes
4333 """
4334 dtb_data = data[start:]
4335 dtb = fdt.Fdt.FromData(dtb_data)
4336 fdt_size = dtb.GetFdtObj().totalsize()
4337 dtb.Scan()
4338 props = self._GetPropTree(dtb, 'size')
4339 self.assertEqual({
4340 'size': len(data),
4341 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4342 'u-boot-spl/u-boot-spl-dtb:size': 801,
4343 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4344 'u-boot-spl:size': 860,
4345 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4346 'u-boot/u-boot-dtb:size': 781,
4347 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4348 'u-boot:size': 827,
4349 }, props)
4350 return fdt_size
4351
4352 def testExpanded(self):
4353 """Test that an expanded entry type is selected when needed"""
4354 self._SetupSplElf()
4355 self._SetupTplElf()
4356
4357 # SPL has a devicetree, TPL does not
4358 entry_args = {
4359 'spl-dtb': '1',
4360 'spl-bss-pad': 'y',
4361 'tpl-dtb': '',
4362 }
4363 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4364 entry_args=entry_args)
4365 image = control.images['image']
4366 entries = image.GetEntries()
4367 self.assertEqual(3, len(entries))
4368
4369 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4370 self.assertIn('u-boot', entries)
4371 entry = entries['u-boot']
4372 self.assertEqual('u-boot-expanded', entry.etype)
4373 subent = entry.GetEntries()
4374 self.assertEqual(2, len(subent))
4375 self.assertIn('u-boot-nodtb', subent)
4376 self.assertIn('u-boot-dtb', subent)
4377
4378 # Second, u-boot-spl, which should be expanded into three parts
4379 self.assertIn('u-boot-spl', entries)
4380 entry = entries['u-boot-spl']
4381 self.assertEqual('u-boot-spl-expanded', entry.etype)
4382 subent = entry.GetEntries()
4383 self.assertEqual(3, len(subent))
4384 self.assertIn('u-boot-spl-nodtb', subent)
4385 self.assertIn('u-boot-spl-bss-pad', subent)
4386 self.assertIn('u-boot-spl-dtb', subent)
4387
4388 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4389 # devicetree
4390 self.assertIn('u-boot-tpl', entries)
4391 entry = entries['u-boot-tpl']
4392 self.assertEqual('u-boot-tpl', entry.etype)
4393 self.assertEqual(None, entry.GetEntries())
4394
4395 def testExpandedTpl(self):
4396 """Test that an expanded entry type is selected for TPL when needed"""
4397 self._SetupTplElf()
4398
4399 entry_args = {
4400 'tpl-bss-pad': 'y',
4401 'tpl-dtb': 'y',
4402 }
4403 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4404 entry_args=entry_args)
4405 image = control.images['image']
4406 entries = image.GetEntries()
4407 self.assertEqual(1, len(entries))
4408
4409 # We only have u-boot-tpl, which be expanded
4410 self.assertIn('u-boot-tpl', entries)
4411 entry = entries['u-boot-tpl']
4412 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4413 subent = entry.GetEntries()
4414 self.assertEqual(3, len(subent))
4415 self.assertIn('u-boot-tpl-nodtb', subent)
4416 self.assertIn('u-boot-tpl-bss-pad', subent)
4417 self.assertIn('u-boot-tpl-dtb', subent)
4418
4419 def testExpandedNoPad(self):
4420 """Test an expanded entry without BSS pad enabled"""
4421 self._SetupSplElf()
4422 self._SetupTplElf()
4423
4424 # SPL has a devicetree, TPL does not
4425 entry_args = {
4426 'spl-dtb': 'something',
4427 'spl-bss-pad': 'n',
4428 'tpl-dtb': '',
4429 }
4430 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4431 entry_args=entry_args)
4432 image = control.images['image']
4433 entries = image.GetEntries()
4434
4435 # Just check u-boot-spl, which should be expanded into two parts
4436 self.assertIn('u-boot-spl', entries)
4437 entry = entries['u-boot-spl']
4438 self.assertEqual('u-boot-spl-expanded', entry.etype)
4439 subent = entry.GetEntries()
4440 self.assertEqual(2, len(subent))
4441 self.assertIn('u-boot-spl-nodtb', subent)
4442 self.assertIn('u-boot-spl-dtb', subent)
4443
4444 def testExpandedTplNoPad(self):
4445 """Test that an expanded entry type with padding disabled in TPL"""
4446 self._SetupTplElf()
4447
4448 entry_args = {
4449 'tpl-bss-pad': '',
4450 'tpl-dtb': 'y',
4451 }
4452 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4453 entry_args=entry_args)
4454 image = control.images['image']
4455 entries = image.GetEntries()
4456 self.assertEqual(1, len(entries))
4457
4458 # We only have u-boot-tpl, which be expanded
4459 self.assertIn('u-boot-tpl', entries)
4460 entry = entries['u-boot-tpl']
4461 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4462 subent = entry.GetEntries()
4463 self.assertEqual(2, len(subent))
4464 self.assertIn('u-boot-tpl-nodtb', subent)
4465 self.assertIn('u-boot-tpl-dtb', subent)
4466
4467 def testFdtInclude(self):
4468 """Test that an Fdt is update within all binaries"""
4469 self._SetupSplElf()
4470 self._SetupTplElf()
4471
4472 # SPL has a devicetree, TPL does not
4473 self.maxDiff = None
4474 entry_args = {
4475 'spl-dtb': '1',
4476 'spl-bss-pad': 'y',
4477 'tpl-dtb': '',
4478 }
4479 # Build the image. It includes two separate devicetree binaries, each
4480 # with their own contents, but all contain the binman definition.
4481 data = self._DoReadFileDtb(
4482 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4483 update_dtb=True, entry_args=entry_args)[0]
4484 pad_len = 10
4485
4486 # Check the U-Boot dtb
4487 start = len(U_BOOT_NODTB_DATA)
4488 fdt_size = self.checkDtbSizes(data, pad_len, start)
4489
4490 # Now check SPL
4491 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4492 fdt_size = self.checkDtbSizes(data, pad_len, start)
4493
4494 # TPL has no devicetree
4495 start += fdt_size + len(U_BOOT_TPL_DATA)
4496 self.assertEqual(len(data), start)
Simon Glass7d398bb2020-10-26 17:40:14 -06004497
Simon Glass3d433382021-03-21 18:24:30 +13004498 def testSymbolsExpanded(self):
4499 """Test binman can assign symbols in expanded entries"""
4500 entry_args = {
4501 'spl-dtb': '1',
4502 }
4503 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4504 U_BOOT_SPL_DTB_DATA, 0x38,
4505 entry_args=entry_args, use_expanded=True)
4506
Simon Glass189f2912021-03-21 18:24:31 +13004507 def testCollection(self):
4508 """Test a collection"""
4509 data = self._DoReadFile('198_collection.dts')
4510 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
4511 tools.GetBytes(0xff, 2) + U_BOOT_NODTB_DATA +
4512 tools.GetBytes(0xfe, 3) + U_BOOT_DTB_DATA,
4513 data)
4514
Simon Glass631f7522021-03-21 18:24:32 +13004515 def testCollectionSection(self):
4516 """Test a collection where a section must be built first"""
4517 # Sections never have their contents when GetData() is called, but when
4518 # _BuildSectionData() is called with required=True, a section will force
4519 # building the contents, producing an error is anything is still
4520 # missing.
4521 data = self._DoReadFile('199_collection_section.dts')
4522 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
4523 self.assertEqual(section + U_BOOT_DATA + tools.GetBytes(0xff, 2) +
4524 section + tools.GetBytes(0xfe, 3) + U_BOOT_DATA,
4525 data)
4526
Simon Glass5ff9fed2021-03-21 18:24:33 +13004527 def testAlignDefault(self):
4528 """Test that default alignment works on sections"""
4529 data = self._DoReadFile('200_align_default.dts')
4530 expected = (U_BOOT_DATA + tools.GetBytes(0, 8 - len(U_BOOT_DATA)) +
4531 U_BOOT_DATA)
4532 # Special alignment for section
4533 expected += tools.GetBytes(0, 32 - len(expected))
4534 # No alignment within the nested section
4535 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
4536 # Now the final piece, which should be default-aligned
4537 expected += tools.GetBytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
4538 self.assertEqual(expected, data)
Simon Glass631f7522021-03-21 18:24:32 +13004539
Bin Meng4c4d6072021-05-10 20:23:33 +08004540 def testPackOpenSBI(self):
4541 """Test that an image with an OpenSBI binary can be created"""
4542 data = self._DoReadFile('201_opensbi.dts')
4543 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
4544
Simon Glass9fc60b42017-11-12 21:52:22 -07004545if __name__ == "__main__":
4546 unittest.main()