blob: cea3ebf2b9f7512a8b1c6e5d58c6072b2b53c8de [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,
Simon Glassc69d19c2021-07-06 10:36:37 -0600311 extra_indirs=None, threads=None,
312 test_section_timeout=False):
Simon Glass4f443042016-11-25 20:15:52 -0700313 """Run binman with a given test file
314
315 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600316 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600317 debug: True to enable debugging output
Simon Glass3b0c38212018-06-01 09:38:20 -0600318 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600319 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600320 tree before packing it into the image
Simon Glass0bfa7b02018-09-14 04:57:12 -0600321 entry_args: Dict of entry args to supply to binman
322 key: arg name
323 value: value of that arg
324 images: List of image names to build
Simon Glasse9d336d2020-09-01 05:13:55 -0600325 use_real_dtb: True to use the test file as the contents of
326 the u-boot-dtb entry. Normally this is not needed and the
327 test contents (the U_BOOT_DTB_DATA string) can be used.
328 But in some test we need the real contents.
Simon Glass63aeaeb2021-03-18 20:25:05 +1300329 use_expanded: True to use expanded entries where available, e.g.
330 'u-boot-expanded' instead of 'u-boot'
Simon Glasse9d336d2020-09-01 05:13:55 -0600331 verbosity: Verbosity level to use (0-3, None=don't set it)
332 allow_missing: Set the '--allow-missing' flag so that missing
333 external binaries just produce a warning instead of an error
Simon Glass6cf99532020-09-01 05:13:59 -0600334 extra_indirs: Extra input directories to add using -I
Simon Glassc69d19c2021-07-06 10:36:37 -0600335 threads: Number of threads to use (None for default, 0 for
336 single-threaded)
Simon Glass4f443042016-11-25 20:15:52 -0700337 """
Simon Glass53cd5d92019-07-08 14:25:29 -0600338 args = []
Simon Glass7fe91732017-11-13 18:55:00 -0700339 if debug:
340 args.append('-D')
Simon Glass53cd5d92019-07-08 14:25:29 -0600341 if verbosity is not None:
342 args.append('-v%d' % verbosity)
343 elif self.verbosity:
344 args.append('-v%d' % self.verbosity)
345 if self.toolpath:
346 for path in self.toolpath:
347 args += ['--toolpath', path]
Simon Glassc69d19c2021-07-06 10:36:37 -0600348 if threads is not None:
349 args.append('-T%d' % threads)
350 if test_section_timeout:
351 args.append('--test-section-timeout')
Simon Glass53cd5d92019-07-08 14:25:29 -0600352 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass3b0c38212018-06-01 09:38:20 -0600353 if map:
354 args.append('-m')
Simon Glass16b8d6b2018-07-06 10:27:42 -0600355 if update_dtb:
Simon Glass2569e102019-07-08 13:18:47 -0600356 args.append('-u')
Simon Glass93d17412018-09-14 04:57:23 -0600357 if not use_real_dtb:
358 args.append('--fake-dtb')
Simon Glass63aeaeb2021-03-18 20:25:05 +1300359 if not use_expanded:
360 args.append('--no-expanded')
Simon Glass53af22a2018-07-17 13:25:32 -0600361 if entry_args:
Simon Glass50979152019-05-14 15:53:41 -0600362 for arg, value in entry_args.items():
Simon Glass53af22a2018-07-17 13:25:32 -0600363 args.append('-a%s=%s' % (arg, value))
Simon Glass4f9f1052020-07-09 18:39:38 -0600364 if allow_missing:
365 args.append('-M')
Simon Glass0bfa7b02018-09-14 04:57:12 -0600366 if images:
367 for image in images:
368 args += ['-i', image]
Simon Glass6cf99532020-09-01 05:13:59 -0600369 if extra_indirs:
370 for indir in extra_indirs:
371 args += ['-I', indir]
Simon Glass7fe91732017-11-13 18:55:00 -0700372 return self._DoBinman(*args)
Simon Glass4f443042016-11-25 20:15:52 -0700373
374 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glasse0ff8552016-11-25 20:15:53 -0700375 """Set up a new test device-tree file
376
377 The given file is compiled and set up as the device tree to be used
378 for ths test.
379
380 Args:
381 fname: Filename of .dts file to read
Simon Glass7ae5f312018-06-01 09:38:19 -0600382 outfile: Output filename for compiled device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700383
384 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600385 Contents of device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700386 """
Simon Glassa004f292019-07-20 12:23:49 -0600387 tmpdir = tempfile.mkdtemp(prefix='binmant.')
388 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
Simon Glass1d0ebf72019-05-14 15:53:42 -0600389 with open(dtb, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700390 data = fd.read()
391 TestFunctional._MakeInputFile(outfile, data)
Simon Glassa004f292019-07-20 12:23:49 -0600392 shutil.rmtree(tmpdir)
Simon Glasse0e62752018-10-01 21:12:41 -0600393 return data
Simon Glass4f443042016-11-25 20:15:52 -0700394
Simon Glass6ed45ba2018-09-14 04:57:24 -0600395 def _GetDtbContentsForSplTpl(self, dtb_data, name):
396 """Create a version of the main DTB for SPL or SPL
397
398 For testing we don't actually have different versions of the DTB. With
399 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
400 we don't normally have any unwanted nodes.
401
402 We still want the DTBs for SPL and TPL to be different though, since
403 otherwise it is confusing to know which one we are looking at. So add
404 an 'spl' or 'tpl' property to the top-level node.
Simon Glasse9d336d2020-09-01 05:13:55 -0600405
406 Args:
407 dtb_data: dtb data to modify (this should be a value devicetree)
408 name: Name of a new property to add
409
410 Returns:
411 New dtb data with the property added
Simon Glass6ed45ba2018-09-14 04:57:24 -0600412 """
413 dtb = fdt.Fdt.FromData(dtb_data)
414 dtb.Scan()
415 dtb.GetNode('/binman').AddZeroProp(name)
416 dtb.Sync(auto_resize=True)
417 dtb.Pack()
418 return dtb.GetContents()
419
Simon Glass63aeaeb2021-03-18 20:25:05 +1300420 def _DoReadFileDtb(self, fname, use_real_dtb=False, use_expanded=False,
421 map=False, update_dtb=False, entry_args=None,
Simon Glassc69d19c2021-07-06 10:36:37 -0600422 reset_dtbs=True, extra_indirs=None, threads=None):
Simon Glass4f443042016-11-25 20:15:52 -0700423 """Run binman and return the resulting image
424
425 This runs binman with a given test file and then reads the resulting
426 output file. It is a shortcut function since most tests need to do
427 these steps.
428
429 Raises an assertion failure if binman returns a non-zero exit code.
430
431 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600432 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass4f443042016-11-25 20:15:52 -0700433 use_real_dtb: True to use the test file as the contents of
434 the u-boot-dtb entry. Normally this is not needed and the
435 test contents (the U_BOOT_DTB_DATA string) can be used.
436 But in some test we need the real contents.
Simon Glass63aeaeb2021-03-18 20:25:05 +1300437 use_expanded: True to use expanded entries where available, e.g.
438 'u-boot-expanded' instead of 'u-boot'
Simon Glass3b0c38212018-06-01 09:38:20 -0600439 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600440 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600441 tree before packing it into the image
Simon Glasse9d336d2020-09-01 05:13:55 -0600442 entry_args: Dict of entry args to supply to binman
443 key: arg name
444 value: value of that arg
445 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
446 function. If reset_dtbs is True, then the original test dtb
447 is written back before this function finishes
Simon Glass6cf99532020-09-01 05:13:59 -0600448 extra_indirs: Extra input directories to add using -I
Simon Glassc69d19c2021-07-06 10:36:37 -0600449 threads: Number of threads to use (None for default, 0 for
450 single-threaded)
Simon Glasse0ff8552016-11-25 20:15:53 -0700451
452 Returns:
453 Tuple:
454 Resulting image contents
455 Device tree contents
Simon Glass3b0c38212018-06-01 09:38:20 -0600456 Map data showing contents of image (or None if none)
Simon Glassea6922e2018-07-17 13:25:27 -0600457 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass4f443042016-11-25 20:15:52 -0700458 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700459 dtb_data = None
Simon Glass4f443042016-11-25 20:15:52 -0700460 # Use the compiled test file as the u-boot-dtb input
461 if use_real_dtb:
Simon Glasse0ff8552016-11-25 20:15:53 -0700462 dtb_data = self._SetupDtb(fname)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600463
464 # For testing purposes, make a copy of the DT for SPL and TPL. Add
465 # a node indicating which it is, so aid verification.
466 for name in ['spl', 'tpl']:
467 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
468 outfile = os.path.join(self._indir, dtb_fname)
469 TestFunctional._MakeInputFile(dtb_fname,
470 self._GetDtbContentsForSplTpl(dtb_data, name))
Simon Glass4f443042016-11-25 20:15:52 -0700471
472 try:
Simon Glass53af22a2018-07-17 13:25:32 -0600473 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glass6cf99532020-09-01 05:13:59 -0600474 entry_args=entry_args, use_real_dtb=use_real_dtb,
Simon Glassc69d19c2021-07-06 10:36:37 -0600475 use_expanded=use_expanded, extra_indirs=extra_indirs,
476 threads=threads)
Simon Glass4f443042016-11-25 20:15:52 -0700477 self.assertEqual(0, retcode)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600478 out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
Simon Glass4f443042016-11-25 20:15:52 -0700479
480 # Find the (only) image, read it and return its contents
481 image = control.images['image']
Simon Glass16b8d6b2018-07-06 10:27:42 -0600482 image_fname = tools.GetOutputFilename('image.bin')
483 self.assertTrue(os.path.exists(image_fname))
Simon Glass3b0c38212018-06-01 09:38:20 -0600484 if map:
485 map_fname = tools.GetOutputFilename('image.map')
486 with open(map_fname) as fd:
487 map_data = fd.read()
488 else:
489 map_data = None
Simon Glass1d0ebf72019-05-14 15:53:42 -0600490 with open(image_fname, 'rb') as fd:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600491 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass4f443042016-11-25 20:15:52 -0700492 finally:
493 # Put the test file back
Simon Glass6ed45ba2018-09-14 04:57:24 -0600494 if reset_dtbs and use_real_dtb:
Simon Glassb8ef5b62018-07-17 13:25:48 -0600495 self._ResetDtbs()
Simon Glass4f443042016-11-25 20:15:52 -0700496
Simon Glass3c081312019-07-08 14:25:26 -0600497 def _DoReadFileRealDtb(self, fname):
498 """Run binman with a real .dtb file and return the resulting data
499
500 Args:
501 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
502
503 Returns:
504 Resulting image contents
505 """
506 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
507
Simon Glasse0ff8552016-11-25 20:15:53 -0700508 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass7ae5f312018-06-01 09:38:19 -0600509 """Helper function which discards the device-tree binary
510
511 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600512 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600513 use_real_dtb: True to use the test file as the contents of
514 the u-boot-dtb entry. Normally this is not needed and the
515 test contents (the U_BOOT_DTB_DATA string) can be used.
516 But in some test we need the real contents.
Simon Glassea6922e2018-07-17 13:25:27 -0600517
518 Returns:
519 Resulting image contents
Simon Glass7ae5f312018-06-01 09:38:19 -0600520 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700521 return self._DoReadFileDtb(fname, use_real_dtb)[0]
522
Simon Glass4f443042016-11-25 20:15:52 -0700523 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600524 def _MakeInputFile(cls, fname, contents):
Simon Glass4f443042016-11-25 20:15:52 -0700525 """Create a new test input file, creating directories as needed
526
527 Args:
Simon Glass3ab95982018-08-01 15:22:37 -0600528 fname: Filename to create
Simon Glass4f443042016-11-25 20:15:52 -0700529 contents: File contents to write in to the file
530 Returns:
531 Full pathname of file created
532 """
Simon Glassb986b3b2019-08-24 07:22:43 -0600533 pathname = os.path.join(cls._indir, fname)
Simon Glass4f443042016-11-25 20:15:52 -0700534 dirname = os.path.dirname(pathname)
535 if dirname and not os.path.exists(dirname):
536 os.makedirs(dirname)
537 with open(pathname, 'wb') as fd:
538 fd.write(contents)
539 return pathname
540
541 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600542 def _MakeInputDir(cls, dirname):
Simon Glass0ef87aa2018-07-17 13:25:44 -0600543 """Create a new test input directory, creating directories as needed
544
545 Args:
546 dirname: Directory name to create
547
548 Returns:
549 Full pathname of directory created
550 """
Simon Glassb986b3b2019-08-24 07:22:43 -0600551 pathname = os.path.join(cls._indir, dirname)
Simon Glass0ef87aa2018-07-17 13:25:44 -0600552 if not os.path.exists(pathname):
553 os.makedirs(pathname)
554 return pathname
555
556 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600557 def _SetupSplElf(cls, src_fname='bss_data'):
Simon Glass11ae93e2018-10-01 21:12:47 -0600558 """Set up an ELF file with a '_dt_ucode_base_size' symbol
559
560 Args:
561 Filename of ELF file to use as SPL
562 """
Simon Glassc9a0b272019-08-24 07:22:59 -0600563 TestFunctional._MakeInputFile('spl/u-boot-spl',
564 tools.ReadFile(cls.ElfTestFile(src_fname)))
Simon Glass11ae93e2018-10-01 21:12:47 -0600565
566 @classmethod
Simon Glass2090f1e2019-08-24 07:23:00 -0600567 def _SetupTplElf(cls, src_fname='bss_data'):
568 """Set up an ELF file with a '_dt_ucode_base_size' symbol
569
570 Args:
571 Filename of ELF file to use as TPL
572 """
573 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
574 tools.ReadFile(cls.ElfTestFile(src_fname)))
575
576 @classmethod
Simon Glass0ba4b3d2020-07-09 18:39:41 -0600577 def _SetupDescriptor(cls):
578 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
579 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
580
581 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600582 def TestFile(cls, fname):
583 return os.path.join(cls._binman_dir, 'test', fname)
Simon Glass4f443042016-11-25 20:15:52 -0700584
Simon Glass53e22bf2019-08-24 07:22:53 -0600585 @classmethod
586 def ElfTestFile(cls, fname):
587 return os.path.join(cls._elf_testdir, fname)
588
Simon Glass4f443042016-11-25 20:15:52 -0700589 def AssertInList(self, grep_list, target):
590 """Assert that at least one of a list of things is in a target
591
592 Args:
593 grep_list: List of strings to check
594 target: Target string
595 """
596 for grep in grep_list:
597 if grep in target:
598 return
Simon Glass1fc62de2019-05-17 22:00:50 -0600599 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass4f443042016-11-25 20:15:52 -0700600
601 def CheckNoGaps(self, entries):
602 """Check that all entries fit together without gaps
603
604 Args:
605 entries: List of entries to check
606 """
Simon Glass3ab95982018-08-01 15:22:37 -0600607 offset = 0
Simon Glass4f443042016-11-25 20:15:52 -0700608 for entry in entries.values():
Simon Glass3ab95982018-08-01 15:22:37 -0600609 self.assertEqual(offset, entry.offset)
610 offset += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700611
Simon Glasse0ff8552016-11-25 20:15:53 -0700612 def GetFdtLen(self, dtb):
Simon Glass7ae5f312018-06-01 09:38:19 -0600613 """Get the totalsize field from a device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700614
615 Args:
Simon Glass7ae5f312018-06-01 09:38:19 -0600616 dtb: Device-tree binary contents
Simon Glasse0ff8552016-11-25 20:15:53 -0700617
618 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600619 Total size of device-tree binary, from the header
Simon Glasse0ff8552016-11-25 20:15:53 -0700620 """
621 return struct.unpack('>L', dtb[4:8])[0]
622
Simon Glass086cec92019-07-08 14:25:27 -0600623 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glass16b8d6b2018-07-06 10:27:42 -0600624 def AddNode(node, path):
625 if node.name != '/':
626 path += '/' + node.name
Simon Glass086cec92019-07-08 14:25:27 -0600627 for prop in node.props.values():
628 if prop.name in prop_names:
629 prop_path = path + ':' + prop.name
630 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
631 prop.value)
Simon Glass16b8d6b2018-07-06 10:27:42 -0600632 for subnode in node.subnodes:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600633 AddNode(subnode, path)
634
635 tree = {}
Simon Glass16b8d6b2018-07-06 10:27:42 -0600636 AddNode(dtb.GetRoot(), '')
637 return tree
638
Simon Glass4f443042016-11-25 20:15:52 -0700639 def testRun(self):
640 """Test a basic run with valid args"""
641 result = self._RunBinman('-h')
642
643 def testFullHelp(self):
644 """Test that the full help is displayed with -H"""
645 result = self._RunBinman('-H')
Simon Glass61adb2d2021-03-18 20:25:13 +1300646 help_file = os.path.join(self._binman_dir, 'README.rst')
Tom Rini3759df02018-01-16 15:29:50 -0500647 # Remove possible extraneous strings
648 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
649 gothelp = result.stdout.replace(extra, '')
650 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass4f443042016-11-25 20:15:52 -0700651 self.assertEqual(0, len(result.stderr))
652 self.assertEqual(0, result.return_code)
653
654 def testFullHelpInternal(self):
655 """Test that the full help is displayed with -H"""
656 try:
657 command.test_result = command.CommandResult()
658 result = self._DoBinman('-H')
Simon Glass61adb2d2021-03-18 20:25:13 +1300659 help_file = os.path.join(self._binman_dir, 'README.rst')
Simon Glass4f443042016-11-25 20:15:52 -0700660 finally:
661 command.test_result = None
662
663 def testHelp(self):
664 """Test that the basic help is displayed with -h"""
665 result = self._RunBinman('-h')
666 self.assertTrue(len(result.stdout) > 200)
667 self.assertEqual(0, len(result.stderr))
668 self.assertEqual(0, result.return_code)
669
Simon Glass4f443042016-11-25 20:15:52 -0700670 def testBoard(self):
671 """Test that we can run it with a specific board"""
Simon Glass741f2d62018-10-01 12:22:30 -0600672 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass4f443042016-11-25 20:15:52 -0700673 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glass63aeaeb2021-03-18 20:25:05 +1300674 result = self._DoBinman('build', '-n', '-b', 'sandbox')
Simon Glass4f443042016-11-25 20:15:52 -0700675 self.assertEqual(0, result)
676
677 def testNeedBoard(self):
678 """Test that we get an error when no board ius supplied"""
679 with self.assertRaises(ValueError) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600680 result = self._DoBinman('build')
Simon Glass4f443042016-11-25 20:15:52 -0700681 self.assertIn("Must provide a board to process (use -b <board>)",
682 str(e.exception))
683
684 def testMissingDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600685 """Test that an invalid device-tree file generates an error"""
Simon Glass4f443042016-11-25 20:15:52 -0700686 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600687 self._RunBinman('build', '-d', 'missing_file')
Simon Glass4f443042016-11-25 20:15:52 -0700688 # We get one error from libfdt, and a different one from fdtget.
689 self.AssertInList(["Couldn't open blob from 'missing_file'",
690 'No such file or directory'], str(e.exception))
691
692 def testBrokenDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600693 """Test that an invalid device-tree source file generates an error
Simon Glass4f443042016-11-25 20:15:52 -0700694
695 Since this is a source file it should be compiled and the error
696 will come from the device-tree compiler (dtc).
697 """
698 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600699 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700700 self.assertIn("FATAL ERROR: Unable to parse input tree",
701 str(e.exception))
702
703 def testMissingNode(self):
704 """Test that a device tree without a 'binman' node generates an error"""
705 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600706 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700707 self.assertIn("does not have a 'binman' node", str(e.exception))
708
709 def testEmpty(self):
710 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glass53cd5d92019-07-08 14:25:29 -0600711 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700712 self.assertEqual(0, len(result.stderr))
713 self.assertEqual(0, result.return_code)
714
715 def testInvalidEntry(self):
716 """Test that an invalid entry is flagged"""
717 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600718 result = self._RunBinman('build', '-d',
Simon Glass741f2d62018-10-01 12:22:30 -0600719 self.TestFile('004_invalid_entry.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700720 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
721 "'/binman/not-a-valid-type'", str(e.exception))
722
723 def testSimple(self):
724 """Test a simple binman with a single file"""
Simon Glass741f2d62018-10-01 12:22:30 -0600725 data = self._DoReadFile('005_simple.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700726 self.assertEqual(U_BOOT_DATA, data)
727
Simon Glass7fe91732017-11-13 18:55:00 -0700728 def testSimpleDebug(self):
729 """Test a simple binman run with debugging enabled"""
Simon Glasse2705fa2019-07-08 14:25:53 -0600730 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass7fe91732017-11-13 18:55:00 -0700731
Simon Glass4f443042016-11-25 20:15:52 -0700732 def testDual(self):
733 """Test that we can handle creating two images
734
735 This also tests image padding.
736 """
Simon Glass741f2d62018-10-01 12:22:30 -0600737 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700738 self.assertEqual(0, retcode)
739
740 image = control.images['image1']
Simon Glass8beb11e2019-07-08 14:25:47 -0600741 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700742 fname = tools.GetOutputFilename('image1.bin')
743 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600744 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700745 data = fd.read()
746 self.assertEqual(U_BOOT_DATA, data)
747
748 image = control.images['image2']
Simon Glass8beb11e2019-07-08 14:25:47 -0600749 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700750 fname = tools.GetOutputFilename('image2.bin')
751 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600752 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700753 data = fd.read()
754 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glasse6d85ff2019-05-14 15:53:47 -0600755 self.assertEqual(tools.GetBytes(0, 3), data[:3])
756 self.assertEqual(tools.GetBytes(0, 5), data[7:])
Simon Glass4f443042016-11-25 20:15:52 -0700757
758 def testBadAlign(self):
759 """Test that an invalid alignment value is detected"""
760 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600761 self._DoTestFile('007_bad_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700762 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
763 "of two", str(e.exception))
764
765 def testPackSimple(self):
766 """Test that packing works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600767 retcode = self._DoTestFile('008_pack.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700768 self.assertEqual(0, retcode)
769 self.assertIn('image', control.images)
770 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600771 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700772 self.assertEqual(5, len(entries))
773
774 # First u-boot
775 self.assertIn('u-boot', entries)
776 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600777 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700778 self.assertEqual(len(U_BOOT_DATA), entry.size)
779
780 # Second u-boot, aligned to 16-byte boundary
781 self.assertIn('u-boot-align', entries)
782 entry = entries['u-boot-align']
Simon Glass3ab95982018-08-01 15:22:37 -0600783 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700784 self.assertEqual(len(U_BOOT_DATA), entry.size)
785
786 # Third u-boot, size 23 bytes
787 self.assertIn('u-boot-size', entries)
788 entry = entries['u-boot-size']
Simon Glass3ab95982018-08-01 15:22:37 -0600789 self.assertEqual(20, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700790 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
791 self.assertEqual(23, entry.size)
792
793 # Fourth u-boot, placed immediate after the above
794 self.assertIn('u-boot-next', entries)
795 entry = entries['u-boot-next']
Simon Glass3ab95982018-08-01 15:22:37 -0600796 self.assertEqual(43, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700797 self.assertEqual(len(U_BOOT_DATA), entry.size)
798
Simon Glass3ab95982018-08-01 15:22:37 -0600799 # Fifth u-boot, placed at a fixed offset
Simon Glass4f443042016-11-25 20:15:52 -0700800 self.assertIn('u-boot-fixed', entries)
801 entry = entries['u-boot-fixed']
Simon Glass3ab95982018-08-01 15:22:37 -0600802 self.assertEqual(61, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700803 self.assertEqual(len(U_BOOT_DATA), entry.size)
804
Simon Glass8beb11e2019-07-08 14:25:47 -0600805 self.assertEqual(65, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700806
807 def testPackExtra(self):
808 """Test that extra packing feature works as expected"""
Simon Glass4eec34c2020-10-26 17:40:10 -0600809 data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
810 update_dtb=True)
Simon Glass4f443042016-11-25 20:15:52 -0700811
Simon Glass4f443042016-11-25 20:15:52 -0700812 self.assertIn('image', control.images)
813 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600814 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700815 self.assertEqual(5, len(entries))
816
817 # First u-boot with padding before and after
818 self.assertIn('u-boot', entries)
819 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600820 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700821 self.assertEqual(3, entry.pad_before)
822 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600823 self.assertEqual(U_BOOT_DATA, entry.data)
824 self.assertEqual(tools.GetBytes(0, 3) + U_BOOT_DATA +
825 tools.GetBytes(0, 5), data[:entry.size])
826 pos = entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700827
828 # Second u-boot has an aligned size, but it has no effect
829 self.assertIn('u-boot-align-size-nop', entries)
830 entry = entries['u-boot-align-size-nop']
Simon Glassef439ed2020-10-26 17:40:08 -0600831 self.assertEqual(pos, entry.offset)
832 self.assertEqual(len(U_BOOT_DATA), entry.size)
833 self.assertEqual(U_BOOT_DATA, entry.data)
834 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
835 pos += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700836
837 # Third u-boot has an aligned size too
838 self.assertIn('u-boot-align-size', entries)
839 entry = entries['u-boot-align-size']
Simon Glassef439ed2020-10-26 17:40:08 -0600840 self.assertEqual(pos, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700841 self.assertEqual(32, entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600842 self.assertEqual(U_BOOT_DATA, entry.data)
843 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 32 - len(U_BOOT_DATA)),
844 data[pos:pos + entry.size])
845 pos += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700846
847 # Fourth u-boot has an aligned end
848 self.assertIn('u-boot-align-end', entries)
849 entry = entries['u-boot-align-end']
Simon Glass3ab95982018-08-01 15:22:37 -0600850 self.assertEqual(48, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700851 self.assertEqual(16, 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, 16 - len(U_BOOT_DATA)),
854 data[pos:pos + entry.size])
855 pos += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700856
857 # Fifth u-boot immediately afterwards
858 self.assertIn('u-boot-align-both', entries)
859 entry = entries['u-boot-align-both']
Simon Glass3ab95982018-08-01 15:22:37 -0600860 self.assertEqual(64, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700861 self.assertEqual(64, entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600862 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
863 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 64 - len(U_BOOT_DATA)),
864 data[pos:pos + entry.size])
Simon Glass4f443042016-11-25 20:15:52 -0700865
866 self.CheckNoGaps(entries)
Simon Glass8beb11e2019-07-08 14:25:47 -0600867 self.assertEqual(128, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700868
Simon Glass4eec34c2020-10-26 17:40:10 -0600869 dtb = fdt.Fdt(out_dtb_fname)
870 dtb.Scan()
871 props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
872 expected = {
873 'image-pos': 0,
874 'offset': 0,
875 'size': 128,
876
877 'u-boot:image-pos': 0,
878 'u-boot:offset': 0,
879 'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
880
881 'u-boot-align-size-nop:image-pos': 12,
882 'u-boot-align-size-nop:offset': 12,
883 'u-boot-align-size-nop:size': 4,
884
885 'u-boot-align-size:image-pos': 16,
886 'u-boot-align-size:offset': 16,
887 'u-boot-align-size:size': 32,
888
889 'u-boot-align-end:image-pos': 48,
890 'u-boot-align-end:offset': 48,
891 'u-boot-align-end:size': 16,
892
893 'u-boot-align-both:image-pos': 64,
894 'u-boot-align-both:offset': 64,
895 'u-boot-align-both:size': 64,
896 }
897 self.assertEqual(expected, props)
898
Simon Glass4f443042016-11-25 20:15:52 -0700899 def testPackAlignPowerOf2(self):
900 """Test that invalid entry alignment is detected"""
901 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600902 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700903 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
904 "of two", str(e.exception))
905
906 def testPackAlignSizePowerOf2(self):
907 """Test that invalid entry size alignment is detected"""
908 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600909 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700910 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
911 "power of two", str(e.exception))
912
913 def testPackInvalidAlign(self):
Simon Glass3ab95982018-08-01 15:22:37 -0600914 """Test detection of an offset that does not match its alignment"""
Simon Glass4f443042016-11-25 20:15:52 -0700915 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600916 self._DoTestFile('012_pack_inv_align.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600917 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700918 "align 0x4 (4)", str(e.exception))
919
920 def testPackInvalidSizeAlign(self):
921 """Test that invalid entry size alignment is detected"""
922 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600923 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700924 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
925 "align-size 0x4 (4)", str(e.exception))
926
927 def testPackOverlap(self):
928 """Test that overlapping regions are detected"""
929 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600930 self._DoTestFile('014_pack_overlap.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600931 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -0700932 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
933 str(e.exception))
934
935 def testPackEntryOverflow(self):
936 """Test that entries that overflow their size are detected"""
937 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600938 self._DoTestFile('015_pack_overflow.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700939 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
940 "but entry size is 0x3 (3)", str(e.exception))
941
942 def testPackImageOverflow(self):
943 """Test that entries which overflow the image size are detected"""
944 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600945 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600946 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass4f443042016-11-25 20:15:52 -0700947 "size 0x3 (3)", str(e.exception))
948
949 def testPackImageSize(self):
950 """Test that the image size can be set"""
Simon Glass741f2d62018-10-01 12:22:30 -0600951 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700952 self.assertEqual(0, retcode)
953 self.assertIn('image', control.images)
954 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -0600955 self.assertEqual(7, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700956
957 def testPackImageSizeAlign(self):
958 """Test that image size alignemnt works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600959 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700960 self.assertEqual(0, retcode)
961 self.assertIn('image', control.images)
962 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -0600963 self.assertEqual(16, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700964
965 def testPackInvalidImageAlign(self):
966 """Test that invalid image alignment is detected"""
967 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600968 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600969 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700970 "align-size 0x8 (8)", str(e.exception))
971
972 def testPackAlignPowerOf2(self):
973 """Test that invalid image alignment is detected"""
974 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600975 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -0600976 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass4f443042016-11-25 20:15:52 -0700977 "two", str(e.exception))
978
979 def testImagePadByte(self):
980 """Test that the image pad byte can be specified"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600981 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600982 data = self._DoReadFile('021_image_pad.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -0600983 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0xff, 1) +
984 U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -0700985
986 def testImageName(self):
987 """Test that image files can be named"""
Simon Glass741f2d62018-10-01 12:22:30 -0600988 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700989 self.assertEqual(0, retcode)
990 image = control.images['image1']
991 fname = tools.GetOutputFilename('test-name')
992 self.assertTrue(os.path.exists(fname))
993
994 image = control.images['image2']
995 fname = tools.GetOutputFilename('test-name.xx')
996 self.assertTrue(os.path.exists(fname))
997
998 def testBlobFilename(self):
999 """Test that generic blobs can be provided by filename"""
Simon Glass741f2d62018-10-01 12:22:30 -06001000 data = self._DoReadFile('023_blob.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001001 self.assertEqual(BLOB_DATA, data)
1002
1003 def testPackSorted(self):
1004 """Test that entries can be sorted"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001005 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001006 data = self._DoReadFile('024_sorted.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001007 self.assertEqual(tools.GetBytes(0, 1) + U_BOOT_SPL_DATA +
1008 tools.GetBytes(0, 2) + U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -07001009
Simon Glass3ab95982018-08-01 15:22:37 -06001010 def testPackZeroOffset(self):
1011 """Test that an entry at offset 0 is not given a new offset"""
Simon Glass4f443042016-11-25 20:15:52 -07001012 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001013 self._DoTestFile('025_pack_zero_size.dts')
Simon Glass3ab95982018-08-01 15:22:37 -06001014 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -07001015 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1016 str(e.exception))
1017
1018 def testPackUbootDtb(self):
1019 """Test that a device tree can be added to U-Boot"""
Simon Glass741f2d62018-10-01 12:22:30 -06001020 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001021 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glasse0ff8552016-11-25 20:15:53 -07001022
1023 def testPackX86RomNoSize(self):
1024 """Test that the end-at-4gb property requires a size property"""
1025 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001026 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -06001027 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glasse0ff8552016-11-25 20:15:53 -07001028 "using end-at-4gb", str(e.exception))
1029
Jagdish Gediya94b57db2018-09-03 21:35:07 +05301030 def test4gbAndSkipAtStartTogether(self):
1031 """Test that the end-at-4gb and skip-at-size property can't be used
1032 together"""
1033 with self.assertRaises(ValueError) as e:
Simon Glassdfdd2b62019-08-24 07:23:02 -06001034 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -06001035 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya94b57db2018-09-03 21:35:07 +05301036 "'skip-at-start'", str(e.exception))
1037
Simon Glasse0ff8552016-11-25 20:15:53 -07001038 def testPackX86RomOutside(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001039 """Test that the end-at-4gb property checks for offset boundaries"""
Simon Glasse0ff8552016-11-25 20:15:53 -07001040 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001041 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glasse6bed4f2020-10-26 17:40:05 -06001042 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
1043 "is outside the section '/binman' starting at "
1044 '0xffffffe0 (4294967264) of size 0x20 (32)',
Simon Glasse0ff8552016-11-25 20:15:53 -07001045 str(e.exception))
1046
1047 def testPackX86Rom(self):
1048 """Test that a basic x86 ROM can be created"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001049 self._SetupSplElf()
Simon Glass9255f3c2019-08-24 07:23:01 -06001050 data = self._DoReadFile('029_x86_rom.dts')
Simon Glasseb0086f2019-08-24 07:23:04 -06001051 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 3) + U_BOOT_SPL_DATA +
Simon Glasse6d85ff2019-05-14 15:53:47 -06001052 tools.GetBytes(0, 2), data)
Simon Glasse0ff8552016-11-25 20:15:53 -07001053
1054 def testPackX86RomMeNoDesc(self):
1055 """Test that an invalid Intel descriptor entry is detected"""
Simon Glass0ba4b3d2020-07-09 18:39:41 -06001056 try:
Simon Glass52b10dd2020-07-25 15:11:19 -06001057 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
Simon Glass0ba4b3d2020-07-09 18:39:41 -06001058 with self.assertRaises(ValueError) as e:
Simon Glass52b10dd2020-07-25 15:11:19 -06001059 self._DoTestFile('163_x86_rom_me_empty.dts')
Simon Glass0ba4b3d2020-07-09 18:39:41 -06001060 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1061 str(e.exception))
1062 finally:
1063 self._SetupDescriptor()
Simon Glasse0ff8552016-11-25 20:15:53 -07001064
1065 def testPackX86RomBadDesc(self):
1066 """Test that the Intel requires a descriptor entry"""
1067 with self.assertRaises(ValueError) as e:
Simon Glass9255f3c2019-08-24 07:23:01 -06001068 self._DoTestFile('030_x86_rom_me_no_desc.dts')
Simon Glass3ab95982018-08-01 15:22:37 -06001069 self.assertIn("Node '/binman/intel-me': No offset set with "
1070 "offset-unset: should another entry provide this correct "
1071 "offset?", str(e.exception))
Simon Glasse0ff8552016-11-25 20:15:53 -07001072
1073 def testPackX86RomMe(self):
1074 """Test that an x86 ROM with an ME region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001075 data = self._DoReadFile('031_x86_rom_me.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06001076 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
1077 if data[:0x1000] != expected_desc:
1078 self.fail('Expected descriptor binary at start of image')
Simon Glasse0ff8552016-11-25 20:15:53 -07001079 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1080
1081 def testPackVga(self):
1082 """Test that an image with a VGA binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001083 data = self._DoReadFile('032_intel_vga.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -07001084 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1085
1086 def testPackStart16(self):
1087 """Test that an image with an x86 start16 region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001088 data = self._DoReadFile('033_x86_start16.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -07001089 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1090
Jagdish Gediya9d368f32018-09-03 21:35:08 +05301091 def testPackPowerpcMpc85xxBootpgResetvec(self):
1092 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1093 created"""
Simon Glassdfdd2b62019-08-24 07:23:02 -06001094 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
Jagdish Gediya9d368f32018-09-03 21:35:08 +05301095 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1096
Simon Glass736bb0a2018-07-06 10:27:17 -06001097 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glassadc57012018-07-06 10:27:16 -06001098 """Handle running a test for insertion of microcode
1099
1100 Args:
1101 dts_fname: Name of test .dts file
1102 nodtb_data: Data that we expect in the first section
Simon Glass736bb0a2018-07-06 10:27:17 -06001103 ucode_second: True if the microsecond entry is second instead of
1104 third
Simon Glassadc57012018-07-06 10:27:16 -06001105
1106 Returns:
1107 Tuple:
1108 Contents of first region (U-Boot or SPL)
Simon Glass3ab95982018-08-01 15:22:37 -06001109 Offset and size components of microcode pointer, as inserted
Simon Glassadc57012018-07-06 10:27:16 -06001110 in the above (two 4-byte words)
1111 """
Simon Glass6b187df2017-11-12 21:52:27 -07001112 data = self._DoReadFile(dts_fname, True)
Simon Glasse0ff8552016-11-25 20:15:53 -07001113
1114 # Now check the device tree has no microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001115 if ucode_second:
1116 ucode_content = data[len(nodtb_data):]
1117 ucode_pos = len(nodtb_data)
1118 dtb_with_ucode = ucode_content[16:]
1119 fdt_len = self.GetFdtLen(dtb_with_ucode)
1120 else:
1121 dtb_with_ucode = data[len(nodtb_data):]
1122 fdt_len = self.GetFdtLen(dtb_with_ucode)
1123 ucode_content = dtb_with_ucode[fdt_len:]
1124 ucode_pos = len(nodtb_data) + fdt_len
Simon Glasse0ff8552016-11-25 20:15:53 -07001125 fname = tools.GetOutputFilename('test.dtb')
1126 with open(fname, 'wb') as fd:
Simon Glassadc57012018-07-06 10:27:16 -06001127 fd.write(dtb_with_ucode)
Simon Glassec3f3782017-05-27 07:38:29 -06001128 dtb = fdt.FdtScan(fname)
1129 ucode = dtb.GetNode('/microcode')
Simon Glasse0ff8552016-11-25 20:15:53 -07001130 self.assertTrue(ucode)
1131 for node in ucode.subnodes:
1132 self.assertFalse(node.props.get('data'))
1133
Simon Glasse0ff8552016-11-25 20:15:53 -07001134 # Check that the microcode appears immediately after the Fdt
1135 # This matches the concatenation of the data properties in
Simon Glass87722132017-11-12 21:52:26 -07001136 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glasse0ff8552016-11-25 20:15:53 -07001137 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1138 0x78235609)
Simon Glassadc57012018-07-06 10:27:16 -06001139 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glasse0ff8552016-11-25 20:15:53 -07001140
1141 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -06001142 # expected offset and size
Simon Glasse0ff8552016-11-25 20:15:53 -07001143 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1144 len(ucode_data))
Simon Glass736bb0a2018-07-06 10:27:17 -06001145 u_boot = data[:len(nodtb_data)]
1146 return u_boot, pos_and_size
Simon Glass6b187df2017-11-12 21:52:27 -07001147
1148 def testPackUbootMicrocode(self):
1149 """Test that x86 microcode can be handled correctly
1150
1151 We expect to see the following in the image, in order:
1152 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1153 place
1154 u-boot.dtb with the microcode removed
1155 the microcode
1156 """
Simon Glass741f2d62018-10-01 12:22:30 -06001157 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass6b187df2017-11-12 21:52:27 -07001158 U_BOOT_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001159 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1160 b' somewhere in here', first)
Simon Glasse0ff8552016-11-25 20:15:53 -07001161
Simon Glass160a7662017-05-27 07:38:26 -06001162 def _RunPackUbootSingleMicrocode(self):
Simon Glasse0ff8552016-11-25 20:15:53 -07001163 """Test that x86 microcode can be handled correctly
1164
1165 We expect to see the following in the image, in order:
1166 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1167 place
1168 u-boot.dtb with the microcode
1169 an empty microcode region
1170 """
1171 # We need the libfdt library to run this test since only that allows
1172 # finding the offset of a property. This is required by
1173 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass741f2d62018-10-01 12:22:30 -06001174 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glasse0ff8552016-11-25 20:15:53 -07001175
1176 second = data[len(U_BOOT_NODTB_DATA):]
1177
1178 fdt_len = self.GetFdtLen(second)
1179 third = second[fdt_len:]
1180 second = second[:fdt_len]
1181
Simon Glass160a7662017-05-27 07:38:26 -06001182 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1183 self.assertIn(ucode_data, second)
1184 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -07001185
Simon Glass160a7662017-05-27 07:38:26 -06001186 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -06001187 # expected offset and size
Simon Glass160a7662017-05-27 07:38:26 -06001188 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1189 len(ucode_data))
1190 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glassc6c10e72019-05-17 22:00:46 -06001191 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1192 b' somewhere in here', first)
Simon Glassc49deb82016-11-25 20:15:54 -07001193
Simon Glass75db0862016-11-25 20:15:55 -07001194 def testPackUbootSingleMicrocode(self):
1195 """Test that x86 microcode can be handled correctly with fdt_normal.
1196 """
Simon Glass160a7662017-05-27 07:38:26 -06001197 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001198
Simon Glassc49deb82016-11-25 20:15:54 -07001199 def testUBootImg(self):
1200 """Test that u-boot.img can be put in a file"""
Simon Glass741f2d62018-10-01 12:22:30 -06001201 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glassc49deb82016-11-25 20:15:54 -07001202 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glass75db0862016-11-25 20:15:55 -07001203
1204 def testNoMicrocode(self):
1205 """Test that a missing microcode region is detected"""
1206 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001207 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001208 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1209 "node found in ", str(e.exception))
1210
1211 def testMicrocodeWithoutNode(self):
1212 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1213 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001214 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001215 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1216 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1217
1218 def testMicrocodeWithoutNode2(self):
1219 """Test that a missing u-boot-ucode node is detected"""
1220 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001221 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001222 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1223 "microcode region u-boot-ucode", str(e.exception))
1224
1225 def testMicrocodeWithoutPtrInElf(self):
1226 """Test that a U-Boot binary without the microcode symbol is detected"""
1227 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glass75db0862016-11-25 20:15:55 -07001228 try:
Simon Glassbccd91d2019-08-24 07:22:55 -06001229 TestFunctional._MakeInputFile('u-boot',
1230 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass75db0862016-11-25 20:15:55 -07001231
1232 with self.assertRaises(ValueError) as e:
Simon Glass160a7662017-05-27 07:38:26 -06001233 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001234 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1235 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1236
1237 finally:
1238 # Put the original file back
Simon Glassf514d8f2019-08-24 07:22:54 -06001239 TestFunctional._MakeInputFile('u-boot',
1240 tools.ReadFile(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glass75db0862016-11-25 20:15:55 -07001241
1242 def testMicrocodeNotInImage(self):
1243 """Test that microcode must be placed within the image"""
1244 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001245 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001246 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1247 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glass25ac0e62018-06-01 09:38:14 -06001248 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glass75db0862016-11-25 20:15:55 -07001249
1250 def testWithoutMicrocode(self):
1251 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glassbccd91d2019-08-24 07:22:55 -06001252 TestFunctional._MakeInputFile('u-boot',
1253 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass741f2d62018-10-01 12:22:30 -06001254 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001255
1256 # Now check the device tree has no microcode
1257 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1258 second = data[len(U_BOOT_NODTB_DATA):]
1259
1260 fdt_len = self.GetFdtLen(second)
1261 self.assertEqual(dtb, second[:fdt_len])
1262
1263 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1264 third = data[used_len:]
Simon Glasse6d85ff2019-05-14 15:53:47 -06001265 self.assertEqual(tools.GetBytes(0, 0x200 - used_len), third)
Simon Glass75db0862016-11-25 20:15:55 -07001266
1267 def testUnknownPosSize(self):
1268 """Test that microcode must be placed within the image"""
1269 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001270 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glass3ab95982018-08-01 15:22:37 -06001271 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glass75db0862016-11-25 20:15:55 -07001272 "entry 'invalid-entry'", str(e.exception))
Simon Glassda229092016-11-25 20:15:56 -07001273
1274 def testPackFsp(self):
1275 """Test that an image with a FSP binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001276 data = self._DoReadFile('042_intel_fsp.dts')
Simon Glassda229092016-11-25 20:15:56 -07001277 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1278
1279 def testPackCmc(self):
Bin Meng59ea8c22017-08-15 22:41:54 -07001280 """Test that an image with a CMC binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001281 data = self._DoReadFile('043_intel_cmc.dts')
Simon Glassda229092016-11-25 20:15:56 -07001282 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Meng59ea8c22017-08-15 22:41:54 -07001283
1284 def testPackVbt(self):
1285 """Test that an image with a VBT binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001286 data = self._DoReadFile('046_intel_vbt.dts')
Bin Meng59ea8c22017-08-15 22:41:54 -07001287 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glass9fc60b42017-11-12 21:52:22 -07001288
Simon Glass56509842017-11-12 21:52:25 -07001289 def testSplBssPad(self):
1290 """Test that we can pad SPL's BSS with zeros"""
Simon Glass6b187df2017-11-12 21:52:27 -07001291 # ELF file with a '__bss_size' symbol
Simon Glass11ae93e2018-10-01 21:12:47 -06001292 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001293 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001294 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
1295 data)
Simon Glass56509842017-11-12 21:52:25 -07001296
Simon Glass86af5112018-10-01 21:12:42 -06001297 def testSplBssPadMissing(self):
1298 """Test that a missing symbol is detected"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001299 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glassb50e5612017-11-13 18:54:54 -07001300 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001301 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassb50e5612017-11-13 18:54:54 -07001302 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1303 str(e.exception))
1304
Simon Glass87722132017-11-12 21:52:26 -07001305 def testPackStart16Spl(self):
Simon Glass35b384c2018-09-14 04:57:10 -06001306 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001307 data = self._DoReadFile('048_x86_start16_spl.dts')
Simon Glass87722132017-11-12 21:52:26 -07001308 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1309
Simon Glass736bb0a2018-07-06 10:27:17 -06001310 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1311 """Helper function for microcode tests
Simon Glass6b187df2017-11-12 21:52:27 -07001312
1313 We expect to see the following in the image, in order:
1314 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1315 correct place
1316 u-boot.dtb with the microcode removed
1317 the microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001318
1319 Args:
1320 dts: Device tree file to use for test
1321 ucode_second: True if the microsecond entry is second instead of
1322 third
Simon Glass6b187df2017-11-12 21:52:27 -07001323 """
Simon Glass11ae93e2018-10-01 21:12:47 -06001324 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass736bb0a2018-07-06 10:27:17 -06001325 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1326 ucode_second=ucode_second)
Simon Glassc6c10e72019-05-17 22:00:46 -06001327 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1328 b'ter somewhere in here', first)
Simon Glass6b187df2017-11-12 21:52:27 -07001329
Simon Glass736bb0a2018-07-06 10:27:17 -06001330 def testPackUbootSplMicrocode(self):
1331 """Test that x86 microcode can be handled correctly in SPL"""
Simon Glass741f2d62018-10-01 12:22:30 -06001332 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass736bb0a2018-07-06 10:27:17 -06001333
1334 def testPackUbootSplMicrocodeReorder(self):
1335 """Test that order doesn't matter for microcode entries
1336
1337 This is the same as testPackUbootSplMicrocode but when we process the
1338 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1339 entry, so we reply on binman to try later.
1340 """
Simon Glass741f2d62018-10-01 12:22:30 -06001341 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass736bb0a2018-07-06 10:27:17 -06001342 ucode_second=True)
1343
Simon Glassca4f4ff2017-11-12 21:52:28 -07001344 def testPackMrc(self):
1345 """Test that an image with an MRC binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001346 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassca4f4ff2017-11-12 21:52:28 -07001347 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1348
Simon Glass47419ea2017-11-13 18:54:55 -07001349 def testSplDtb(self):
1350 """Test that an image with spl/u-boot-spl.dtb can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001351 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass47419ea2017-11-13 18:54:55 -07001352 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1353
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001354 def testSplNoDtb(self):
1355 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass0fe44dc2021-04-25 08:39:32 +12001356 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001357 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001358 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1359
Simon Glass3d433382021-03-21 18:24:30 +13001360 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
1361 use_expanded=False):
Simon Glassf5898822021-03-18 20:24:56 +13001362 """Check the image contains the expected symbol values
1363
1364 Args:
1365 dts: Device tree file to use for test
1366 base_data: Data before and after 'u-boot' section
1367 u_boot_offset: Offset of 'u-boot' section in image
Simon Glass3d433382021-03-21 18:24:30 +13001368 entry_args: Dict of entry args to supply to binman
1369 key: arg name
1370 value: value of that arg
1371 use_expanded: True to use expanded entries where available, e.g.
1372 'u-boot-expanded' instead of 'u-boot'
Simon Glassf5898822021-03-18 20:24:56 +13001373 """
Simon Glass1542c8b2019-08-24 07:22:56 -06001374 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass19790632017-11-13 18:55:01 -07001375 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1376 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Simon Glassf5898822021-03-18 20:24:56 +13001377 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
1378 addr)
Simon Glass19790632017-11-13 18:55:01 -07001379
Simon Glass11ae93e2018-10-01 21:12:47 -06001380 self._SetupSplElf('u_boot_binman_syms')
Simon Glass3d433382021-03-21 18:24:30 +13001381 data = self._DoReadFileDtb(dts, entry_args=entry_args,
1382 use_expanded=use_expanded)[0]
Simon Glassf5898822021-03-18 20:24:56 +13001383 # The image should contain the symbols from u_boot_binman_syms.c
1384 # Note that image_pos is adjusted by the base address of the image,
1385 # which is 0x10 in our test image
1386 sym_values = struct.pack('<LQLL', 0x00,
1387 u_boot_offset + len(U_BOOT_DATA),
1388 0x10 + u_boot_offset, 0x04)
1389 expected = (sym_values + base_data[20:] +
Simon Glasse6d85ff2019-05-14 15:53:47 -06001390 tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
Simon Glassf5898822021-03-18 20:24:56 +13001391 base_data[20:])
Simon Glass19790632017-11-13 18:55:01 -07001392 self.assertEqual(expected, data)
1393
Simon Glassf5898822021-03-18 20:24:56 +13001394 def testSymbols(self):
1395 """Test binman can assign symbols embedded in U-Boot"""
1396 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x18)
1397
1398 def testSymbolsNoDtb(self):
1399 """Test binman can assign symbols embedded in U-Boot SPL"""
Simon Glasse9e0db82021-03-21 18:24:29 +13001400 self.checkSymbols('196_symbols_nodtb.dts',
Simon Glassf5898822021-03-18 20:24:56 +13001401 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1402 0x38)
1403
Simon Glassdd57c132018-06-01 09:38:11 -06001404 def testPackUnitAddress(self):
1405 """Test that we support multiple binaries with the same name"""
Simon Glass741f2d62018-10-01 12:22:30 -06001406 data = self._DoReadFile('054_unit_address.dts')
Simon Glassdd57c132018-06-01 09:38:11 -06001407 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1408
Simon Glass18546952018-06-01 09:38:16 -06001409 def testSections(self):
1410 """Basic test of sections"""
Simon Glass741f2d62018-10-01 12:22:30 -06001411 data = self._DoReadFile('055_sections.dts')
Simon Glassc6c10e72019-05-17 22:00:46 -06001412 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1413 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
1414 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
Simon Glass18546952018-06-01 09:38:16 -06001415 self.assertEqual(expected, data)
Simon Glass9fc60b42017-11-12 21:52:22 -07001416
Simon Glass3b0c38212018-06-01 09:38:20 -06001417 def testMap(self):
1418 """Tests outputting a map of the images"""
Simon Glass741f2d62018-10-01 12:22:30 -06001419 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001420 self.assertEqual('''ImagePos Offset Size Name
142100000000 00000000 00000028 main-section
142200000000 00000000 00000010 section@0
142300000000 00000000 00000004 u-boot
142400000010 00000010 00000010 section@1
142500000010 00000000 00000004 u-boot
142600000020 00000020 00000004 section@2
142700000020 00000000 00000004 u-boot
Simon Glass3b0c38212018-06-01 09:38:20 -06001428''', map_data)
1429
Simon Glassc8d48ef2018-06-01 09:38:21 -06001430 def testNamePrefix(self):
1431 """Tests that name prefixes are used"""
Simon Glass741f2d62018-10-01 12:22:30 -06001432 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001433 self.assertEqual('''ImagePos Offset Size Name
143400000000 00000000 00000028 main-section
143500000000 00000000 00000010 section@0
143600000000 00000000 00000004 ro-u-boot
143700000010 00000010 00000010 section@1
143800000010 00000000 00000004 rw-u-boot
Simon Glassc8d48ef2018-06-01 09:38:21 -06001439''', map_data)
1440
Simon Glass736bb0a2018-07-06 10:27:17 -06001441 def testUnknownContents(self):
1442 """Test that obtaining the contents works as expected"""
1443 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001444 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass8beb11e2019-07-08 14:25:47 -06001445 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glass16287932020-04-17 18:09:03 -06001446 "processing of contents: remaining ["
1447 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass736bb0a2018-07-06 10:27:17 -06001448
Simon Glass5c890232018-07-06 10:27:19 -06001449 def testBadChangeSize(self):
1450 """Test that trying to change the size of an entry fails"""
Simon Glassc52c9e72019-07-08 14:25:37 -06001451 try:
1452 state.SetAllowEntryExpansion(False)
1453 with self.assertRaises(ValueError) as e:
1454 self._DoReadFile('059_change_size.dts', True)
Simon Glass79d3c582019-07-20 12:23:57 -06001455 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glassc52c9e72019-07-08 14:25:37 -06001456 str(e.exception))
1457 finally:
1458 state.SetAllowEntryExpansion(True)
Simon Glass5c890232018-07-06 10:27:19 -06001459
Simon Glass16b8d6b2018-07-06 10:27:42 -06001460 def testUpdateFdt(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001461 """Test that we can update the device tree with offset/size info"""
Simon Glass741f2d62018-10-01 12:22:30 -06001462 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glass16b8d6b2018-07-06 10:27:42 -06001463 update_dtb=True)
Simon Glasscee02e62018-07-17 13:25:52 -06001464 dtb = fdt.Fdt(out_dtb_fname)
1465 dtb.Scan()
Simon Glass12bb1a92019-07-20 12:23:51 -06001466 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001467 self.assertEqual({
Simon Glassdbf6be92018-08-01 15:22:42 -06001468 'image-pos': 0,
Simon Glass8122f392018-07-17 13:25:28 -06001469 'offset': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001470 '_testing:offset': 32,
Simon Glass79d3c582019-07-20 12:23:57 -06001471 '_testing:size': 2,
Simon Glassdbf6be92018-08-01 15:22:42 -06001472 '_testing:image-pos': 32,
Simon Glass3ab95982018-08-01 15:22:37 -06001473 'section@0/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001474 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001475 'section@0/u-boot:image-pos': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001476 'section@0:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001477 'section@0:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001478 'section@0:image-pos': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001479
Simon Glass3ab95982018-08-01 15:22:37 -06001480 'section@1/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001481 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001482 'section@1/u-boot:image-pos': 16,
Simon Glass3ab95982018-08-01 15:22:37 -06001483 'section@1:offset': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001484 'section@1:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001485 'section@1:image-pos': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001486 'size': 40
1487 }, props)
1488
1489 def testUpdateFdtBad(self):
1490 """Test that we detect when ProcessFdt never completes"""
1491 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001492 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001493 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glass16287932020-04-17 18:09:03 -06001494 '[<binman.etype._testing.Entry__testing',
1495 str(e.exception))
Simon Glass5c890232018-07-06 10:27:19 -06001496
Simon Glass53af22a2018-07-17 13:25:32 -06001497 def testEntryArgs(self):
1498 """Test passing arguments to entries from the command line"""
1499 entry_args = {
1500 'test-str-arg': 'test1',
1501 'test-int-arg': '456',
1502 }
Simon Glass741f2d62018-10-01 12:22:30 -06001503 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001504 self.assertIn('image', control.images)
1505 entry = control.images['image'].GetEntries()['_testing']
1506 self.assertEqual('test0', entry.test_str_fdt)
1507 self.assertEqual('test1', entry.test_str_arg)
1508 self.assertEqual(123, entry.test_int_fdt)
1509 self.assertEqual(456, entry.test_int_arg)
1510
1511 def testEntryArgsMissing(self):
1512 """Test missing arguments and properties"""
1513 entry_args = {
1514 'test-int-arg': '456',
1515 }
Simon Glass741f2d62018-10-01 12:22:30 -06001516 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001517 entry = control.images['image'].GetEntries()['_testing']
1518 self.assertEqual('test0', entry.test_str_fdt)
1519 self.assertEqual(None, entry.test_str_arg)
1520 self.assertEqual(None, entry.test_int_fdt)
1521 self.assertEqual(456, entry.test_int_arg)
1522
1523 def testEntryArgsRequired(self):
1524 """Test missing arguments and properties"""
1525 entry_args = {
1526 'test-int-arg': '456',
1527 }
1528 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001529 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass3decfa32020-09-01 05:13:54 -06001530 self.assertIn("Node '/binman/_testing': "
1531 'Missing required properties/entry args: test-str-arg, '
1532 'test-int-fdt, test-int-arg',
Simon Glass53af22a2018-07-17 13:25:32 -06001533 str(e.exception))
1534
1535 def testEntryArgsInvalidFormat(self):
1536 """Test that an invalid entry-argument format is detected"""
Simon Glass53cd5d92019-07-08 14:25:29 -06001537 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1538 '-ano-value']
Simon Glass53af22a2018-07-17 13:25:32 -06001539 with self.assertRaises(ValueError) as e:
1540 self._DoBinman(*args)
1541 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1542
1543 def testEntryArgsInvalidInteger(self):
1544 """Test that an invalid entry-argument integer is detected"""
1545 entry_args = {
1546 'test-int-arg': 'abc',
1547 }
1548 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001549 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001550 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1551 "'test-int-arg' (value 'abc') to integer",
1552 str(e.exception))
1553
1554 def testEntryArgsInvalidDatatype(self):
1555 """Test that an invalid entry-argument datatype is detected
1556
1557 This test could be written in entry_test.py except that it needs
1558 access to control.entry_args, which seems more than that module should
1559 be able to see.
1560 """
1561 entry_args = {
1562 'test-bad-datatype-arg': '12',
1563 }
1564 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001565 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass53af22a2018-07-17 13:25:32 -06001566 entry_args=entry_args)
1567 self.assertIn('GetArg() internal error: Unknown data type ',
1568 str(e.exception))
1569
Simon Glassbb748372018-07-17 13:25:33 -06001570 def testText(self):
1571 """Test for a text entry type"""
1572 entry_args = {
1573 'test-id': TEXT_DATA,
1574 'test-id2': TEXT_DATA2,
1575 'test-id3': TEXT_DATA3,
1576 }
Simon Glass741f2d62018-10-01 12:22:30 -06001577 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glassbb748372018-07-17 13:25:33 -06001578 entry_args=entry_args)
Simon Glassc6c10e72019-05-17 22:00:46 -06001579 expected = (tools.ToBytes(TEXT_DATA) +
1580 tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1581 tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
Simon Glassaa88b502019-07-08 13:18:40 -06001582 b'some text' + b'more text')
Simon Glassbb748372018-07-17 13:25:33 -06001583 self.assertEqual(expected, data)
1584
Simon Glassfd8d1f72018-07-17 13:25:36 -06001585 def testEntryDocs(self):
1586 """Test for creation of entry documentation"""
1587 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass87d43322020-08-05 13:27:46 -06001588 control.WriteEntryDocs(control.GetEntryModules())
Simon Glassfd8d1f72018-07-17 13:25:36 -06001589 self.assertTrue(len(stdout.getvalue()) > 0)
1590
1591 def testEntryDocsMissing(self):
1592 """Test handling of missing entry documentation"""
1593 with self.assertRaises(ValueError) as e:
1594 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass87d43322020-08-05 13:27:46 -06001595 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glassfd8d1f72018-07-17 13:25:36 -06001596 self.assertIn('Documentation is missing for modules: u_boot',
1597 str(e.exception))
1598
Simon Glass11e36cc2018-07-17 13:25:38 -06001599 def testFmap(self):
1600 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001601 data = self._DoReadFile('067_fmap.dts')
Simon Glass11e36cc2018-07-17 13:25:38 -06001602 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc6c10e72019-05-17 22:00:46 -06001603 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1604 U_BOOT_DATA + tools.GetBytes(ord('a'), 12))
Simon Glass11e36cc2018-07-17 13:25:38 -06001605 self.assertEqual(expected, data[:32])
Simon Glassc6c10e72019-05-17 22:00:46 -06001606 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass11e36cc2018-07-17 13:25:38 -06001607 self.assertEqual(1, fhdr.ver_major)
1608 self.assertEqual(0, fhdr.ver_minor)
1609 self.assertEqual(0, fhdr.base)
Simon Glass17365752021-04-03 11:05:10 +13001610 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 5
Simon Glassc7722e82021-04-03 11:05:09 +13001611 self.assertEqual(16 + 16 + expect_size, fhdr.image_size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001612 self.assertEqual(b'FMAP', fhdr.name)
Simon Glass17365752021-04-03 11:05:10 +13001613 self.assertEqual(5, fhdr.nareas)
Simon Glassc7722e82021-04-03 11:05:09 +13001614 fiter = iter(fentries)
Simon Glass11e36cc2018-07-17 13:25:38 -06001615
Simon Glassc7722e82021-04-03 11:05:09 +13001616 fentry = next(fiter)
Simon Glass17365752021-04-03 11:05:10 +13001617 self.assertEqual(b'SECTION0', fentry.name)
1618 self.assertEqual(0, fentry.offset)
1619 self.assertEqual(16, fentry.size)
1620 self.assertEqual(0, fentry.flags)
1621
1622 fentry = next(fiter)
Simon Glassc7722e82021-04-03 11:05:09 +13001623 self.assertEqual(b'RO_U_BOOT', fentry.name)
1624 self.assertEqual(0, fentry.offset)
1625 self.assertEqual(4, fentry.size)
1626 self.assertEqual(0, fentry.flags)
Simon Glass11e36cc2018-07-17 13:25:38 -06001627
Simon Glassc7722e82021-04-03 11:05:09 +13001628 fentry = next(fiter)
Simon Glass17365752021-04-03 11:05:10 +13001629 self.assertEqual(b'SECTION1', fentry.name)
1630 self.assertEqual(16, fentry.offset)
1631 self.assertEqual(16, fentry.size)
1632 self.assertEqual(0, fentry.flags)
1633
1634 fentry = next(fiter)
Simon Glassc7722e82021-04-03 11:05:09 +13001635 self.assertEqual(b'RW_U_BOOT', fentry.name)
1636 self.assertEqual(16, fentry.offset)
1637 self.assertEqual(4, fentry.size)
1638 self.assertEqual(0, fentry.flags)
Simon Glass11e36cc2018-07-17 13:25:38 -06001639
Simon Glassc7722e82021-04-03 11:05:09 +13001640 fentry = next(fiter)
1641 self.assertEqual(b'FMAP', fentry.name)
1642 self.assertEqual(32, fentry.offset)
1643 self.assertEqual(expect_size, fentry.size)
1644 self.assertEqual(0, fentry.flags)
Simon Glass11e36cc2018-07-17 13:25:38 -06001645
Simon Glassec127af2018-07-17 13:25:39 -06001646 def testBlobNamedByArg(self):
1647 """Test we can add a blob with the filename coming from an entry arg"""
1648 entry_args = {
1649 'cros-ec-rw-path': 'ecrw.bin',
1650 }
Simon Glass3decfa32020-09-01 05:13:54 -06001651 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassec127af2018-07-17 13:25:39 -06001652
Simon Glass3af8e492018-07-17 13:25:40 -06001653 def testFill(self):
1654 """Test for an fill entry type"""
Simon Glass741f2d62018-10-01 12:22:30 -06001655 data = self._DoReadFile('069_fill.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001656 expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
Simon Glass3af8e492018-07-17 13:25:40 -06001657 self.assertEqual(expected, data)
1658
1659 def testFillNoSize(self):
1660 """Test for an fill entry type with no size"""
1661 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001662 self._DoReadFile('070_fill_no_size.dts')
Simon Glass3af8e492018-07-17 13:25:40 -06001663 self.assertIn("'fill' entry must have a size property",
1664 str(e.exception))
1665
Simon Glass0ef87aa2018-07-17 13:25:44 -06001666 def _HandleGbbCommand(self, pipe_list):
1667 """Fake calls to the futility utility"""
1668 if pipe_list[0][0] == 'futility':
1669 fname = pipe_list[0][-1]
1670 # Append our GBB data to the file, which will happen every time the
1671 # futility command is called.
Simon Glass1d0ebf72019-05-14 15:53:42 -06001672 with open(fname, 'ab') as fd:
Simon Glass0ef87aa2018-07-17 13:25:44 -06001673 fd.write(GBB_DATA)
1674 return command.CommandResult()
1675
1676 def testGbb(self):
1677 """Test for the Chromium OS Google Binary Block"""
1678 command.test_result = self._HandleGbbCommand
1679 entry_args = {
1680 'keydir': 'devkeys',
1681 'bmpblk': 'bmpblk.bin',
1682 }
Simon Glass741f2d62018-10-01 12:22:30 -06001683 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glass0ef87aa2018-07-17 13:25:44 -06001684
1685 # Since futility
Simon Glasse6d85ff2019-05-14 15:53:47 -06001686 expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1687 tools.GetBytes(0, 0x2180 - 16))
Simon Glass0ef87aa2018-07-17 13:25:44 -06001688 self.assertEqual(expected, data)
1689
1690 def testGbbTooSmall(self):
1691 """Test for the Chromium OS Google Binary Block being large enough"""
1692 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001693 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001694 self.assertIn("Node '/binman/gbb': GBB is too small",
1695 str(e.exception))
1696
1697 def testGbbNoSize(self):
1698 """Test for the Chromium OS Google Binary Block having a size"""
1699 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001700 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001701 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1702 str(e.exception))
1703
Simon Glass24d0d3c2018-07-17 13:25:47 -06001704 def _HandleVblockCommand(self, pipe_list):
Simon Glass5af9ebc2021-01-06 21:35:17 -07001705 """Fake calls to the futility utility
1706
1707 The expected pipe is:
1708
1709 [('futility', 'vbutil_firmware', '--vblock',
1710 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1711 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1712 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1713 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1714
1715 This writes to the output file (here, 'vblock.vblock'). If
1716 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1717 of the input data (here, 'input.vblock').
1718 """
Simon Glass24d0d3c2018-07-17 13:25:47 -06001719 if pipe_list[0][0] == 'futility':
1720 fname = pipe_list[0][3]
Simon Glassa326b492018-09-14 04:57:11 -06001721 with open(fname, 'wb') as fd:
Simon Glass5af9ebc2021-01-06 21:35:17 -07001722 if self._hash_data:
1723 infile = pipe_list[0][11]
1724 m = hashlib.sha256()
1725 data = tools.ReadFile(infile)
1726 m.update(data)
1727 fd.write(m.digest())
1728 else:
1729 fd.write(VBLOCK_DATA)
1730
Simon Glass24d0d3c2018-07-17 13:25:47 -06001731 return command.CommandResult()
1732
1733 def testVblock(self):
1734 """Test for the Chromium OS Verified Boot Block"""
Simon Glass5af9ebc2021-01-06 21:35:17 -07001735 self._hash_data = False
Simon Glass24d0d3c2018-07-17 13:25:47 -06001736 command.test_result = self._HandleVblockCommand
1737 entry_args = {
1738 'keydir': 'devkeys',
1739 }
Simon Glass741f2d62018-10-01 12:22:30 -06001740 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass24d0d3c2018-07-17 13:25:47 -06001741 entry_args=entry_args)
1742 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1743 self.assertEqual(expected, data)
1744
1745 def testVblockNoContent(self):
1746 """Test we detect a vblock which has no content to sign"""
1747 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001748 self._DoReadFile('075_vblock_no_content.dts')
Simon Glass189f2912021-03-21 18:24:31 +13001749 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
Simon Glass24d0d3c2018-07-17 13:25:47 -06001750 'property', str(e.exception))
1751
1752 def testVblockBadPhandle(self):
1753 """Test that we detect a vblock with an invalid phandle in contents"""
1754 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001755 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001756 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1757 '1000', str(e.exception))
1758
1759 def testVblockBadEntry(self):
1760 """Test that we detect an entry that points to a non-entry"""
1761 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001762 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001763 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1764 "'other'", str(e.exception))
1765
Simon Glass5af9ebc2021-01-06 21:35:17 -07001766 def testVblockContent(self):
1767 """Test that the vblock signs the right data"""
1768 self._hash_data = True
1769 command.test_result = self._HandleVblockCommand
1770 entry_args = {
1771 'keydir': 'devkeys',
1772 }
1773 data = self._DoReadFileDtb(
1774 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1775 entry_args=entry_args)[0]
1776 hashlen = 32 # SHA256 hash is 32 bytes
1777 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1778 hashval = data[-hashlen:]
1779 dtb = data[len(U_BOOT_DATA):-hashlen]
1780
1781 expected_data = U_BOOT_DATA + dtb
1782
1783 # The hashval should be a hash of the dtb
1784 m = hashlib.sha256()
1785 m.update(expected_data)
1786 expected_hashval = m.digest()
1787 self.assertEqual(expected_hashval, hashval)
1788
Simon Glassb8ef5b62018-07-17 13:25:48 -06001789 def testTpl(self):
Simon Glass2090f1e2019-08-24 07:23:00 -06001790 """Test that an image with TPL and its device tree can be created"""
Simon Glassb8ef5b62018-07-17 13:25:48 -06001791 # ELF file with a '__bss_size' symbol
Simon Glass2090f1e2019-08-24 07:23:00 -06001792 self._SetupTplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001793 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glassb8ef5b62018-07-17 13:25:48 -06001794 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1795
Simon Glass15a587c2018-07-17 13:25:51 -06001796 def testUsesPos(self):
1797 """Test that the 'pos' property cannot be used anymore"""
1798 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001799 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass15a587c2018-07-17 13:25:51 -06001800 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1801 "'pos'", str(e.exception))
1802
Simon Glassd178eab2018-09-14 04:57:08 -06001803 def testFillZero(self):
1804 """Test for an fill entry type with a size of 0"""
Simon Glass741f2d62018-10-01 12:22:30 -06001805 data = self._DoReadFile('080_fill_empty.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001806 self.assertEqual(tools.GetBytes(0, 16), data)
Simon Glassd178eab2018-09-14 04:57:08 -06001807
Simon Glass0b489362018-09-14 04:57:09 -06001808 def testTextMissing(self):
1809 """Test for a text entry type where there is no text"""
1810 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001811 self._DoReadFileDtb('066_text.dts',)
Simon Glass0b489362018-09-14 04:57:09 -06001812 self.assertIn("Node '/binman/text': No value provided for text label "
1813 "'test-id'", str(e.exception))
1814
Simon Glass35b384c2018-09-14 04:57:10 -06001815 def testPackStart16Tpl(self):
1816 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001817 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glass35b384c2018-09-14 04:57:10 -06001818 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1819
Simon Glass0bfa7b02018-09-14 04:57:12 -06001820 def testSelectImage(self):
1821 """Test that we can select which images to build"""
Simon Glasseb833d82019-04-25 21:58:34 -06001822 expected = 'Skipping images: image1'
Simon Glass0bfa7b02018-09-14 04:57:12 -06001823
Simon Glasseb833d82019-04-25 21:58:34 -06001824 # We should only get the expected message in verbose mode
Simon Glassee0c9a72019-07-08 13:18:48 -06001825 for verbosity in (0, 2):
Simon Glasseb833d82019-04-25 21:58:34 -06001826 with test_util.capture_sys_output() as (stdout, stderr):
1827 retcode = self._DoTestFile('006_dual_image.dts',
1828 verbosity=verbosity,
1829 images=['image2'])
1830 self.assertEqual(0, retcode)
1831 if verbosity:
1832 self.assertIn(expected, stdout.getvalue())
1833 else:
1834 self.assertNotIn(expected, stdout.getvalue())
1835
1836 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1837 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
Simon Glassf86a7362019-07-20 12:24:10 -06001838 self._CleanupOutputDir()
Simon Glass0bfa7b02018-09-14 04:57:12 -06001839
Simon Glass6ed45ba2018-09-14 04:57:24 -06001840 def testUpdateFdtAll(self):
1841 """Test that all device trees are updated with offset/size info"""
Simon Glass3c081312019-07-08 14:25:26 -06001842 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glass6ed45ba2018-09-14 04:57:24 -06001843
1844 base_expected = {
1845 'section:image-pos': 0,
1846 'u-boot-tpl-dtb:size': 513,
1847 'u-boot-spl-dtb:size': 513,
1848 'u-boot-spl-dtb:offset': 493,
1849 'image-pos': 0,
1850 'section/u-boot-dtb:image-pos': 0,
1851 'u-boot-spl-dtb:image-pos': 493,
1852 'section/u-boot-dtb:size': 493,
1853 'u-boot-tpl-dtb:image-pos': 1006,
1854 'section/u-boot-dtb:offset': 0,
1855 'section:size': 493,
1856 'offset': 0,
1857 'section:offset': 0,
1858 'u-boot-tpl-dtb:offset': 1006,
1859 'size': 1519
1860 }
1861
1862 # We expect three device-tree files in the output, one after the other.
1863 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1864 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1865 # main U-Boot tree. All three should have the same postions and offset.
1866 start = 0
1867 for item in ['', 'spl', 'tpl']:
1868 dtb = fdt.Fdt.FromData(data[start:])
1869 dtb.Scan()
Simon Glass12bb1a92019-07-20 12:23:51 -06001870 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
1871 ['spl', 'tpl'])
Simon Glass6ed45ba2018-09-14 04:57:24 -06001872 expected = dict(base_expected)
1873 if item:
1874 expected[item] = 0
1875 self.assertEqual(expected, props)
1876 start += dtb._fdt_obj.totalsize()
1877
1878 def testUpdateFdtOutput(self):
1879 """Test that output DTB files are updated"""
1880 try:
Simon Glass741f2d62018-10-01 12:22:30 -06001881 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glass6ed45ba2018-09-14 04:57:24 -06001882 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1883
1884 # Unfortunately, compiling a source file always results in a file
1885 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass741f2d62018-10-01 12:22:30 -06001886 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glass6ed45ba2018-09-14 04:57:24 -06001887 # binman as a file called u-boot.dtb. To fix this, copy the file
1888 # over to the expected place.
Simon Glass6ed45ba2018-09-14 04:57:24 -06001889 start = 0
1890 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1891 'tpl/u-boot-tpl.dtb.out']:
1892 dtb = fdt.Fdt.FromData(data[start:])
1893 size = dtb._fdt_obj.totalsize()
1894 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1895 outdata = tools.ReadFile(pathname)
1896 name = os.path.split(fname)[0]
1897
1898 if name:
1899 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1900 else:
1901 orig_indata = dtb_data
1902 self.assertNotEqual(outdata, orig_indata,
1903 "Expected output file '%s' be updated" % pathname)
1904 self.assertEqual(outdata, data[start:start + size],
1905 "Expected output file '%s' to match output image" %
1906 pathname)
1907 start += size
1908 finally:
1909 self._ResetDtbs()
1910
Simon Glass83d73c22018-09-14 04:57:26 -06001911 def _decompress(self, data):
Simon Glassff5c7e32019-07-08 13:18:42 -06001912 return tools.Decompress(data, 'lz4')
Simon Glass83d73c22018-09-14 04:57:26 -06001913
1914 def testCompress(self):
1915 """Test compression of blobs"""
Simon Glassac62fba2019-07-08 13:18:53 -06001916 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06001917 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass83d73c22018-09-14 04:57:26 -06001918 use_real_dtb=True, update_dtb=True)
1919 dtb = fdt.Fdt(out_dtb_fname)
1920 dtb.Scan()
1921 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1922 orig = self._decompress(data)
1923 self.assertEquals(COMPRESS_DATA, orig)
Simon Glass97c3e9a2020-10-26 17:40:15 -06001924
1925 # Do a sanity check on various fields
1926 image = control.images['image']
1927 entries = image.GetEntries()
1928 self.assertEqual(1, len(entries))
1929
1930 entry = entries['blob']
1931 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
1932 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
1933 orig = self._decompress(entry.data)
1934 self.assertEqual(orig, entry.uncomp_data)
1935
Simon Glass63e7ba62020-10-26 17:40:16 -06001936 self.assertEqual(image.data, entry.data)
1937
Simon Glass83d73c22018-09-14 04:57:26 -06001938 expected = {
1939 'blob:uncomp-size': len(COMPRESS_DATA),
1940 'blob:size': len(data),
1941 'size': len(data),
1942 }
1943 self.assertEqual(expected, props)
1944
Simon Glass0a98b282018-09-14 04:57:28 -06001945 def testFiles(self):
1946 """Test bringing in multiple files"""
Simon Glass741f2d62018-10-01 12:22:30 -06001947 data = self._DoReadFile('084_files.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001948 self.assertEqual(FILES_DATA, data)
1949
1950 def testFilesCompress(self):
1951 """Test bringing in multiple files and compressing them"""
Simon Glassac62fba2019-07-08 13:18:53 -06001952 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06001953 data = self._DoReadFile('085_files_compress.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001954
1955 image = control.images['image']
1956 entries = image.GetEntries()
1957 files = entries['files']
Simon Glass8beb11e2019-07-08 14:25:47 -06001958 entries = files._entries
Simon Glass0a98b282018-09-14 04:57:28 -06001959
Simon Glassc6c10e72019-05-17 22:00:46 -06001960 orig = b''
Simon Glass0a98b282018-09-14 04:57:28 -06001961 for i in range(1, 3):
1962 key = '%d.dat' % i
1963 start = entries[key].image_pos
1964 len = entries[key].size
1965 chunk = data[start:start + len]
1966 orig += self._decompress(chunk)
1967
1968 self.assertEqual(FILES_DATA, orig)
1969
1970 def testFilesMissing(self):
1971 """Test missing files"""
1972 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001973 data = self._DoReadFile('086_files_none.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001974 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1975 'no files', str(e.exception))
1976
1977 def testFilesNoPattern(self):
1978 """Test missing files"""
1979 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001980 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001981 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1982 str(e.exception))
1983
Simon Glassba64a0b2018-09-14 04:57:29 -06001984 def testExpandSize(self):
1985 """Test an expanding entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001986 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
Simon Glassba64a0b2018-09-14 04:57:29 -06001987 map=True)
Simon Glassc6c10e72019-05-17 22:00:46 -06001988 expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA +
1989 MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA +
1990 tools.GetBytes(ord('c'), 8) + U_BOOT_DATA +
1991 tools.GetBytes(ord('d'), 8))
Simon Glassba64a0b2018-09-14 04:57:29 -06001992 self.assertEqual(expect, data)
1993 self.assertEqual('''ImagePos Offset Size Name
199400000000 00000000 00000028 main-section
199500000000 00000000 00000008 fill
199600000008 00000008 00000004 u-boot
19970000000c 0000000c 00000004 section
19980000000c 00000000 00000003 intel-mrc
199900000010 00000010 00000004 u-boot2
200000000014 00000014 0000000c section2
200100000014 00000000 00000008 fill
20020000001c 00000008 00000004 u-boot
200300000020 00000020 00000008 fill2
2004''', map_data)
2005
2006 def testExpandSizeBad(self):
2007 """Test an expanding entry which fails to provide contents"""
Simon Glass163ed6c2018-09-14 04:57:36 -06002008 with test_util.capture_sys_output() as (stdout, stderr):
2009 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002010 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
Simon Glassba64a0b2018-09-14 04:57:29 -06002011 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
2012 'expanding entry', str(e.exception))
2013
Simon Glasse0e5df92018-09-14 04:57:31 -06002014 def testHash(self):
2015 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06002016 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06002017 use_real_dtb=True, update_dtb=True)
2018 dtb = fdt.Fdt(out_dtb_fname)
2019 dtb.Scan()
2020 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
2021 m = hashlib.sha256()
2022 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06002023 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06002024
2025 def testHashNoAlgo(self):
2026 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002027 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06002028 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2029 'hash node', str(e.exception))
2030
2031 def testHashBadAlgo(self):
2032 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002033 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06002034 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
2035 str(e.exception))
2036
2037 def testHashSection(self):
2038 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06002039 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06002040 use_real_dtb=True, update_dtb=True)
2041 dtb = fdt.Fdt(out_dtb_fname)
2042 dtb.Scan()
2043 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2044 m = hashlib.sha256()
2045 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06002046 m.update(tools.GetBytes(ord('a'), 16))
2047 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06002048
Simon Glassf0253632018-09-14 04:57:32 -06002049 def testPackUBootTplMicrocode(self):
2050 """Test that x86 microcode can be handled correctly in TPL
2051
2052 We expect to see the following in the image, in order:
2053 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2054 place
2055 u-boot-tpl.dtb with the microcode removed
2056 the microcode
2057 """
Simon Glass2090f1e2019-08-24 07:23:00 -06002058 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass741f2d62018-10-01 12:22:30 -06002059 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glassf0253632018-09-14 04:57:32 -06002060 U_BOOT_TPL_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06002061 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2062 b'ter somewhere in here', first)
Simon Glassf0253632018-09-14 04:57:32 -06002063
Simon Glassf8f8df62018-09-14 04:57:34 -06002064 def testFmapX86(self):
2065 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06002066 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassf8f8df62018-09-14 04:57:34 -06002067 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc6c10e72019-05-17 22:00:46 -06002068 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06002069 self.assertEqual(expected, data[:32])
2070 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2071
2072 self.assertEqual(0x100, fhdr.image_size)
2073
2074 self.assertEqual(0, fentries[0].offset)
2075 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06002076 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06002077
2078 self.assertEqual(4, fentries[1].offset)
2079 self.assertEqual(3, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06002080 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06002081
2082 self.assertEqual(32, fentries[2].offset)
2083 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2084 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06002085 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06002086
2087 def testFmapX86Section(self):
2088 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06002089 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glassc6c10e72019-05-17 22:00:46 -06002090 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06002091 self.assertEqual(expected, data[:32])
2092 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2093
Simon Glass17365752021-04-03 11:05:10 +13002094 self.assertEqual(0x180, fhdr.image_size)
2095 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
Simon Glassc7722e82021-04-03 11:05:09 +13002096 fiter = iter(fentries)
Simon Glassf8f8df62018-09-14 04:57:34 -06002097
Simon Glassc7722e82021-04-03 11:05:09 +13002098 fentry = next(fiter)
2099 self.assertEqual(b'U_BOOT', fentry.name)
2100 self.assertEqual(0, fentry.offset)
2101 self.assertEqual(4, fentry.size)
Simon Glassf8f8df62018-09-14 04:57:34 -06002102
Simon Glassc7722e82021-04-03 11:05:09 +13002103 fentry = next(fiter)
Simon Glass17365752021-04-03 11:05:10 +13002104 self.assertEqual(b'SECTION', fentry.name)
2105 self.assertEqual(4, fentry.offset)
2106 self.assertEqual(0x20 + expect_size, fentry.size)
2107
2108 fentry = next(fiter)
Simon Glassc7722e82021-04-03 11:05:09 +13002109 self.assertEqual(b'INTEL_MRC', fentry.name)
2110 self.assertEqual(4, fentry.offset)
2111 self.assertEqual(3, fentry.size)
Simon Glassf8f8df62018-09-14 04:57:34 -06002112
Simon Glassc7722e82021-04-03 11:05:09 +13002113 fentry = next(fiter)
2114 self.assertEqual(b'FMAP', fentry.name)
2115 self.assertEqual(36, fentry.offset)
2116 self.assertEqual(expect_size, fentry.size)
Simon Glassf8f8df62018-09-14 04:57:34 -06002117
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002118 def testElf(self):
2119 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06002120 self._SetupSplElf()
Simon Glass2090f1e2019-08-24 07:23:00 -06002121 self._SetupTplElf()
Simon Glass53e22bf2019-08-24 07:22:53 -06002122 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002123 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06002124 data = self._DoReadFile('096_elf.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002125
Simon Glass093d1682019-07-08 13:18:25 -06002126 def testElfStrip(self):
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002127 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06002128 self._SetupSplElf()
Simon Glass53e22bf2019-08-24 07:22:53 -06002129 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002130 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06002131 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002132
Simon Glass163ed6c2018-09-14 04:57:36 -06002133 def testPackOverlapMap(self):
2134 """Test that overlapping regions are detected"""
2135 with test_util.capture_sys_output() as (stdout, stderr):
2136 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002137 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glass163ed6c2018-09-14 04:57:36 -06002138 map_fname = tools.GetOutputFilename('image.map')
2139 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2140 stdout.getvalue())
2141
2142 # We should not get an inmage, but there should be a map file
2143 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
2144 self.assertTrue(os.path.exists(map_fname))
Simon Glasseb546ac2019-05-17 22:00:51 -06002145 map_data = tools.ReadFile(map_fname, binary=False)
Simon Glass163ed6c2018-09-14 04:57:36 -06002146 self.assertEqual('''ImagePos Offset Size Name
Simon Glass0ff83da2020-10-26 17:40:24 -06002147<none> 00000000 00000008 main-section
Simon Glass163ed6c2018-09-14 04:57:36 -06002148<none> 00000000 00000004 u-boot
2149<none> 00000003 00000004 u-boot-align
2150''', map_data)
2151
Simon Glass093d1682019-07-08 13:18:25 -06002152 def testPackRefCode(self):
Simon Glass3ae192c2018-10-01 12:22:31 -06002153 """Test that an image with an Intel Reference code binary works"""
2154 data = self._DoReadFile('100_intel_refcode.dts')
2155 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2156
Simon Glass9481c802019-04-25 21:58:39 -06002157 def testSectionOffset(self):
2158 """Tests use of a section with an offset"""
2159 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2160 map=True)
2161 self.assertEqual('''ImagePos Offset Size Name
216200000000 00000000 00000038 main-section
216300000004 00000004 00000010 section@0
216400000004 00000000 00000004 u-boot
216500000018 00000018 00000010 section@1
216600000018 00000000 00000004 u-boot
21670000002c 0000002c 00000004 section@2
21680000002c 00000000 00000004 u-boot
2169''', map_data)
2170 self.assertEqual(data,
Simon Glasse6d85ff2019-05-14 15:53:47 -06002171 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2172 tools.GetBytes(0x21, 12) +
2173 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2174 tools.GetBytes(0x61, 12) +
2175 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2176 tools.GetBytes(0x26, 8))
Simon Glass9481c802019-04-25 21:58:39 -06002177
Simon Glassac62fba2019-07-08 13:18:53 -06002178 def testCbfsRaw(self):
2179 """Test base handling of a Coreboot Filesystem (CBFS)
2180
2181 The exact contents of the CBFS is verified by similar tests in
2182 cbfs_util_test.py. The tests here merely check that the files added to
2183 the CBFS can be found in the final image.
2184 """
2185 data = self._DoReadFile('102_cbfs_raw.dts')
2186 size = 0xb0
2187
2188 cbfs = cbfs_util.CbfsReader(data)
2189 self.assertEqual(size, cbfs.rom_size)
2190
2191 self.assertIn('u-boot-dtb', cbfs.files)
2192 cfile = cbfs.files['u-boot-dtb']
2193 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2194
2195 def testCbfsArch(self):
2196 """Test on non-x86 architecture"""
2197 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2198 size = 0x100
2199
2200 cbfs = cbfs_util.CbfsReader(data)
2201 self.assertEqual(size, cbfs.rom_size)
2202
2203 self.assertIn('u-boot-dtb', cbfs.files)
2204 cfile = cbfs.files['u-boot-dtb']
2205 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2206
2207 def testCbfsStage(self):
2208 """Tests handling of a Coreboot Filesystem (CBFS)"""
2209 if not elf.ELF_TOOLS:
2210 self.skipTest('Python elftools not available')
2211 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2212 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2213 size = 0xb0
2214
2215 data = self._DoReadFile('104_cbfs_stage.dts')
2216 cbfs = cbfs_util.CbfsReader(data)
2217 self.assertEqual(size, cbfs.rom_size)
2218
2219 self.assertIn('u-boot', cbfs.files)
2220 cfile = cbfs.files['u-boot']
2221 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2222
2223 def testCbfsRawCompress(self):
2224 """Test handling of compressing raw files"""
2225 self._CheckLz4()
2226 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2227 size = 0x140
2228
2229 cbfs = cbfs_util.CbfsReader(data)
2230 self.assertIn('u-boot', cbfs.files)
2231 cfile = cbfs.files['u-boot']
2232 self.assertEqual(COMPRESS_DATA, cfile.data)
2233
2234 def testCbfsBadArch(self):
2235 """Test handling of a bad architecture"""
2236 with self.assertRaises(ValueError) as e:
2237 self._DoReadFile('106_cbfs_bad_arch.dts')
2238 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2239
2240 def testCbfsNoSize(self):
2241 """Test handling of a missing size property"""
2242 with self.assertRaises(ValueError) as e:
2243 self._DoReadFile('107_cbfs_no_size.dts')
2244 self.assertIn('entry must have a size property', str(e.exception))
2245
2246 def testCbfsNoCOntents(self):
2247 """Test handling of a CBFS entry which does not provide contentsy"""
2248 with self.assertRaises(ValueError) as e:
2249 self._DoReadFile('108_cbfs_no_contents.dts')
2250 self.assertIn('Could not complete processing of contents',
2251 str(e.exception))
2252
2253 def testCbfsBadCompress(self):
2254 """Test handling of a bad architecture"""
2255 with self.assertRaises(ValueError) as e:
2256 self._DoReadFile('109_cbfs_bad_compress.dts')
2257 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2258 str(e.exception))
2259
2260 def testCbfsNamedEntries(self):
2261 """Test handling of named entries"""
2262 data = self._DoReadFile('110_cbfs_name.dts')
2263
2264 cbfs = cbfs_util.CbfsReader(data)
2265 self.assertIn('FRED', cbfs.files)
2266 cfile1 = cbfs.files['FRED']
2267 self.assertEqual(U_BOOT_DATA, cfile1.data)
2268
2269 self.assertIn('hello', cbfs.files)
2270 cfile2 = cbfs.files['hello']
2271 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2272
Simon Glassc5ac1382019-07-08 13:18:54 -06002273 def _SetupIfwi(self, fname):
2274 """Set up to run an IFWI test
2275
2276 Args:
2277 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2278 """
2279 self._SetupSplElf()
Simon Glass2090f1e2019-08-24 07:23:00 -06002280 self._SetupTplElf()
Simon Glassc5ac1382019-07-08 13:18:54 -06002281
2282 # Intel Integrated Firmware Image (IFWI) file
2283 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2284 data = fd.read()
2285 TestFunctional._MakeInputFile(fname,data)
2286
2287 def _CheckIfwi(self, data):
2288 """Check that an image with an IFWI contains the correct output
2289
2290 Args:
2291 data: Conents of output file
2292 """
2293 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
2294 if data[:0x1000] != expected_desc:
2295 self.fail('Expected descriptor binary at start of image')
2296
2297 # We expect to find the TPL wil in subpart IBBP entry IBBL
2298 image_fname = tools.GetOutputFilename('image.bin')
2299 tpl_fname = tools.GetOutputFilename('tpl.out')
2300 tools.RunIfwiTool(image_fname, tools.CMD_EXTRACT, fname=tpl_fname,
2301 subpart='IBBP', entry_name='IBBL')
2302
2303 tpl_data = tools.ReadFile(tpl_fname)
Simon Glasse95be632019-08-24 07:22:51 -06002304 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glassc5ac1382019-07-08 13:18:54 -06002305
2306 def testPackX86RomIfwi(self):
2307 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2308 self._SetupIfwi('fitimage.bin')
Simon Glass9255f3c2019-08-24 07:23:01 -06002309 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002310 self._CheckIfwi(data)
2311
2312 def testPackX86RomIfwiNoDesc(self):
2313 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2314 self._SetupIfwi('ifwi.bin')
Simon Glass9255f3c2019-08-24 07:23:01 -06002315 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002316 self._CheckIfwi(data)
2317
2318 def testPackX86RomIfwiNoData(self):
2319 """Test that an x86 ROM with IFWI handles missing data"""
2320 self._SetupIfwi('ifwi.bin')
2321 with self.assertRaises(ValueError) as e:
Simon Glass9255f3c2019-08-24 07:23:01 -06002322 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002323 self.assertIn('Could not complete processing of contents',
2324 str(e.exception))
Simon Glass53af22a2018-07-17 13:25:32 -06002325
Simon Glasse073d4e2019-07-08 13:18:56 -06002326 def testCbfsOffset(self):
2327 """Test a CBFS with files at particular offsets
2328
2329 Like all CFBS tests, this is just checking the logic that calls
2330 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2331 """
2332 data = self._DoReadFile('114_cbfs_offset.dts')
2333 size = 0x200
2334
2335 cbfs = cbfs_util.CbfsReader(data)
2336 self.assertEqual(size, cbfs.rom_size)
2337
2338 self.assertIn('u-boot', cbfs.files)
2339 cfile = cbfs.files['u-boot']
2340 self.assertEqual(U_BOOT_DATA, cfile.data)
2341 self.assertEqual(0x40, cfile.cbfs_offset)
2342
2343 self.assertIn('u-boot-dtb', cbfs.files)
2344 cfile2 = cbfs.files['u-boot-dtb']
2345 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2346 self.assertEqual(0x140, cfile2.cbfs_offset)
2347
Simon Glass086cec92019-07-08 14:25:27 -06002348 def testFdtmap(self):
2349 """Test an FDT map can be inserted in the image"""
2350 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2351 fdtmap_data = data[len(U_BOOT_DATA):]
2352 magic = fdtmap_data[:8]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002353 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass086cec92019-07-08 14:25:27 -06002354 self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
2355
2356 fdt_data = fdtmap_data[16:]
2357 dtb = fdt.Fdt.FromData(fdt_data)
2358 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002359 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass086cec92019-07-08 14:25:27 -06002360 self.assertEqual({
2361 'image-pos': 0,
2362 'offset': 0,
2363 'u-boot:offset': 0,
2364 'u-boot:size': len(U_BOOT_DATA),
2365 'u-boot:image-pos': 0,
2366 'fdtmap:image-pos': 4,
2367 'fdtmap:offset': 4,
2368 'fdtmap:size': len(fdtmap_data),
2369 'size': len(data),
2370 }, props)
2371
2372 def testFdtmapNoMatch(self):
2373 """Check handling of an FDT map when the section cannot be found"""
2374 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2375
2376 # Mangle the section name, which should cause a mismatch between the
2377 # correct FDT path and the one expected by the section
2378 image = control.images['image']
Simon Glasscf228942019-07-08 14:25:28 -06002379 image._node.path += '-suffix'
Simon Glass086cec92019-07-08 14:25:27 -06002380 entries = image.GetEntries()
2381 fdtmap = entries['fdtmap']
2382 with self.assertRaises(ValueError) as e:
2383 fdtmap._GetFdtmap()
2384 self.assertIn("Cannot locate node for path '/binman-suffix'",
2385 str(e.exception))
2386
Simon Glasscf228942019-07-08 14:25:28 -06002387 def testFdtmapHeader(self):
2388 """Test an FDT map and image header can be inserted in the image"""
2389 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2390 fdtmap_pos = len(U_BOOT_DATA)
2391 fdtmap_data = data[fdtmap_pos:]
2392 fdt_data = fdtmap_data[16:]
2393 dtb = fdt.Fdt.FromData(fdt_data)
2394 fdt_size = dtb.GetFdtObj().totalsize()
2395 hdr_data = data[-8:]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002396 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002397 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2398 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2399
2400 def testFdtmapHeaderStart(self):
2401 """Test an image header can be inserted at the image start"""
2402 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2403 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2404 hdr_data = data[:8]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002405 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002406 offset = struct.unpack('<I', hdr_data[4:])[0]
2407 self.assertEqual(fdtmap_pos, offset)
2408
2409 def testFdtmapHeaderPos(self):
2410 """Test an image header can be inserted at a chosen position"""
2411 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2412 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2413 hdr_data = data[0x80:0x88]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002414 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002415 offset = struct.unpack('<I', hdr_data[4:])[0]
2416 self.assertEqual(fdtmap_pos, offset)
2417
2418 def testHeaderMissingFdtmap(self):
2419 """Test an image header requires an fdtmap"""
2420 with self.assertRaises(ValueError) as e:
2421 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2422 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2423 str(e.exception))
2424
2425 def testHeaderNoLocation(self):
2426 """Test an image header with a no specified location is detected"""
2427 with self.assertRaises(ValueError) as e:
2428 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2429 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2430 str(e.exception))
2431
Simon Glassc52c9e72019-07-08 14:25:37 -06002432 def testEntryExpand(self):
2433 """Test expanding an entry after it is packed"""
2434 data = self._DoReadFile('121_entry_expand.dts')
Simon Glass79d3c582019-07-20 12:23:57 -06002435 self.assertEqual(b'aaa', data[:3])
2436 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2437 self.assertEqual(b'aaa', data[-3:])
Simon Glassc52c9e72019-07-08 14:25:37 -06002438
2439 def testEntryExpandBad(self):
2440 """Test expanding an entry after it is packed, twice"""
2441 with self.assertRaises(ValueError) as e:
2442 self._DoReadFile('122_entry_expand_twice.dts')
Simon Glass61ec04f2019-07-20 12:23:58 -06002443 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glassc52c9e72019-07-08 14:25:37 -06002444 str(e.exception))
2445
2446 def testEntryExpandSection(self):
2447 """Test expanding an entry within a section after it is packed"""
2448 data = self._DoReadFile('123_entry_expand_section.dts')
Simon Glass79d3c582019-07-20 12:23:57 -06002449 self.assertEqual(b'aaa', data[:3])
2450 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2451 self.assertEqual(b'aaa', data[-3:])
Simon Glassc52c9e72019-07-08 14:25:37 -06002452
Simon Glass6c223fd2019-07-08 14:25:38 -06002453 def testCompressDtb(self):
2454 """Test that compress of device-tree files is supported"""
2455 self._CheckLz4()
2456 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2457 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2458 comp_data = data[len(U_BOOT_DATA):]
2459 orig = self._decompress(comp_data)
2460 dtb = fdt.Fdt.FromData(orig)
2461 dtb.Scan()
2462 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2463 expected = {
2464 'u-boot:size': len(U_BOOT_DATA),
2465 'u-boot-dtb:uncomp-size': len(orig),
2466 'u-boot-dtb:size': len(comp_data),
2467 'size': len(data),
2468 }
2469 self.assertEqual(expected, props)
2470
Simon Glass69f7cb32019-07-08 14:25:41 -06002471 def testCbfsUpdateFdt(self):
2472 """Test that we can update the device tree with CBFS offset/size info"""
2473 self._CheckLz4()
2474 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2475 update_dtb=True)
2476 dtb = fdt.Fdt(out_dtb_fname)
2477 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002478 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass69f7cb32019-07-08 14:25:41 -06002479 del props['cbfs/u-boot:size']
2480 self.assertEqual({
2481 'offset': 0,
2482 'size': len(data),
2483 'image-pos': 0,
2484 'cbfs:offset': 0,
2485 'cbfs:size': len(data),
2486 'cbfs:image-pos': 0,
2487 'cbfs/u-boot:offset': 0x38,
2488 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2489 'cbfs/u-boot:image-pos': 0x38,
2490 'cbfs/u-boot-dtb:offset': 0xb8,
2491 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2492 'cbfs/u-boot-dtb:image-pos': 0xb8,
2493 }, props)
2494
Simon Glass8a1ad062019-07-08 14:25:42 -06002495 def testCbfsBadType(self):
2496 """Test an image header with a no specified location is detected"""
2497 with self.assertRaises(ValueError) as e:
2498 self._DoReadFile('126_cbfs_bad_type.dts')
2499 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2500
Simon Glass41b8ba02019-07-08 14:25:43 -06002501 def testList(self):
2502 """Test listing the files in an image"""
2503 self._CheckLz4()
2504 data = self._DoReadFile('127_list.dts')
2505 image = control.images['image']
2506 entries = image.BuildEntryList()
2507 self.assertEqual(7, len(entries))
2508
2509 ent = entries[0]
2510 self.assertEqual(0, ent.indent)
2511 self.assertEqual('main-section', ent.name)
2512 self.assertEqual('section', ent.etype)
2513 self.assertEqual(len(data), ent.size)
2514 self.assertEqual(0, ent.image_pos)
2515 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002516 self.assertEqual(0, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002517
2518 ent = entries[1]
2519 self.assertEqual(1, ent.indent)
2520 self.assertEqual('u-boot', ent.name)
2521 self.assertEqual('u-boot', ent.etype)
2522 self.assertEqual(len(U_BOOT_DATA), ent.size)
2523 self.assertEqual(0, ent.image_pos)
2524 self.assertEqual(None, ent.uncomp_size)
2525 self.assertEqual(0, ent.offset)
2526
2527 ent = entries[2]
2528 self.assertEqual(1, ent.indent)
2529 self.assertEqual('section', ent.name)
2530 self.assertEqual('section', ent.etype)
2531 section_size = ent.size
2532 self.assertEqual(0x100, ent.image_pos)
2533 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002534 self.assertEqual(0x100, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002535
2536 ent = entries[3]
2537 self.assertEqual(2, ent.indent)
2538 self.assertEqual('cbfs', ent.name)
2539 self.assertEqual('cbfs', ent.etype)
2540 self.assertEqual(0x400, ent.size)
2541 self.assertEqual(0x100, ent.image_pos)
2542 self.assertEqual(None, ent.uncomp_size)
2543 self.assertEqual(0, ent.offset)
2544
2545 ent = entries[4]
2546 self.assertEqual(3, ent.indent)
2547 self.assertEqual('u-boot', ent.name)
2548 self.assertEqual('u-boot', ent.etype)
2549 self.assertEqual(len(U_BOOT_DATA), ent.size)
2550 self.assertEqual(0x138, ent.image_pos)
2551 self.assertEqual(None, ent.uncomp_size)
2552 self.assertEqual(0x38, ent.offset)
2553
2554 ent = entries[5]
2555 self.assertEqual(3, ent.indent)
2556 self.assertEqual('u-boot-dtb', ent.name)
2557 self.assertEqual('text', ent.etype)
2558 self.assertGreater(len(COMPRESS_DATA), ent.size)
2559 self.assertEqual(0x178, ent.image_pos)
2560 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2561 self.assertEqual(0x78, ent.offset)
2562
2563 ent = entries[6]
2564 self.assertEqual(2, ent.indent)
2565 self.assertEqual('u-boot-dtb', ent.name)
2566 self.assertEqual('u-boot-dtb', ent.etype)
2567 self.assertEqual(0x500, ent.image_pos)
2568 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2569 dtb_size = ent.size
2570 # Compressing this data expands it since headers are added
2571 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2572 self.assertEqual(0x400, ent.offset)
2573
2574 self.assertEqual(len(data), 0x100 + section_size)
2575 self.assertEqual(section_size, 0x400 + dtb_size)
2576
Simon Glasse1925fa2019-07-08 14:25:44 -06002577 def testFindFdtmap(self):
2578 """Test locating an FDT map in an image"""
2579 self._CheckLz4()
2580 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2581 image = control.images['image']
2582 entries = image.GetEntries()
2583 entry = entries['fdtmap']
2584 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2585
2586 def testFindFdtmapMissing(self):
2587 """Test failing to locate an FDP map"""
2588 data = self._DoReadFile('005_simple.dts')
2589 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2590
Simon Glass2d260032019-07-08 14:25:45 -06002591 def testFindImageHeader(self):
2592 """Test locating a image header"""
2593 self._CheckLz4()
Simon Glassffded752019-07-08 14:25:46 -06002594 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002595 image = control.images['image']
2596 entries = image.GetEntries()
2597 entry = entries['fdtmap']
2598 # The header should point to the FDT map
2599 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2600
2601 def testFindImageHeaderStart(self):
2602 """Test locating a image header located at the start of an image"""
Simon Glassffded752019-07-08 14:25:46 -06002603 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002604 image = control.images['image']
2605 entries = image.GetEntries()
2606 entry = entries['fdtmap']
2607 # The header should point to the FDT map
2608 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2609
2610 def testFindImageHeaderMissing(self):
2611 """Test failing to locate an image header"""
2612 data = self._DoReadFile('005_simple.dts')
2613 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2614
Simon Glassffded752019-07-08 14:25:46 -06002615 def testReadImage(self):
2616 """Test reading an image and accessing its FDT map"""
2617 self._CheckLz4()
2618 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2619 image_fname = tools.GetOutputFilename('image.bin')
2620 orig_image = control.images['image']
2621 image = Image.FromFile(image_fname)
2622 self.assertEqual(orig_image.GetEntries().keys(),
2623 image.GetEntries().keys())
2624
2625 orig_entry = orig_image.GetEntries()['fdtmap']
2626 entry = image.GetEntries()['fdtmap']
2627 self.assertEquals(orig_entry.offset, entry.offset)
2628 self.assertEquals(orig_entry.size, entry.size)
2629 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2630
2631 def testReadImageNoHeader(self):
2632 """Test accessing an image's FDT map without an image header"""
2633 self._CheckLz4()
2634 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
2635 image_fname = tools.GetOutputFilename('image.bin')
2636 image = Image.FromFile(image_fname)
2637 self.assertTrue(isinstance(image, Image))
Simon Glass10f9d002019-07-20 12:23:50 -06002638 self.assertEqual('image', image.image_name[-5:])
Simon Glassffded752019-07-08 14:25:46 -06002639
2640 def testReadImageFail(self):
2641 """Test failing to read an image image's FDT map"""
2642 self._DoReadFile('005_simple.dts')
2643 image_fname = tools.GetOutputFilename('image.bin')
2644 with self.assertRaises(ValueError) as e:
2645 image = Image.FromFile(image_fname)
2646 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glasse073d4e2019-07-08 13:18:56 -06002647
Simon Glass61f564d2019-07-08 14:25:48 -06002648 def testListCmd(self):
2649 """Test listing the files in an image using an Fdtmap"""
2650 self._CheckLz4()
2651 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2652
2653 # lz4 compression size differs depending on the version
2654 image = control.images['image']
2655 entries = image.GetEntries()
2656 section_size = entries['section'].size
2657 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2658 fdtmap_offset = entries['fdtmap'].offset
2659
Simon Glassf86a7362019-07-20 12:24:10 -06002660 try:
2661 tmpdir, updated_fname = self._SetupImageInTmpdir()
2662 with test_util.capture_sys_output() as (stdout, stderr):
2663 self._DoBinman('ls', '-i', updated_fname)
2664 finally:
2665 shutil.rmtree(tmpdir)
Simon Glass61f564d2019-07-08 14:25:48 -06002666 lines = stdout.getvalue().splitlines()
2667 expected = [
2668'Name Image-pos Size Entry-type Offset Uncomp-size',
2669'----------------------------------------------------------------------',
2670'main-section 0 c00 section 0',
2671' u-boot 0 4 u-boot 0',
2672' section 100 %x section 100' % section_size,
2673' cbfs 100 400 cbfs 0',
2674' u-boot 138 4 u-boot 38',
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002675' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glass61f564d2019-07-08 14:25:48 -06002676' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002677' fdtmap %x 3bd fdtmap %x' %
Simon Glass61f564d2019-07-08 14:25:48 -06002678 (fdtmap_offset, fdtmap_offset),
2679' image-header bf8 8 image-header bf8',
2680 ]
2681 self.assertEqual(expected, lines)
2682
2683 def testListCmdFail(self):
2684 """Test failing to list an image"""
2685 self._DoReadFile('005_simple.dts')
Simon Glassf86a7362019-07-20 12:24:10 -06002686 try:
2687 tmpdir, updated_fname = self._SetupImageInTmpdir()
2688 with self.assertRaises(ValueError) as e:
2689 self._DoBinman('ls', '-i', updated_fname)
2690 finally:
2691 shutil.rmtree(tmpdir)
Simon Glass61f564d2019-07-08 14:25:48 -06002692 self.assertIn("Cannot find FDT map in image", str(e.exception))
2693
2694 def _RunListCmd(self, paths, expected):
2695 """List out entries and check the result
2696
2697 Args:
2698 paths: List of paths to pass to the list command
2699 expected: Expected list of filenames to be returned, in order
2700 """
2701 self._CheckLz4()
2702 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2703 image_fname = tools.GetOutputFilename('image.bin')
2704 image = Image.FromFile(image_fname)
2705 lines = image.GetListEntries(paths)[1]
2706 files = [line[0].strip() for line in lines[1:]]
2707 self.assertEqual(expected, files)
2708
2709 def testListCmdSection(self):
2710 """Test listing the files in a section"""
2711 self._RunListCmd(['section'],
2712 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2713
2714 def testListCmdFile(self):
2715 """Test listing a particular file"""
2716 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2717
2718 def testListCmdWildcard(self):
2719 """Test listing a wildcarded file"""
2720 self._RunListCmd(['*boot*'],
2721 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2722
2723 def testListCmdWildcardMulti(self):
2724 """Test listing a wildcarded file"""
2725 self._RunListCmd(['*cb*', '*head*'],
2726 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2727
2728 def testListCmdEmpty(self):
2729 """Test listing a wildcarded file"""
2730 self._RunListCmd(['nothing'], [])
2731
2732 def testListCmdPath(self):
2733 """Test listing the files in a sub-entry of a section"""
2734 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2735
Simon Glassf667e452019-07-08 14:25:50 -06002736 def _RunExtractCmd(self, entry_name, decomp=True):
2737 """Extract an entry from an image
2738
2739 Args:
2740 entry_name: Entry name to extract
2741 decomp: True to decompress the data if compressed, False to leave
2742 it in its raw uncompressed format
2743
2744 Returns:
2745 data from entry
2746 """
2747 self._CheckLz4()
2748 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2749 image_fname = tools.GetOutputFilename('image.bin')
2750 return control.ReadEntry(image_fname, entry_name, decomp)
2751
2752 def testExtractSimple(self):
2753 """Test extracting a single file"""
2754 data = self._RunExtractCmd('u-boot')
2755 self.assertEqual(U_BOOT_DATA, data)
2756
Simon Glass71ce0ba2019-07-08 14:25:52 -06002757 def testExtractSection(self):
2758 """Test extracting the files in a section"""
2759 data = self._RunExtractCmd('section')
2760 cbfs_data = data[:0x400]
2761 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002762 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass71ce0ba2019-07-08 14:25:52 -06002763 dtb_data = data[0x400:]
2764 dtb = self._decompress(dtb_data)
2765 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2766
2767 def testExtractCompressed(self):
2768 """Test extracting compressed data"""
2769 data = self._RunExtractCmd('section/u-boot-dtb')
2770 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2771
2772 def testExtractRaw(self):
2773 """Test extracting compressed data without decompressing it"""
2774 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2775 dtb = self._decompress(data)
2776 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2777
2778 def testExtractCbfs(self):
2779 """Test extracting CBFS data"""
2780 data = self._RunExtractCmd('section/cbfs/u-boot')
2781 self.assertEqual(U_BOOT_DATA, data)
2782
2783 def testExtractCbfsCompressed(self):
2784 """Test extracting CBFS compressed data"""
2785 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2786 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2787
2788 def testExtractCbfsRaw(self):
2789 """Test extracting CBFS compressed data without decompressing it"""
2790 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Simon Glasseb0f4a42019-07-20 12:24:06 -06002791 dtb = tools.Decompress(data, 'lzma', with_header=False)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002792 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2793
Simon Glassf667e452019-07-08 14:25:50 -06002794 def testExtractBadEntry(self):
2795 """Test extracting a bad section path"""
2796 with self.assertRaises(ValueError) as e:
2797 self._RunExtractCmd('section/does-not-exist')
2798 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2799 str(e.exception))
2800
2801 def testExtractMissingFile(self):
2802 """Test extracting file that does not exist"""
2803 with self.assertRaises(IOError) as e:
2804 control.ReadEntry('missing-file', 'name')
2805
2806 def testExtractBadFile(self):
2807 """Test extracting an invalid file"""
2808 fname = os.path.join(self._indir, 'badfile')
2809 tools.WriteFile(fname, b'')
2810 with self.assertRaises(ValueError) as e:
2811 control.ReadEntry(fname, 'name')
2812
Simon Glass71ce0ba2019-07-08 14:25:52 -06002813 def testExtractCmd(self):
2814 """Test extracting a file fron an image on the command line"""
2815 self._CheckLz4()
2816 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass71ce0ba2019-07-08 14:25:52 -06002817 fname = os.path.join(self._indir, 'output.extact')
Simon Glassf86a7362019-07-20 12:24:10 -06002818 try:
2819 tmpdir, updated_fname = self._SetupImageInTmpdir()
2820 with test_util.capture_sys_output() as (stdout, stderr):
2821 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2822 '-f', fname)
2823 finally:
2824 shutil.rmtree(tmpdir)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002825 data = tools.ReadFile(fname)
2826 self.assertEqual(U_BOOT_DATA, data)
2827
2828 def testExtractOneEntry(self):
2829 """Test extracting a single entry fron an image """
2830 self._CheckLz4()
2831 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2832 image_fname = tools.GetOutputFilename('image.bin')
2833 fname = os.path.join(self._indir, 'output.extact')
2834 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
2835 data = tools.ReadFile(fname)
2836 self.assertEqual(U_BOOT_DATA, data)
2837
2838 def _CheckExtractOutput(self, decomp):
2839 """Helper to test file output with and without decompression
2840
2841 Args:
2842 decomp: True to decompress entry data, False to output it raw
2843 """
2844 def _CheckPresent(entry_path, expect_data, expect_size=None):
2845 """Check and remove expected file
2846
2847 This checks the data/size of a file and removes the file both from
2848 the outfiles set and from the output directory. Once all files are
2849 processed, both the set and directory should be empty.
2850
2851 Args:
2852 entry_path: Entry path
2853 expect_data: Data to expect in file, or None to skip check
2854 expect_size: Size of data to expect in file, or None to skip
2855 """
2856 path = os.path.join(outdir, entry_path)
2857 data = tools.ReadFile(path)
2858 os.remove(path)
2859 if expect_data:
2860 self.assertEqual(expect_data, data)
2861 elif expect_size:
2862 self.assertEqual(expect_size, len(data))
2863 outfiles.remove(path)
2864
2865 def _CheckDirPresent(name):
2866 """Remove expected directory
2867
2868 This gives an error if the directory does not exist as expected
2869
2870 Args:
2871 name: Name of directory to remove
2872 """
2873 path = os.path.join(outdir, name)
2874 os.rmdir(path)
2875
2876 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2877 image_fname = tools.GetOutputFilename('image.bin')
2878 outdir = os.path.join(self._indir, 'extract')
2879 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2880
2881 # Create a set of all file that were output (should be 9)
2882 outfiles = set()
2883 for root, dirs, files in os.walk(outdir):
2884 outfiles |= set([os.path.join(root, fname) for fname in files])
2885 self.assertEqual(9, len(outfiles))
2886 self.assertEqual(9, len(einfos))
2887
2888 image = control.images['image']
2889 entries = image.GetEntries()
2890
2891 # Check the 9 files in various ways
2892 section = entries['section']
2893 section_entries = section.GetEntries()
2894 cbfs_entries = section_entries['cbfs'].GetEntries()
2895 _CheckPresent('u-boot', U_BOOT_DATA)
2896 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
2897 dtb_len = EXTRACT_DTB_SIZE
2898 if not decomp:
2899 dtb_len = cbfs_entries['u-boot-dtb'].size
2900 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
2901 if not decomp:
2902 dtb_len = section_entries['u-boot-dtb'].size
2903 _CheckPresent('section/u-boot-dtb', None, dtb_len)
2904
2905 fdtmap = entries['fdtmap']
2906 _CheckPresent('fdtmap', fdtmap.data)
2907 hdr = entries['image-header']
2908 _CheckPresent('image-header', hdr.data)
2909
2910 _CheckPresent('section/root', section.data)
2911 cbfs = section_entries['cbfs']
2912 _CheckPresent('section/cbfs/root', cbfs.data)
2913 data = tools.ReadFile(image_fname)
2914 _CheckPresent('root', data)
2915
2916 # There should be no files left. Remove all the directories to check.
2917 # If there are any files/dirs remaining, one of these checks will fail.
2918 self.assertEqual(0, len(outfiles))
2919 _CheckDirPresent('section/cbfs')
2920 _CheckDirPresent('section')
2921 _CheckDirPresent('')
2922 self.assertFalse(os.path.exists(outdir))
2923
2924 def testExtractAllEntries(self):
2925 """Test extracting all entries"""
2926 self._CheckLz4()
2927 self._CheckExtractOutput(decomp=True)
2928
2929 def testExtractAllEntriesRaw(self):
2930 """Test extracting all entries without decompressing them"""
2931 self._CheckLz4()
2932 self._CheckExtractOutput(decomp=False)
2933
2934 def testExtractSelectedEntries(self):
2935 """Test extracting some entries"""
2936 self._CheckLz4()
2937 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2938 image_fname = tools.GetOutputFilename('image.bin')
2939 outdir = os.path.join(self._indir, 'extract')
2940 einfos = control.ExtractEntries(image_fname, None, outdir,
2941 ['*cb*', '*head*'])
2942
2943 # File output is tested by testExtractAllEntries(), so just check that
2944 # the expected entries are selected
2945 names = [einfo.name for einfo in einfos]
2946 self.assertEqual(names,
2947 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2948
2949 def testExtractNoEntryPaths(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, [])
Simon Glassbb5edc12019-07-20 12:24:14 -06002956 self.assertIn('Must specify an entry path to write with -f',
Simon Glass71ce0ba2019-07-08 14:25:52 -06002957 str(e.exception))
2958
2959 def testExtractTooManyEntryPaths(self):
2960 """Test extracting some entries"""
2961 self._CheckLz4()
2962 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2963 image_fname = tools.GetOutputFilename('image.bin')
2964 with self.assertRaises(ValueError) as e:
2965 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassbb5edc12019-07-20 12:24:14 -06002966 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass71ce0ba2019-07-08 14:25:52 -06002967 str(e.exception))
2968
Simon Glasse2705fa2019-07-08 14:25:53 -06002969 def testPackAlignSection(self):
2970 """Test that sections can have alignment"""
2971 self._DoReadFile('131_pack_align_section.dts')
2972
2973 self.assertIn('image', control.images)
2974 image = control.images['image']
2975 entries = image.GetEntries()
2976 self.assertEqual(3, len(entries))
2977
2978 # First u-boot
2979 self.assertIn('u-boot', entries)
2980 entry = entries['u-boot']
2981 self.assertEqual(0, entry.offset)
2982 self.assertEqual(0, entry.image_pos)
2983 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2984 self.assertEqual(len(U_BOOT_DATA), entry.size)
2985
2986 # Section0
2987 self.assertIn('section0', entries)
2988 section0 = entries['section0']
2989 self.assertEqual(0x10, section0.offset)
2990 self.assertEqual(0x10, section0.image_pos)
2991 self.assertEqual(len(U_BOOT_DATA), section0.size)
2992
2993 # Second u-boot
2994 section_entries = section0.GetEntries()
2995 self.assertIn('u-boot', section_entries)
2996 entry = section_entries['u-boot']
2997 self.assertEqual(0, entry.offset)
2998 self.assertEqual(0x10, entry.image_pos)
2999 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3000 self.assertEqual(len(U_BOOT_DATA), entry.size)
3001
3002 # Section1
3003 self.assertIn('section1', entries)
3004 section1 = entries['section1']
3005 self.assertEqual(0x14, section1.offset)
3006 self.assertEqual(0x14, section1.image_pos)
3007 self.assertEqual(0x20, section1.size)
3008
3009 # Second u-boot
3010 section_entries = section1.GetEntries()
3011 self.assertIn('u-boot', section_entries)
3012 entry = section_entries['u-boot']
3013 self.assertEqual(0, entry.offset)
3014 self.assertEqual(0x14, entry.image_pos)
3015 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3016 self.assertEqual(len(U_BOOT_DATA), entry.size)
3017
3018 # Section2
3019 self.assertIn('section2', section_entries)
3020 section2 = section_entries['section2']
3021 self.assertEqual(0x4, section2.offset)
3022 self.assertEqual(0x18, section2.image_pos)
3023 self.assertEqual(4, section2.size)
3024
3025 # Third u-boot
3026 section_entries = section2.GetEntries()
3027 self.assertIn('u-boot', section_entries)
3028 entry = section_entries['u-boot']
3029 self.assertEqual(0, entry.offset)
3030 self.assertEqual(0x18, entry.image_pos)
3031 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3032 self.assertEqual(len(U_BOOT_DATA), entry.size)
3033
Simon Glass51014aa2019-07-20 12:23:56 -06003034 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3035 dts='132_replace.dts'):
Simon Glass10f9d002019-07-20 12:23:50 -06003036 """Replace an entry in an image
3037
3038 This writes the entry data to update it, then opens the updated file and
3039 returns the value that it now finds there.
3040
3041 Args:
3042 entry_name: Entry name to replace
3043 data: Data to replace it with
3044 decomp: True to compress the data if needed, False if data is
3045 already compressed so should be used as is
Simon Glass51014aa2019-07-20 12:23:56 -06003046 allow_resize: True to allow entries to change size, False to raise
3047 an exception
Simon Glass10f9d002019-07-20 12:23:50 -06003048
3049 Returns:
3050 Tuple:
3051 data from entry
3052 data from fdtmap (excluding header)
Simon Glass51014aa2019-07-20 12:23:56 -06003053 Image object that was modified
Simon Glass10f9d002019-07-20 12:23:50 -06003054 """
Simon Glass51014aa2019-07-20 12:23:56 -06003055 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass10f9d002019-07-20 12:23:50 -06003056 update_dtb=True)[1]
3057
3058 self.assertIn('image', control.images)
3059 image = control.images['image']
3060 entries = image.GetEntries()
3061 orig_dtb_data = entries['u-boot-dtb'].data
3062 orig_fdtmap_data = entries['fdtmap'].data
3063
3064 image_fname = tools.GetOutputFilename('image.bin')
3065 updated_fname = tools.GetOutputFilename('image-updated.bin')
3066 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
Simon Glass51014aa2019-07-20 12:23:56 -06003067 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3068 allow_resize)
Simon Glass10f9d002019-07-20 12:23:50 -06003069 data = control.ReadEntry(updated_fname, entry_name, decomp)
3070
Simon Glass51014aa2019-07-20 12:23:56 -06003071 # The DT data should not change unless resized:
3072 if not allow_resize:
3073 new_dtb_data = entries['u-boot-dtb'].data
3074 self.assertEqual(new_dtb_data, orig_dtb_data)
3075 new_fdtmap_data = entries['fdtmap'].data
3076 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass10f9d002019-07-20 12:23:50 -06003077
Simon Glass51014aa2019-07-20 12:23:56 -06003078 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass10f9d002019-07-20 12:23:50 -06003079
3080 def testReplaceSimple(self):
3081 """Test replacing a single file"""
3082 expected = b'x' * len(U_BOOT_DATA)
Simon Glass51014aa2019-07-20 12:23:56 -06003083 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3084 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06003085 self.assertEqual(expected, data)
3086
3087 # Test that the state looks right. There should be an FDT for the fdtmap
3088 # that we jsut read back in, and it should match what we find in the
3089 # 'control' tables. Checking for an FDT that does not exist should
3090 # return None.
3091 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glass51014aa2019-07-20 12:23:56 -06003092 self.assertIsNotNone(path)
Simon Glass10f9d002019-07-20 12:23:50 -06003093 self.assertEqual(expected_fdtmap, fdtmap)
3094
3095 dtb = state.GetFdtForEtype('fdtmap')
3096 self.assertEqual(dtb.GetContents(), fdtmap)
3097
3098 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3099 self.assertIsNone(missing_path)
3100 self.assertIsNone(missing_fdtmap)
3101
3102 missing_dtb = state.GetFdtForEtype('missing')
3103 self.assertIsNone(missing_dtb)
3104
3105 self.assertEqual('/binman', state.fdt_path_prefix)
3106
3107 def testReplaceResizeFail(self):
3108 """Test replacing a file by something larger"""
3109 expected = U_BOOT_DATA + b'x'
3110 with self.assertRaises(ValueError) as e:
Simon Glass51014aa2019-07-20 12:23:56 -06003111 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3112 dts='139_replace_repack.dts')
Simon Glass10f9d002019-07-20 12:23:50 -06003113 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3114 str(e.exception))
3115
3116 def testReplaceMulti(self):
3117 """Test replacing entry data where multiple images are generated"""
3118 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3119 update_dtb=True)[0]
3120 expected = b'x' * len(U_BOOT_DATA)
3121 updated_fname = tools.GetOutputFilename('image-updated.bin')
3122 tools.WriteFile(updated_fname, data)
3123 entry_name = 'u-boot'
Simon Glass51014aa2019-07-20 12:23:56 -06003124 control.WriteEntry(updated_fname, entry_name, expected,
3125 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06003126 data = control.ReadEntry(updated_fname, entry_name)
3127 self.assertEqual(expected, data)
3128
3129 # Check the state looks right.
3130 self.assertEqual('/binman/image', state.fdt_path_prefix)
3131
3132 # Now check we can write the first image
3133 image_fname = tools.GetOutputFilename('first-image.bin')
3134 updated_fname = tools.GetOutputFilename('first-updated.bin')
3135 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
3136 entry_name = 'u-boot'
Simon Glass51014aa2019-07-20 12:23:56 -06003137 control.WriteEntry(updated_fname, entry_name, expected,
3138 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06003139 data = control.ReadEntry(updated_fname, entry_name)
3140 self.assertEqual(expected, data)
3141
3142 # Check the state looks right.
3143 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass8beb11e2019-07-08 14:25:47 -06003144
Simon Glass12bb1a92019-07-20 12:23:51 -06003145 def testUpdateFdtAllRepack(self):
3146 """Test that all device trees are updated with offset/size info"""
3147 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3148 SECTION_SIZE = 0x300
3149 DTB_SIZE = 602
3150 FDTMAP_SIZE = 608
3151 base_expected = {
3152 'offset': 0,
3153 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3154 'image-pos': 0,
3155 'section:offset': 0,
3156 'section:size': SECTION_SIZE,
3157 'section:image-pos': 0,
3158 'section/u-boot-dtb:offset': 4,
3159 'section/u-boot-dtb:size': 636,
3160 'section/u-boot-dtb:image-pos': 4,
3161 'u-boot-spl-dtb:offset': SECTION_SIZE,
3162 'u-boot-spl-dtb:size': DTB_SIZE,
3163 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3164 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3165 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3166 'u-boot-tpl-dtb:size': DTB_SIZE,
3167 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3168 'fdtmap:size': FDTMAP_SIZE,
3169 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3170 }
3171 main_expected = {
3172 'section:orig-size': SECTION_SIZE,
3173 'section/u-boot-dtb:orig-offset': 4,
3174 }
3175
3176 # We expect three device-tree files in the output, with the first one
3177 # within a fixed-size section.
3178 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3179 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3180 # main U-Boot tree. All three should have the same positions and offset
3181 # except that the main tree should include the main_expected properties
3182 start = 4
3183 for item in ['', 'spl', 'tpl', None]:
3184 if item is None:
3185 start += 16 # Move past fdtmap header
3186 dtb = fdt.Fdt.FromData(data[start:])
3187 dtb.Scan()
3188 props = self._GetPropTree(dtb,
3189 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3190 prefix='/' if item is None else '/binman/')
3191 expected = dict(base_expected)
3192 if item:
3193 expected[item] = 0
3194 else:
3195 # Main DTB and fdtdec should include the 'orig-' properties
3196 expected.update(main_expected)
3197 # Helpful for debugging:
3198 #for prop in sorted(props):
3199 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3200 self.assertEqual(expected, props)
3201 if item == '':
3202 start = SECTION_SIZE
3203 else:
3204 start += dtb._fdt_obj.totalsize()
3205
Simon Glasseba1f0c2019-07-20 12:23:55 -06003206 def testFdtmapHeaderMiddle(self):
3207 """Test an FDT map in the middle of an image when it should be at end"""
3208 with self.assertRaises(ValueError) as e:
3209 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3210 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3211 str(e.exception))
3212
3213 def testFdtmapHeaderStartBad(self):
3214 """Test an FDT map in middle of an image when it should be at start"""
3215 with self.assertRaises(ValueError) as e:
3216 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3217 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3218 str(e.exception))
3219
3220 def testFdtmapHeaderEndBad(self):
3221 """Test an FDT map at the start of an image when it should be at end"""
3222 with self.assertRaises(ValueError) as e:
3223 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3224 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3225 str(e.exception))
3226
3227 def testFdtmapHeaderNoSize(self):
3228 """Test an image header at the end of an image with undefined size"""
3229 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3230
Simon Glass51014aa2019-07-20 12:23:56 -06003231 def testReplaceResize(self):
3232 """Test replacing a single file in an entry with a larger file"""
3233 expected = U_BOOT_DATA + b'x'
3234 data, _, image = self._RunReplaceCmd('u-boot', expected,
3235 dts='139_replace_repack.dts')
3236 self.assertEqual(expected, data)
3237
3238 entries = image.GetEntries()
3239 dtb_data = entries['u-boot-dtb'].data
3240 dtb = fdt.Fdt.FromData(dtb_data)
3241 dtb.Scan()
3242
3243 # The u-boot section should now be larger in the dtb
3244 node = dtb.GetNode('/binman/u-boot')
3245 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3246
3247 # Same for the fdtmap
3248 fdata = entries['fdtmap'].data
3249 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3250 fdtb.Scan()
3251 fnode = fdtb.GetNode('/u-boot')
3252 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3253
3254 def testReplaceResizeNoRepack(self):
3255 """Test replacing an entry with a larger file when not allowed"""
3256 expected = U_BOOT_DATA + b'x'
3257 with self.assertRaises(ValueError) as e:
3258 self._RunReplaceCmd('u-boot', expected)
3259 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3260 str(e.exception))
3261
Simon Glass61ec04f2019-07-20 12:23:58 -06003262 def testEntryShrink(self):
3263 """Test contracting an entry after it is packed"""
3264 try:
3265 state.SetAllowEntryContraction(True)
3266 data = self._DoReadFileDtb('140_entry_shrink.dts',
3267 update_dtb=True)[0]
3268 finally:
3269 state.SetAllowEntryContraction(False)
3270 self.assertEqual(b'a', data[:1])
3271 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3272 self.assertEqual(b'a', data[-1:])
3273
3274 def testEntryShrinkFail(self):
3275 """Test not being allowed to contract an entry after it is packed"""
3276 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3277
3278 # In this case there is a spare byte at the end of the data. The size of
3279 # the contents is only 1 byte but we still have the size before it
3280 # shrunk.
3281 self.assertEqual(b'a\0', data[:2])
3282 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3283 self.assertEqual(b'a\0', data[-2:])
3284
Simon Glass27145fd2019-07-20 12:24:01 -06003285 def testDescriptorOffset(self):
3286 """Test that the Intel descriptor is always placed at at the start"""
3287 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3288 image = control.images['image']
3289 entries = image.GetEntries()
3290 desc = entries['intel-descriptor']
3291 self.assertEqual(0xff800000, desc.offset);
3292 self.assertEqual(0xff800000, desc.image_pos);
3293
Simon Glasseb0f4a42019-07-20 12:24:06 -06003294 def testReplaceCbfs(self):
3295 """Test replacing a single file in CBFS without changing the size"""
3296 self._CheckLz4()
3297 expected = b'x' * len(U_BOOT_DATA)
3298 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3299 updated_fname = tools.GetOutputFilename('image-updated.bin')
3300 tools.WriteFile(updated_fname, data)
3301 entry_name = 'section/cbfs/u-boot'
3302 control.WriteEntry(updated_fname, entry_name, expected,
3303 allow_resize=True)
3304 data = control.ReadEntry(updated_fname, entry_name)
3305 self.assertEqual(expected, data)
3306
3307 def testReplaceResizeCbfs(self):
3308 """Test replacing a single file in CBFS with one of a different size"""
3309 self._CheckLz4()
3310 expected = U_BOOT_DATA + b'x'
3311 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3312 updated_fname = tools.GetOutputFilename('image-updated.bin')
3313 tools.WriteFile(updated_fname, data)
3314 entry_name = 'section/cbfs/u-boot'
3315 control.WriteEntry(updated_fname, entry_name, expected,
3316 allow_resize=True)
3317 data = control.ReadEntry(updated_fname, entry_name)
3318 self.assertEqual(expected, data)
3319
Simon Glassa6cb9952019-07-20 12:24:15 -06003320 def _SetupForReplace(self):
3321 """Set up some files to use to replace entries
3322
3323 This generates an image, copies it to a new file, extracts all the files
3324 in it and updates some of them
3325
3326 Returns:
3327 List
3328 Image filename
3329 Output directory
3330 Expected values for updated entries, each a string
3331 """
3332 data = self._DoReadFileRealDtb('143_replace_all.dts')
3333
3334 updated_fname = tools.GetOutputFilename('image-updated.bin')
3335 tools.WriteFile(updated_fname, data)
3336
3337 outdir = os.path.join(self._indir, 'extract')
3338 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3339
3340 expected1 = b'x' + U_BOOT_DATA + b'y'
3341 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3342 tools.WriteFile(u_boot_fname1, expected1)
3343
3344 expected2 = b'a' + U_BOOT_DATA + b'b'
3345 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
3346 tools.WriteFile(u_boot_fname2, expected2)
3347
3348 expected_text = b'not the same text'
3349 text_fname = os.path.join(outdir, 'text')
3350 tools.WriteFile(text_fname, expected_text)
3351
3352 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3353 dtb = fdt.FdtScan(dtb_fname)
3354 node = dtb.GetNode('/binman/text')
3355 node.AddString('my-property', 'the value')
3356 dtb.Sync(auto_resize=True)
3357 dtb.Flush()
3358
3359 return updated_fname, outdir, expected1, expected2, expected_text
3360
3361 def _CheckReplaceMultiple(self, entry_paths):
3362 """Handle replacing the contents of multiple entries
3363
3364 Args:
3365 entry_paths: List of entry paths to replace
3366
3367 Returns:
3368 List
3369 Dict of entries in the image:
3370 key: Entry name
3371 Value: Entry object
3372 Expected values for updated entries, each a string
3373 """
3374 updated_fname, outdir, expected1, expected2, expected_text = (
3375 self._SetupForReplace())
3376 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3377
3378 image = Image.FromFile(updated_fname)
3379 image.LoadData()
3380 return image.GetEntries(), expected1, expected2, expected_text
3381
3382 def testReplaceAll(self):
3383 """Test replacing the contents of all entries"""
3384 entries, expected1, expected2, expected_text = (
3385 self._CheckReplaceMultiple([]))
3386 data = entries['u-boot'].data
3387 self.assertEqual(expected1, data)
3388
3389 data = entries['u-boot2'].data
3390 self.assertEqual(expected2, data)
3391
3392 data = entries['text'].data
3393 self.assertEqual(expected_text, data)
3394
3395 # Check that the device tree is updated
3396 data = entries['u-boot-dtb'].data
3397 dtb = fdt.Fdt.FromData(data)
3398 dtb.Scan()
3399 node = dtb.GetNode('/binman/text')
3400 self.assertEqual('the value', node.props['my-property'].value)
3401
3402 def testReplaceSome(self):
3403 """Test replacing the contents of a few entries"""
3404 entries, expected1, expected2, expected_text = (
3405 self._CheckReplaceMultiple(['u-boot2', 'text']))
3406
3407 # This one should not change
3408 data = entries['u-boot'].data
3409 self.assertEqual(U_BOOT_DATA, data)
3410
3411 data = entries['u-boot2'].data
3412 self.assertEqual(expected2, data)
3413
3414 data = entries['text'].data
3415 self.assertEqual(expected_text, data)
3416
3417 def testReplaceCmd(self):
3418 """Test replacing a file fron an image on the command line"""
3419 self._DoReadFileRealDtb('143_replace_all.dts')
3420
3421 try:
3422 tmpdir, updated_fname = self._SetupImageInTmpdir()
3423
3424 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3425 expected = b'x' * len(U_BOOT_DATA)
3426 tools.WriteFile(fname, expected)
3427
3428 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
3429 data = tools.ReadFile(updated_fname)
3430 self.assertEqual(expected, data[:len(expected)])
3431 map_fname = os.path.join(tmpdir, 'image-updated.map')
3432 self.assertFalse(os.path.exists(map_fname))
3433 finally:
3434 shutil.rmtree(tmpdir)
3435
3436 def testReplaceCmdSome(self):
3437 """Test replacing some files fron an image on the command line"""
3438 updated_fname, outdir, expected1, expected2, expected_text = (
3439 self._SetupForReplace())
3440
3441 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3442 'u-boot2', 'text')
3443
3444 tools.PrepareOutputDir(None)
3445 image = Image.FromFile(updated_fname)
3446 image.LoadData()
3447 entries = image.GetEntries()
3448
3449 # This one should not change
3450 data = entries['u-boot'].data
3451 self.assertEqual(U_BOOT_DATA, data)
3452
3453 data = entries['u-boot2'].data
3454 self.assertEqual(expected2, data)
3455
3456 data = entries['text'].data
3457 self.assertEqual(expected_text, data)
3458
3459 def testReplaceMissing(self):
3460 """Test replacing entries where the file is missing"""
3461 updated_fname, outdir, expected1, expected2, expected_text = (
3462 self._SetupForReplace())
3463
3464 # Remove one of the files, to generate a warning
3465 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3466 os.remove(u_boot_fname1)
3467
3468 with test_util.capture_sys_output() as (stdout, stderr):
3469 control.ReplaceEntries(updated_fname, None, outdir, [])
3470 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass38fdb4c2020-07-09 18:39:39 -06003471 stderr.getvalue())
Simon Glassa6cb9952019-07-20 12:24:15 -06003472
3473 def testReplaceCmdMap(self):
3474 """Test replacing a file fron an image on the command line"""
3475 self._DoReadFileRealDtb('143_replace_all.dts')
3476
3477 try:
3478 tmpdir, updated_fname = self._SetupImageInTmpdir()
3479
3480 fname = os.path.join(self._indir, 'update-u-boot.bin')
3481 expected = b'x' * len(U_BOOT_DATA)
3482 tools.WriteFile(fname, expected)
3483
3484 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3485 '-f', fname, '-m')
3486 map_fname = os.path.join(tmpdir, 'image-updated.map')
3487 self.assertTrue(os.path.exists(map_fname))
3488 finally:
3489 shutil.rmtree(tmpdir)
3490
3491 def testReplaceNoEntryPaths(self):
3492 """Test replacing an entry without an entry path"""
3493 self._DoReadFileRealDtb('143_replace_all.dts')
3494 image_fname = tools.GetOutputFilename('image.bin')
3495 with self.assertRaises(ValueError) as e:
3496 control.ReplaceEntries(image_fname, 'fname', None, [])
3497 self.assertIn('Must specify an entry path to read with -f',
3498 str(e.exception))
3499
3500 def testReplaceTooManyEntryPaths(self):
3501 """Test extracting some entries"""
3502 self._DoReadFileRealDtb('143_replace_all.dts')
3503 image_fname = tools.GetOutputFilename('image.bin')
3504 with self.assertRaises(ValueError) as e:
3505 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3506 self.assertIn('Must specify exactly one entry path to write with -f',
3507 str(e.exception))
3508
Simon Glass2250ee62019-08-24 07:22:48 -06003509 def testPackReset16(self):
3510 """Test that an image with an x86 reset16 region can be created"""
3511 data = self._DoReadFile('144_x86_reset16.dts')
3512 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3513
3514 def testPackReset16Spl(self):
3515 """Test that an image with an x86 reset16-spl region can be created"""
3516 data = self._DoReadFile('145_x86_reset16_spl.dts')
3517 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3518
3519 def testPackReset16Tpl(self):
3520 """Test that an image with an x86 reset16-tpl region can be created"""
3521 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3522 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3523
Simon Glass5af12072019-08-24 07:22:50 -06003524 def testPackIntelFit(self):
3525 """Test that an image with an Intel FIT and pointer can be created"""
3526 data = self._DoReadFile('147_intel_fit.dts')
3527 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3528 fit = data[16:32];
3529 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3530 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3531
3532 image = control.images['image']
3533 entries = image.GetEntries()
3534 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3535 self.assertEqual(expected_ptr, ptr)
3536
3537 def testPackIntelFitMissing(self):
3538 """Test detection of a FIT pointer with not FIT region"""
3539 with self.assertRaises(ValueError) as e:
3540 self._DoReadFile('148_intel_fit_missing.dts')
3541 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3542 str(e.exception))
3543
Simon Glass7c150132019-11-06 17:22:44 -07003544 def _CheckSymbolsTplSection(self, dts, expected_vals):
3545 data = self._DoReadFile(dts)
3546 sym_values = struct.pack('<LQLL', *expected_vals)
Simon Glass2090f1e2019-08-24 07:23:00 -06003547 upto1 = 4 + len(U_BOOT_SPL_DATA)
Simon Glassb87064c2019-08-24 07:23:05 -06003548 expected1 = tools.GetBytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[20:]
Simon Glass2090f1e2019-08-24 07:23:00 -06003549 self.assertEqual(expected1, data[:upto1])
3550
3551 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Simon Glassb87064c2019-08-24 07:23:05 -06003552 expected2 = tools.GetBytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[20:]
Simon Glass2090f1e2019-08-24 07:23:00 -06003553 self.assertEqual(expected2, data[upto1:upto2])
3554
Simon Glasseb0086f2019-08-24 07:23:04 -06003555 upto3 = 0x34 + len(U_BOOT_DATA)
3556 expected3 = tools.GetBytes(0xff, 1) + U_BOOT_DATA
Simon Glass2090f1e2019-08-24 07:23:00 -06003557 self.assertEqual(expected3, data[upto2:upto3])
3558
Simon Glassb87064c2019-08-24 07:23:05 -06003559 expected4 = sym_values + U_BOOT_TPL_DATA[20:]
Simon Glass7c150132019-11-06 17:22:44 -07003560 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3561
3562 def testSymbolsTplSection(self):
3563 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3564 self._SetupSplElf('u_boot_binman_syms')
3565 self._SetupTplElf('u_boot_binman_syms')
3566 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
3567 [0x04, 0x1c, 0x10 + 0x34, 0x04])
3568
3569 def testSymbolsTplSectionX86(self):
3570 """Test binman can assign symbols in a section with end-at-4gb"""
3571 self._SetupSplElf('u_boot_binman_syms_x86')
3572 self._SetupTplElf('u_boot_binman_syms_x86')
3573 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
3574 [0xffffff04, 0xffffff1c, 0xffffff34,
3575 0x04])
Simon Glass2090f1e2019-08-24 07:23:00 -06003576
Simon Glassbf4d0e22019-08-24 07:23:03 -06003577 def testPackX86RomIfwiSectiom(self):
3578 """Test that a section can be placed in an IFWI region"""
3579 self._SetupIfwi('fitimage.bin')
3580 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3581 self._CheckIfwi(data)
3582
Simon Glassea0fff92019-08-24 07:23:07 -06003583 def testPackFspM(self):
3584 """Test that an image with a FSP memory-init binary can be created"""
3585 data = self._DoReadFile('152_intel_fsp_m.dts')
3586 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3587
Simon Glassbc6a88f2019-10-20 21:31:35 -06003588 def testPackFspS(self):
3589 """Test that an image with a FSP silicon-init binary can be created"""
3590 data = self._DoReadFile('153_intel_fsp_s.dts')
3591 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassea0fff92019-08-24 07:23:07 -06003592
Simon Glass998d1482019-10-20 21:31:36 -06003593 def testPackFspT(self):
3594 """Test that an image with a FSP temp-ram-init binary can be created"""
3595 data = self._DoReadFile('154_intel_fsp_t.dts')
3596 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3597
Simon Glass0dc706f2020-07-09 18:39:31 -06003598 def testMkimage(self):
3599 """Test using mkimage to build an image"""
3600 data = self._DoReadFile('156_mkimage.dts')
3601
3602 # Just check that the data appears in the file somewhere
3603 self.assertIn(U_BOOT_SPL_DATA, data)
3604
Simon Glassce867ad2020-07-09 18:39:36 -06003605 def testExtblob(self):
3606 """Test an image with an external blob"""
3607 data = self._DoReadFile('157_blob_ext.dts')
3608 self.assertEqual(REFCODE_DATA, data)
3609
3610 def testExtblobMissing(self):
3611 """Test an image with a missing external blob"""
3612 with self.assertRaises(ValueError) as e:
3613 self._DoReadFile('158_blob_ext_missing.dts')
3614 self.assertIn("Filename 'missing-file' not found in input path",
3615 str(e.exception))
3616
Simon Glass4f9f1052020-07-09 18:39:38 -06003617 def testExtblobMissingOk(self):
3618 """Test an image with an missing external blob that is allowed"""
Simon Glassb1cca952020-07-09 18:39:40 -06003619 with test_util.capture_sys_output() as (stdout, stderr):
3620 self._DoTestFile('158_blob_ext_missing.dts', allow_missing=True)
3621 err = stderr.getvalue()
3622 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
3623
3624 def testExtblobMissingOkSect(self):
3625 """Test an image with an missing external blob that is allowed"""
3626 with test_util.capture_sys_output() as (stdout, stderr):
3627 self._DoTestFile('159_blob_ext_missing_sect.dts',
3628 allow_missing=True)
3629 err = stderr.getvalue()
3630 self.assertRegex(err, "Image 'main-section'.*missing.*: "
3631 "blob-ext blob-ext2")
Simon Glass4f9f1052020-07-09 18:39:38 -06003632
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003633 def testPackX86RomMeMissingDesc(self):
3634 """Test that an missing Intel descriptor entry is allowed"""
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003635 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass52b10dd2020-07-25 15:11:19 -06003636 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003637 err = stderr.getvalue()
3638 self.assertRegex(err,
3639 "Image 'main-section'.*missing.*: intel-descriptor")
3640
3641 def testPackX86RomMissingIfwi(self):
3642 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3643 self._SetupIfwi('fitimage.bin')
3644 pathname = os.path.join(self._indir, 'fitimage.bin')
3645 os.remove(pathname)
3646 with test_util.capture_sys_output() as (stdout, stderr):
3647 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3648 err = stderr.getvalue()
3649 self.assertRegex(err, "Image 'main-section'.*missing.*: intel-ifwi")
3650
Simon Glassb3295fd2020-07-09 18:39:42 -06003651 def testPackOverlap(self):
3652 """Test that zero-size overlapping regions are ignored"""
3653 self._DoTestFile('160_pack_overlap_zero.dts')
3654
Simon Glassfdc34362020-07-09 18:39:45 -06003655 def testSimpleFit(self):
3656 """Test an image with a FIT inside"""
3657 data = self._DoReadFile('161_fit.dts')
3658 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3659 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3660 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3661
3662 # The data should be inside the FIT
3663 dtb = fdt.Fdt.FromData(fit_data)
3664 dtb.Scan()
3665 fnode = dtb.GetNode('/images/kernel')
3666 self.assertIn('data', fnode.props)
3667
3668 fname = os.path.join(self._indir, 'fit_data.fit')
3669 tools.WriteFile(fname, fit_data)
3670 out = tools.Run('dumpimage', '-l', fname)
3671
3672 # Check a few features to make sure the plumbing works. We don't need
3673 # to test the operation of mkimage or dumpimage here. First convert the
3674 # output into a dict where the keys are the fields printed by dumpimage
3675 # and the values are a list of values for each field
3676 lines = out.splitlines()
3677
3678 # Converts "Compression: gzip compressed" into two groups:
3679 # 'Compression' and 'gzip compressed'
3680 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3681 vals = collections.defaultdict(list)
3682 for line in lines:
3683 mat = re_line.match(line)
3684 vals[mat.group(1)].append(mat.group(2))
3685
3686 self.assertEquals('FIT description: test-desc', lines[0])
3687 self.assertIn('Created:', lines[1])
3688 self.assertIn('Image 0 (kernel)', vals)
3689 self.assertIn('Hash value', vals)
3690 data_sizes = vals.get('Data Size')
3691 self.assertIsNotNone(data_sizes)
3692 self.assertEqual(2, len(data_sizes))
3693 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
3694 self.assertEqual(len(U_BOOT_DATA), int(data_sizes[0].split()[0]))
3695 self.assertEqual(len(U_BOOT_SPL_DTB_DATA), int(data_sizes[1].split()[0]))
3696
3697 def testFitExternal(self):
Simon Glasse9d336d2020-09-01 05:13:55 -06003698 """Test an image with an FIT with external images"""
Simon Glassfdc34362020-07-09 18:39:45 -06003699 data = self._DoReadFile('162_fit_external.dts')
3700 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3701
3702 # The data should be outside the FIT
3703 dtb = fdt.Fdt.FromData(fit_data)
3704 dtb.Scan()
3705 fnode = dtb.GetNode('/images/kernel')
3706 self.assertNotIn('data', fnode.props)
Simon Glass12bb1a92019-07-20 12:23:51 -06003707
Alper Nebi Yasak8001d0b2020-08-31 12:58:18 +03003708 def testSectionIgnoreHashSignature(self):
3709 """Test that sections ignore hash, signature nodes for its data"""
3710 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
3711 expected = (U_BOOT_DATA + U_BOOT_DATA)
3712 self.assertEqual(expected, data)
3713
Alper Nebi Yasak3fdeb142020-08-31 12:58:19 +03003714 def testPadInSections(self):
3715 """Test pad-before, pad-after for entries in sections"""
Simon Glassf90d9062020-10-26 17:40:09 -06003716 data, _, _, out_dtb_fname = self._DoReadFileDtb(
3717 '166_pad_in_sections.dts', update_dtb=True)
Alper Nebi Yasak3fdeb142020-08-31 12:58:19 +03003718 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
3719 U_BOOT_DATA + tools.GetBytes(ord('!'), 6) +
3720 U_BOOT_DATA)
3721 self.assertEqual(expected, data)
3722
Simon Glassf90d9062020-10-26 17:40:09 -06003723 dtb = fdt.Fdt(out_dtb_fname)
3724 dtb.Scan()
3725 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
3726 expected = {
3727 'image-pos': 0,
3728 'offset': 0,
3729 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
3730
3731 'section:image-pos': 0,
3732 'section:offset': 0,
3733 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
3734
3735 'section/before:image-pos': 0,
3736 'section/before:offset': 0,
3737 'section/before:size': len(U_BOOT_DATA),
3738
3739 'section/u-boot:image-pos': 4,
3740 'section/u-boot:offset': 4,
3741 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
3742
3743 'section/after:image-pos': 26,
3744 'section/after:offset': 26,
3745 'section/after:size': len(U_BOOT_DATA),
3746 }
3747 self.assertEqual(expected, props)
3748
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03003749 def testFitImageSubentryAlignment(self):
3750 """Test relative alignability of FIT image subentries"""
3751 entry_args = {
3752 'test-id': TEXT_DATA,
3753 }
3754 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
3755 entry_args=entry_args)
3756 dtb = fdt.Fdt.FromData(data)
3757 dtb.Scan()
3758
3759 node = dtb.GetNode('/images/kernel')
3760 data = dtb.GetProps(node)["data"].bytes
3761 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
3762 expected = (tools.GetBytes(0, 0x20) + U_BOOT_SPL_DATA +
3763 tools.GetBytes(0, align_pad) + U_BOOT_DATA)
3764 self.assertEqual(expected, data)
3765
3766 node = dtb.GetNode('/images/fdt-1')
3767 data = dtb.GetProps(node)["data"].bytes
3768 expected = (U_BOOT_SPL_DTB_DATA + tools.GetBytes(0, 20) +
3769 tools.ToBytes(TEXT_DATA) + tools.GetBytes(0, 30) +
3770 U_BOOT_DTB_DATA)
3771 self.assertEqual(expected, data)
3772
3773 def testFitExtblobMissingOk(self):
3774 """Test a FIT with a missing external blob that is allowed"""
3775 with test_util.capture_sys_output() as (stdout, stderr):
3776 self._DoTestFile('168_fit_missing_blob.dts',
3777 allow_missing=True)
3778 err = stderr.getvalue()
Simon Glassb2381432020-09-06 10:39:09 -06003779 self.assertRegex(err, "Image 'main-section'.*missing.*: atf-bl31")
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03003780
Simon Glass3decfa32020-09-01 05:13:54 -06003781 def testBlobNamedByArgMissing(self):
3782 """Test handling of a missing entry arg"""
3783 with self.assertRaises(ValueError) as e:
3784 self._DoReadFile('068_blob_named_by_arg.dts')
3785 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
3786 str(e.exception))
3787
Simon Glassdc2f81a2020-09-01 05:13:58 -06003788 def testPackBl31(self):
3789 """Test that an image with an ATF BL31 binary can be created"""
3790 data = self._DoReadFile('169_atf_bl31.dts')
3791 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
3792
Samuel Holland18bd4552020-10-21 21:12:15 -05003793 def testPackScp(self):
3794 """Test that an image with an SCP binary can be created"""
3795 data = self._DoReadFile('172_scp.dts')
3796 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
3797
Simon Glass6cf99532020-09-01 05:13:59 -06003798 def testFitFdt(self):
3799 """Test an image with an FIT with multiple FDT images"""
3800 def _CheckFdt(seq, expected_data):
3801 """Check the FDT nodes
3802
3803 Args:
3804 seq: Sequence number to check (0 or 1)
3805 expected_data: Expected contents of 'data' property
3806 """
3807 name = 'fdt-%d' % seq
3808 fnode = dtb.GetNode('/images/%s' % name)
3809 self.assertIsNotNone(fnode)
3810 self.assertEqual({'description','type', 'compression', 'data'},
3811 set(fnode.props.keys()))
3812 self.assertEqual(expected_data, fnode.props['data'].bytes)
3813 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
3814 fnode.props['description'].value)
3815
3816 def _CheckConfig(seq, expected_data):
3817 """Check the configuration nodes
3818
3819 Args:
3820 seq: Sequence number to check (0 or 1)
3821 expected_data: Expected contents of 'data' property
3822 """
3823 cnode = dtb.GetNode('/configurations')
3824 self.assertIn('default', cnode.props)
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003825 self.assertEqual('config-2', cnode.props['default'].value)
Simon Glass6cf99532020-09-01 05:13:59 -06003826
3827 name = 'config-%d' % seq
3828 fnode = dtb.GetNode('/configurations/%s' % name)
3829 self.assertIsNotNone(fnode)
3830 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
3831 set(fnode.props.keys()))
3832 self.assertEqual('conf-test-fdt%d.dtb' % seq,
3833 fnode.props['description'].value)
3834 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
3835
3836 entry_args = {
3837 'of-list': 'test-fdt1 test-fdt2',
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003838 'default-dt': 'test-fdt2',
Simon Glass6cf99532020-09-01 05:13:59 -06003839 }
3840 data = self._DoReadFileDtb(
Bin Mengaa75ce92021-05-10 20:23:32 +08003841 '170_fit_fdt.dts',
Simon Glass6cf99532020-09-01 05:13:59 -06003842 entry_args=entry_args,
3843 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3844 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3845 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3846
3847 dtb = fdt.Fdt.FromData(fit_data)
3848 dtb.Scan()
3849 fnode = dtb.GetNode('/images/kernel')
3850 self.assertIn('data', fnode.props)
3851
3852 # Check all the properties in fdt-1 and fdt-2
3853 _CheckFdt(1, TEST_FDT1_DATA)
3854 _CheckFdt(2, TEST_FDT2_DATA)
3855
3856 # Check configurations
3857 _CheckConfig(1, TEST_FDT1_DATA)
3858 _CheckConfig(2, TEST_FDT2_DATA)
3859
3860 def testFitFdtMissingList(self):
3861 """Test handling of a missing 'of-list' entry arg"""
3862 with self.assertRaises(ValueError) as e:
Bin Mengaa75ce92021-05-10 20:23:32 +08003863 self._DoReadFile('170_fit_fdt.dts')
Simon Glass6cf99532020-09-01 05:13:59 -06003864 self.assertIn("Generator node requires 'of-list' entry argument",
3865 str(e.exception))
3866
3867 def testFitFdtEmptyList(self):
3868 """Test handling of an empty 'of-list' entry arg"""
3869 entry_args = {
3870 'of-list': '',
3871 }
3872 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
3873
3874 def testFitFdtMissingProp(self):
3875 """Test handling of a missing 'fit,fdt-list' property"""
3876 with self.assertRaises(ValueError) as e:
3877 self._DoReadFile('171_fit_fdt_missing_prop.dts')
3878 self.assertIn("Generator node requires 'fit,fdt-list' property",
3879 str(e.exception))
Simon Glassdc2f81a2020-09-01 05:13:58 -06003880
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003881 def testFitFdtEmptyList(self):
3882 """Test handling of an empty 'of-list' entry arg"""
3883 entry_args = {
3884 'of-list': '',
3885 }
Bin Mengaa75ce92021-05-10 20:23:32 +08003886 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003887
3888 def testFitFdtMissing(self):
3889 """Test handling of a missing 'default-dt' entry arg"""
3890 entry_args = {
3891 'of-list': 'test-fdt1 test-fdt2',
3892 }
3893 with self.assertRaises(ValueError) as e:
3894 self._DoReadFileDtb(
Bin Mengaa75ce92021-05-10 20:23:32 +08003895 '170_fit_fdt.dts',
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003896 entry_args=entry_args,
3897 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3898 self.assertIn("Generated 'default' node requires default-dt entry argument",
3899 str(e.exception))
3900
3901 def testFitFdtNotInList(self):
3902 """Test handling of a default-dt that is not in the of-list"""
3903 entry_args = {
3904 'of-list': 'test-fdt1 test-fdt2',
3905 'default-dt': 'test-fdt3',
3906 }
3907 with self.assertRaises(ValueError) as e:
3908 self._DoReadFileDtb(
Bin Mengaa75ce92021-05-10 20:23:32 +08003909 '170_fit_fdt.dts',
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003910 entry_args=entry_args,
3911 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3912 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
3913 str(e.exception))
3914
Simon Glassb2381432020-09-06 10:39:09 -06003915 def testFitExtblobMissingHelp(self):
3916 """Test display of help messages when an external blob is missing"""
3917 control.missing_blob_help = control._ReadMissingBlobHelp()
3918 control.missing_blob_help['wibble'] = 'Wibble test'
3919 control.missing_blob_help['another'] = 'Another test'
3920 with test_util.capture_sys_output() as (stdout, stderr):
3921 self._DoTestFile('168_fit_missing_blob.dts',
3922 allow_missing=True)
3923 err = stderr.getvalue()
3924
3925 # We can get the tag from the name, the type or the missing-msg
3926 # property. Check all three.
3927 self.assertIn('You may need to build ARM Trusted', err)
3928 self.assertIn('Wibble test', err)
3929 self.assertIn('Another test', err)
3930
Simon Glass204aa782020-09-06 10:35:32 -06003931 def testMissingBlob(self):
3932 """Test handling of a blob containing a missing file"""
3933 with self.assertRaises(ValueError) as e:
3934 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
3935 self.assertIn("Filename 'missing' not found in input path",
3936 str(e.exception))
3937
Simon Glassfb91d562020-09-06 10:35:33 -06003938 def testEnvironment(self):
3939 """Test adding a U-Boot environment"""
3940 data = self._DoReadFile('174_env.dts')
3941 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3942 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3943 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3944 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
3945 env)
3946
3947 def testEnvironmentNoSize(self):
3948 """Test that a missing 'size' property is detected"""
3949 with self.assertRaises(ValueError) as e:
Simon Glassa4dfe3e2020-10-26 17:40:00 -06003950 self._DoTestFile('175_env_no_size.dts')
Simon Glassfb91d562020-09-06 10:35:33 -06003951 self.assertIn("'u-boot-env' entry must have a size property",
3952 str(e.exception))
3953
3954 def testEnvironmentTooSmall(self):
3955 """Test handling of an environment that does not fit"""
3956 with self.assertRaises(ValueError) as e:
Simon Glassa4dfe3e2020-10-26 17:40:00 -06003957 self._DoTestFile('176_env_too_small.dts')
Simon Glassfb91d562020-09-06 10:35:33 -06003958
3959 # checksum, start byte, environment with \0 terminator, final \0
3960 need = 4 + 1 + len(ENV_DATA) + 1 + 1
3961 short = need - 0x8
3962 self.assertIn("too small to hold data (need %#x more bytes)" % short,
3963 str(e.exception))
3964
Simon Glassf2c0dd82020-10-26 17:40:01 -06003965 def testSkipAtStart(self):
3966 """Test handling of skip-at-start section"""
3967 data = self._DoReadFile('177_skip_at_start.dts')
3968 self.assertEqual(U_BOOT_DATA, data)
3969
3970 image = control.images['image']
3971 entries = image.GetEntries()
3972 section = entries['section']
3973 self.assertEqual(0, section.offset)
3974 self.assertEqual(len(U_BOOT_DATA), section.size)
3975 self.assertEqual(U_BOOT_DATA, section.GetData())
3976
3977 entry = section.GetEntries()['u-boot']
3978 self.assertEqual(16, entry.offset)
3979 self.assertEqual(len(U_BOOT_DATA), entry.size)
3980 self.assertEqual(U_BOOT_DATA, entry.data)
3981
3982 def testSkipAtStartPad(self):
3983 """Test handling of skip-at-start section with padded entry"""
3984 data = self._DoReadFile('178_skip_at_start_pad.dts')
3985 before = tools.GetBytes(0, 8)
3986 after = tools.GetBytes(0, 4)
3987 all = before + U_BOOT_DATA + after
3988 self.assertEqual(all, data)
3989
3990 image = control.images['image']
3991 entries = image.GetEntries()
3992 section = entries['section']
3993 self.assertEqual(0, section.offset)
3994 self.assertEqual(len(all), section.size)
3995 self.assertEqual(all, section.GetData())
3996
3997 entry = section.GetEntries()['u-boot']
3998 self.assertEqual(16, entry.offset)
3999 self.assertEqual(len(all), entry.size)
4000 self.assertEqual(U_BOOT_DATA, entry.data)
4001
4002 def testSkipAtStartSectionPad(self):
4003 """Test handling of skip-at-start section with padding"""
4004 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
4005 before = tools.GetBytes(0, 8)
4006 after = tools.GetBytes(0, 4)
4007 all = before + U_BOOT_DATA + after
Simon Glassd1d3ad72020-10-26 17:40:13 -06004008 self.assertEqual(all, data)
Simon Glassf2c0dd82020-10-26 17:40:01 -06004009
4010 image = control.images['image']
4011 entries = image.GetEntries()
4012 section = entries['section']
4013 self.assertEqual(0, section.offset)
4014 self.assertEqual(len(all), section.size)
Simon Glass63e7ba62020-10-26 17:40:16 -06004015 self.assertEqual(U_BOOT_DATA, section.data)
Simon Glassd1d3ad72020-10-26 17:40:13 -06004016 self.assertEqual(all, section.GetPaddedData())
Simon Glassf2c0dd82020-10-26 17:40:01 -06004017
4018 entry = section.GetEntries()['u-boot']
4019 self.assertEqual(16, entry.offset)
4020 self.assertEqual(len(U_BOOT_DATA), entry.size)
4021 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassfb91d562020-09-06 10:35:33 -06004022
Simon Glass7d398bb2020-10-26 17:40:14 -06004023 def testSectionPad(self):
4024 """Testing padding with sections"""
4025 data = self._DoReadFile('180_section_pad.dts')
4026 expected = (tools.GetBytes(ord('&'), 3) +
4027 tools.GetBytes(ord('!'), 5) +
4028 U_BOOT_DATA +
4029 tools.GetBytes(ord('!'), 1) +
4030 tools.GetBytes(ord('&'), 2))
4031 self.assertEqual(expected, data)
4032
4033 def testSectionAlign(self):
4034 """Testing alignment with sections"""
4035 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4036 expected = (b'\0' + # fill section
4037 tools.GetBytes(ord('&'), 1) + # padding to section align
4038 b'\0' + # fill section
4039 tools.GetBytes(ord('!'), 3) + # padding to u-boot align
4040 U_BOOT_DATA +
4041 tools.GetBytes(ord('!'), 4) + # padding to u-boot size
4042 tools.GetBytes(ord('!'), 4)) # padding to section size
4043 self.assertEqual(expected, data)
4044
Simon Glass8f5ef892020-10-26 17:40:25 -06004045 def testCompressImage(self):
4046 """Test compression of the entire image"""
4047 self._CheckLz4()
4048 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4049 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4050 dtb = fdt.Fdt(out_dtb_fname)
4051 dtb.Scan()
4052 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4053 'uncomp-size'])
4054 orig = self._decompress(data)
4055 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4056
4057 # Do a sanity check on various fields
4058 image = control.images['image']
4059 entries = image.GetEntries()
4060 self.assertEqual(2, len(entries))
4061
4062 entry = entries['blob']
4063 self.assertEqual(COMPRESS_DATA, entry.data)
4064 self.assertEqual(len(COMPRESS_DATA), entry.size)
4065
4066 entry = entries['u-boot']
4067 self.assertEqual(U_BOOT_DATA, entry.data)
4068 self.assertEqual(len(U_BOOT_DATA), entry.size)
4069
4070 self.assertEqual(len(data), image.size)
4071 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4072 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4073 orig = self._decompress(image.data)
4074 self.assertEqual(orig, image.uncomp_data)
4075
4076 expected = {
4077 'blob:offset': 0,
4078 'blob:size': len(COMPRESS_DATA),
4079 'u-boot:offset': len(COMPRESS_DATA),
4080 'u-boot:size': len(U_BOOT_DATA),
4081 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4082 'offset': 0,
4083 'image-pos': 0,
4084 'size': len(data),
4085 }
4086 self.assertEqual(expected, props)
4087
4088 def testCompressImageLess(self):
4089 """Test compression where compression reduces the image size"""
4090 self._CheckLz4()
4091 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4092 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4093 dtb = fdt.Fdt(out_dtb_fname)
4094 dtb.Scan()
4095 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4096 'uncomp-size'])
4097 orig = self._decompress(data)
4098
4099 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
4100
4101 # Do a sanity check on various fields
4102 image = control.images['image']
4103 entries = image.GetEntries()
4104 self.assertEqual(2, len(entries))
4105
4106 entry = entries['blob']
4107 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4108 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4109
4110 entry = entries['u-boot']
4111 self.assertEqual(U_BOOT_DATA, entry.data)
4112 self.assertEqual(len(U_BOOT_DATA), entry.size)
4113
4114 self.assertEqual(len(data), image.size)
4115 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4116 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4117 image.uncomp_size)
4118 orig = self._decompress(image.data)
4119 self.assertEqual(orig, image.uncomp_data)
4120
4121 expected = {
4122 'blob:offset': 0,
4123 'blob:size': len(COMPRESS_DATA_BIG),
4124 'u-boot:offset': len(COMPRESS_DATA_BIG),
4125 'u-boot:size': len(U_BOOT_DATA),
4126 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4127 'offset': 0,
4128 'image-pos': 0,
4129 'size': len(data),
4130 }
4131 self.assertEqual(expected, props)
4132
4133 def testCompressSectionSize(self):
4134 """Test compression of a section with a fixed size"""
4135 self._CheckLz4()
4136 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4137 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4138 dtb = fdt.Fdt(out_dtb_fname)
4139 dtb.Scan()
4140 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4141 'uncomp-size'])
4142 orig = self._decompress(data)
4143 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4144 expected = {
4145 'section/blob:offset': 0,
4146 'section/blob:size': len(COMPRESS_DATA),
4147 'section/u-boot:offset': len(COMPRESS_DATA),
4148 'section/u-boot:size': len(U_BOOT_DATA),
4149 'section:offset': 0,
4150 'section:image-pos': 0,
4151 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4152 'section:size': 0x30,
4153 'offset': 0,
4154 'image-pos': 0,
4155 'size': 0x30,
4156 }
4157 self.assertEqual(expected, props)
4158
4159 def testCompressSection(self):
4160 """Test compression of a section with no fixed size"""
4161 self._CheckLz4()
4162 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4163 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4164 dtb = fdt.Fdt(out_dtb_fname)
4165 dtb.Scan()
4166 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4167 'uncomp-size'])
4168 orig = self._decompress(data)
4169 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4170 expected = {
4171 'section/blob:offset': 0,
4172 'section/blob:size': len(COMPRESS_DATA),
4173 'section/u-boot:offset': len(COMPRESS_DATA),
4174 'section/u-boot:size': len(U_BOOT_DATA),
4175 'section:offset': 0,
4176 'section:image-pos': 0,
4177 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4178 'section:size': len(data),
4179 'offset': 0,
4180 'image-pos': 0,
4181 'size': len(data),
4182 }
4183 self.assertEqual(expected, props)
4184
4185 def testCompressExtra(self):
4186 """Test compression of a section with no fixed size"""
4187 self._CheckLz4()
4188 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4189 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4190 dtb = fdt.Fdt(out_dtb_fname)
4191 dtb.Scan()
4192 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4193 'uncomp-size'])
4194
4195 base = data[len(U_BOOT_DATA):]
4196 self.assertEquals(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
4197 rest = base[len(U_BOOT_DATA):]
4198
4199 # Check compressed data
4200 section1 = self._decompress(rest)
4201 expect1 = tools.Compress(COMPRESS_DATA + U_BOOT_DATA, 'lz4')
4202 self.assertEquals(expect1, rest[:len(expect1)])
4203 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, section1)
4204 rest1 = rest[len(expect1):]
4205
4206 section2 = self._decompress(rest1)
4207 expect2 = tools.Compress(COMPRESS_DATA + COMPRESS_DATA, 'lz4')
4208 self.assertEquals(expect2, rest1[:len(expect2)])
4209 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA, section2)
4210 rest2 = rest1[len(expect2):]
4211
4212 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4213 len(expect2) + len(U_BOOT_DATA))
4214 #self.assertEquals(expect_size, len(data))
4215
4216 #self.assertEquals(U_BOOT_DATA, rest2)
4217
4218 self.maxDiff = None
4219 expected = {
4220 'u-boot:offset': 0,
4221 'u-boot:image-pos': 0,
4222 'u-boot:size': len(U_BOOT_DATA),
4223
4224 'base:offset': len(U_BOOT_DATA),
4225 'base:image-pos': len(U_BOOT_DATA),
4226 'base:size': len(data) - len(U_BOOT_DATA),
4227 'base/u-boot:offset': 0,
4228 'base/u-boot:image-pos': len(U_BOOT_DATA),
4229 'base/u-boot:size': len(U_BOOT_DATA),
4230 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4231 len(expect2),
4232 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4233 len(expect2),
4234 'base/u-boot2:size': len(U_BOOT_DATA),
4235
4236 'base/section:offset': len(U_BOOT_DATA),
4237 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4238 'base/section:size': len(expect1),
4239 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4240 'base/section/blob:offset': 0,
4241 'base/section/blob:size': len(COMPRESS_DATA),
4242 'base/section/u-boot:offset': len(COMPRESS_DATA),
4243 'base/section/u-boot:size': len(U_BOOT_DATA),
4244
4245 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4246 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4247 'base/section2:size': len(expect2),
4248 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4249 'base/section2/blob:offset': 0,
4250 'base/section2/blob:size': len(COMPRESS_DATA),
4251 'base/section2/blob2:offset': len(COMPRESS_DATA),
4252 'base/section2/blob2:size': len(COMPRESS_DATA),
4253
4254 'offset': 0,
4255 'image-pos': 0,
4256 'size': len(data),
4257 }
4258 self.assertEqual(expected, props)
4259
Simon Glass870a9ea2021-01-06 21:35:15 -07004260 def testSymbolsSubsection(self):
4261 """Test binman can assign symbols from a subsection"""
Simon Glassf5898822021-03-18 20:24:56 +13004262 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x18)
Simon Glass870a9ea2021-01-06 21:35:15 -07004263
Simon Glass939d1062021-01-06 21:35:16 -07004264 def testReadImageEntryArg(self):
4265 """Test reading an image that would need an entry arg to generate"""
4266 entry_args = {
4267 'cros-ec-rw-path': 'ecrw.bin',
4268 }
4269 data = self.data = self._DoReadFileDtb(
4270 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4271 entry_args=entry_args)
4272
4273 image_fname = tools.GetOutputFilename('image.bin')
4274 orig_image = control.images['image']
4275
4276 # This should not generate an error about the missing 'cros-ec-rw-path'
4277 # since we are reading the image from a file. Compare with
4278 # testEntryArgsRequired()
4279 image = Image.FromFile(image_fname)
4280 self.assertEqual(orig_image.GetEntries().keys(),
4281 image.GetEntries().keys())
4282
Simon Glass6eb99322021-01-06 21:35:18 -07004283 def testFilesAlign(self):
4284 """Test alignment with files"""
4285 data = self._DoReadFile('190_files_align.dts')
4286
4287 # The first string is 15 bytes so will align to 16
4288 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4289 self.assertEqual(expect, data)
4290
Simon Glass5c6ba712021-01-06 21:35:19 -07004291 def testReadImageSkip(self):
4292 """Test reading an image and accessing its FDT map"""
4293 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
4294 image_fname = tools.GetOutputFilename('image.bin')
4295 orig_image = control.images['image']
4296 image = Image.FromFile(image_fname)
4297 self.assertEqual(orig_image.GetEntries().keys(),
4298 image.GetEntries().keys())
4299
4300 orig_entry = orig_image.GetEntries()['fdtmap']
4301 entry = image.GetEntries()['fdtmap']
4302 self.assertEqual(orig_entry.offset, entry.offset)
4303 self.assertEqual(orig_entry.size, entry.size)
4304 self.assertEqual(16, entry.image_pos)
4305
4306 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4307
4308 self.assertEquals(U_BOOT_DATA, u_boot.ReadData())
4309
Simon Glass77a64e02021-03-18 20:24:57 +13004310 def testTplNoDtb(self):
4311 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
Simon Glass0fe44dc2021-04-25 08:39:32 +12004312 self._SetupTplElf()
Simon Glass77a64e02021-03-18 20:24:57 +13004313 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4314 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4315 data[:len(U_BOOT_TPL_NODTB_DATA)])
4316
Simon Glassd26efc82021-03-18 20:24:58 +13004317 def testTplBssPad(self):
4318 """Test that we can pad TPL's BSS with zeros"""
4319 # ELF file with a '__bss_size' symbol
4320 self._SetupTplElf()
4321 data = self._DoReadFile('193_tpl_bss_pad.dts')
4322 self.assertEqual(U_BOOT_TPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
4323 data)
4324
4325 def testTplBssPadMissing(self):
4326 """Test that a missing symbol is detected"""
4327 self._SetupTplElf('u_boot_ucode_ptr')
4328 with self.assertRaises(ValueError) as e:
4329 self._DoReadFile('193_tpl_bss_pad.dts')
4330 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4331 str(e.exception))
4332
Simon Glass06684922021-03-18 20:25:07 +13004333 def checkDtbSizes(self, data, pad_len, start):
4334 """Check the size arguments in a dtb embedded in an image
4335
4336 Args:
4337 data: The image data
4338 pad_len: Length of the pad section in the image, in bytes
4339 start: Start offset of the devicetree to examine, within the image
4340
4341 Returns:
4342 Size of the devicetree in bytes
4343 """
4344 dtb_data = data[start:]
4345 dtb = fdt.Fdt.FromData(dtb_data)
4346 fdt_size = dtb.GetFdtObj().totalsize()
4347 dtb.Scan()
4348 props = self._GetPropTree(dtb, 'size')
4349 self.assertEqual({
4350 'size': len(data),
4351 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4352 'u-boot-spl/u-boot-spl-dtb:size': 801,
4353 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4354 'u-boot-spl:size': 860,
4355 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4356 'u-boot/u-boot-dtb:size': 781,
4357 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4358 'u-boot:size': 827,
4359 }, props)
4360 return fdt_size
4361
4362 def testExpanded(self):
4363 """Test that an expanded entry type is selected when needed"""
4364 self._SetupSplElf()
4365 self._SetupTplElf()
4366
4367 # SPL has a devicetree, TPL does not
4368 entry_args = {
4369 'spl-dtb': '1',
4370 'spl-bss-pad': 'y',
4371 'tpl-dtb': '',
4372 }
4373 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4374 entry_args=entry_args)
4375 image = control.images['image']
4376 entries = image.GetEntries()
4377 self.assertEqual(3, len(entries))
4378
4379 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4380 self.assertIn('u-boot', entries)
4381 entry = entries['u-boot']
4382 self.assertEqual('u-boot-expanded', entry.etype)
4383 subent = entry.GetEntries()
4384 self.assertEqual(2, len(subent))
4385 self.assertIn('u-boot-nodtb', subent)
4386 self.assertIn('u-boot-dtb', subent)
4387
4388 # Second, u-boot-spl, which should be expanded into three parts
4389 self.assertIn('u-boot-spl', entries)
4390 entry = entries['u-boot-spl']
4391 self.assertEqual('u-boot-spl-expanded', entry.etype)
4392 subent = entry.GetEntries()
4393 self.assertEqual(3, len(subent))
4394 self.assertIn('u-boot-spl-nodtb', subent)
4395 self.assertIn('u-boot-spl-bss-pad', subent)
4396 self.assertIn('u-boot-spl-dtb', subent)
4397
4398 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4399 # devicetree
4400 self.assertIn('u-boot-tpl', entries)
4401 entry = entries['u-boot-tpl']
4402 self.assertEqual('u-boot-tpl', entry.etype)
4403 self.assertEqual(None, entry.GetEntries())
4404
4405 def testExpandedTpl(self):
4406 """Test that an expanded entry type is selected for TPL when needed"""
4407 self._SetupTplElf()
4408
4409 entry_args = {
4410 'tpl-bss-pad': 'y',
4411 'tpl-dtb': 'y',
4412 }
4413 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4414 entry_args=entry_args)
4415 image = control.images['image']
4416 entries = image.GetEntries()
4417 self.assertEqual(1, len(entries))
4418
4419 # We only have u-boot-tpl, which be expanded
4420 self.assertIn('u-boot-tpl', entries)
4421 entry = entries['u-boot-tpl']
4422 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4423 subent = entry.GetEntries()
4424 self.assertEqual(3, len(subent))
4425 self.assertIn('u-boot-tpl-nodtb', subent)
4426 self.assertIn('u-boot-tpl-bss-pad', subent)
4427 self.assertIn('u-boot-tpl-dtb', subent)
4428
4429 def testExpandedNoPad(self):
4430 """Test an expanded entry without BSS pad enabled"""
4431 self._SetupSplElf()
4432 self._SetupTplElf()
4433
4434 # SPL has a devicetree, TPL does not
4435 entry_args = {
4436 'spl-dtb': 'something',
4437 'spl-bss-pad': 'n',
4438 'tpl-dtb': '',
4439 }
4440 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4441 entry_args=entry_args)
4442 image = control.images['image']
4443 entries = image.GetEntries()
4444
4445 # Just check u-boot-spl, which should be expanded into two parts
4446 self.assertIn('u-boot-spl', entries)
4447 entry = entries['u-boot-spl']
4448 self.assertEqual('u-boot-spl-expanded', entry.etype)
4449 subent = entry.GetEntries()
4450 self.assertEqual(2, len(subent))
4451 self.assertIn('u-boot-spl-nodtb', subent)
4452 self.assertIn('u-boot-spl-dtb', subent)
4453
4454 def testExpandedTplNoPad(self):
4455 """Test that an expanded entry type with padding disabled in TPL"""
4456 self._SetupTplElf()
4457
4458 entry_args = {
4459 'tpl-bss-pad': '',
4460 'tpl-dtb': 'y',
4461 }
4462 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4463 entry_args=entry_args)
4464 image = control.images['image']
4465 entries = image.GetEntries()
4466 self.assertEqual(1, len(entries))
4467
4468 # We only have u-boot-tpl, which be expanded
4469 self.assertIn('u-boot-tpl', entries)
4470 entry = entries['u-boot-tpl']
4471 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4472 subent = entry.GetEntries()
4473 self.assertEqual(2, len(subent))
4474 self.assertIn('u-boot-tpl-nodtb', subent)
4475 self.assertIn('u-boot-tpl-dtb', subent)
4476
4477 def testFdtInclude(self):
4478 """Test that an Fdt is update within all binaries"""
4479 self._SetupSplElf()
4480 self._SetupTplElf()
4481
4482 # SPL has a devicetree, TPL does not
4483 self.maxDiff = None
4484 entry_args = {
4485 'spl-dtb': '1',
4486 'spl-bss-pad': 'y',
4487 'tpl-dtb': '',
4488 }
4489 # Build the image. It includes two separate devicetree binaries, each
4490 # with their own contents, but all contain the binman definition.
4491 data = self._DoReadFileDtb(
4492 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4493 update_dtb=True, entry_args=entry_args)[0]
4494 pad_len = 10
4495
4496 # Check the U-Boot dtb
4497 start = len(U_BOOT_NODTB_DATA)
4498 fdt_size = self.checkDtbSizes(data, pad_len, start)
4499
4500 # Now check SPL
4501 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4502 fdt_size = self.checkDtbSizes(data, pad_len, start)
4503
4504 # TPL has no devicetree
4505 start += fdt_size + len(U_BOOT_TPL_DATA)
4506 self.assertEqual(len(data), start)
Simon Glass7d398bb2020-10-26 17:40:14 -06004507
Simon Glass3d433382021-03-21 18:24:30 +13004508 def testSymbolsExpanded(self):
4509 """Test binman can assign symbols in expanded entries"""
4510 entry_args = {
4511 'spl-dtb': '1',
4512 }
4513 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4514 U_BOOT_SPL_DTB_DATA, 0x38,
4515 entry_args=entry_args, use_expanded=True)
4516
Simon Glass189f2912021-03-21 18:24:31 +13004517 def testCollection(self):
4518 """Test a collection"""
4519 data = self._DoReadFile('198_collection.dts')
4520 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
4521 tools.GetBytes(0xff, 2) + U_BOOT_NODTB_DATA +
4522 tools.GetBytes(0xfe, 3) + U_BOOT_DTB_DATA,
4523 data)
4524
Simon Glass631f7522021-03-21 18:24:32 +13004525 def testCollectionSection(self):
4526 """Test a collection where a section must be built first"""
4527 # Sections never have their contents when GetData() is called, but when
4528 # _BuildSectionData() is called with required=True, a section will force
4529 # building the contents, producing an error is anything is still
4530 # missing.
4531 data = self._DoReadFile('199_collection_section.dts')
4532 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
4533 self.assertEqual(section + U_BOOT_DATA + tools.GetBytes(0xff, 2) +
4534 section + tools.GetBytes(0xfe, 3) + U_BOOT_DATA,
4535 data)
4536
Simon Glass5ff9fed2021-03-21 18:24:33 +13004537 def testAlignDefault(self):
4538 """Test that default alignment works on sections"""
4539 data = self._DoReadFile('200_align_default.dts')
4540 expected = (U_BOOT_DATA + tools.GetBytes(0, 8 - len(U_BOOT_DATA)) +
4541 U_BOOT_DATA)
4542 # Special alignment for section
4543 expected += tools.GetBytes(0, 32 - len(expected))
4544 # No alignment within the nested section
4545 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
4546 # Now the final piece, which should be default-aligned
4547 expected += tools.GetBytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
4548 self.assertEqual(expected, data)
Simon Glass631f7522021-03-21 18:24:32 +13004549
Bin Meng4c4d6072021-05-10 20:23:33 +08004550 def testPackOpenSBI(self):
4551 """Test that an image with an OpenSBI binary can be created"""
4552 data = self._DoReadFile('201_opensbi.dts')
4553 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
4554
Simon Glassc69d19c2021-07-06 10:36:37 -06004555 def testSectionsSingleThread(self):
4556 """Test sections without multithreading"""
4557 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
4558 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
4559 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
4560 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
4561 self.assertEqual(expected, data)
4562
4563 def testThreadTimeout(self):
4564 """Test handling a thread that takes too long"""
4565 with self.assertRaises(ValueError) as e:
4566 self._DoTestFile('202_section_timeout.dts',
4567 test_section_timeout=True)
4568 self.assertIn("Node '/binman/section@0': Timed out obtaining contents",
4569 str(e.exception))
4570
Simon Glass03ebc202021-07-06 10:36:41 -06004571 def testTiming(self):
4572 """Test output of timing information"""
4573 data = self._DoReadFile('055_sections.dts')
4574 with test_util.capture_sys_output() as (stdout, stderr):
4575 state.TimingShow()
4576 self.assertIn('read:', stdout.getvalue())
4577 self.assertIn('compress:', stdout.getvalue())
4578
Simon Glassc69d19c2021-07-06 10:36:37 -06004579
Simon Glass9fc60b42017-11-12 21:52:22 -07004580if __name__ == "__main__":
4581 unittest.main()