blob: ceeee1dfe632be8afa70bd7961297acff16adb3d [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001# SPDX-License-Identifier: GPL-2.0+
Simon Glass4f443042016-11-25 20:15:52 -07002# Copyright (c) 2016 Google, Inc
3# Written by Simon Glass <sjg@chromium.org>
4#
Simon Glass4f443042016-11-25 20:15:52 -07005# To run a single test, change to this directory, and:
6#
7# python -m unittest func_test.TestFunctional.testHelp
8
Simon Glassfdc34362020-07-09 18:39:45 -06009import collections
Simon Glass16287932020-04-17 18:09:03 -060010import gzip
Simon Glasse0e5df92018-09-14 04:57:31 -060011import hashlib
Simon Glass4f443042016-11-25 20:15:52 -070012from optparse import OptionParser
13import os
Simon Glassfdc34362020-07-09 18:39:45 -060014import re
Simon Glass4f443042016-11-25 20:15:52 -070015import shutil
16import struct
17import sys
18import tempfile
19import unittest
20
Simon Glass16287932020-04-17 18:09:03 -060021from binman import cbfs_util
22from binman import cmdline
23from binman import control
24from binman import elf
25from binman import elf_test
26from binman import fmap_util
Simon Glass16287932020-04-17 18:09:03 -060027from binman import state
28from dtoc import fdt
29from dtoc import fdt_util
30from binman.etype import fdtmap
31from binman.etype import image_header
Simon Glass07237982020-08-05 13:27:47 -060032from binman.image import Image
Simon Glassbf776672020-04-17 18:09:04 -060033from patman import command
34from patman import test_util
35from patman import tools
36from patman import tout
Simon Glass4f443042016-11-25 20:15:52 -070037
38# Contents of test files, corresponding to different entry types
Simon Glassc6c10e72019-05-17 22:00:46 -060039U_BOOT_DATA = b'1234'
40U_BOOT_IMG_DATA = b'img'
Simon Glasseb0086f2019-08-24 07:23:04 -060041U_BOOT_SPL_DATA = b'56780123456789abcdefghi'
42U_BOOT_TPL_DATA = b'tpl9876543210fedcbazyw'
Simon Glassc6c10e72019-05-17 22:00:46 -060043BLOB_DATA = b'89'
44ME_DATA = b'0abcd'
45VGA_DATA = b'vga'
46U_BOOT_DTB_DATA = b'udtb'
47U_BOOT_SPL_DTB_DATA = b'spldtb'
48U_BOOT_TPL_DTB_DATA = b'tpldtb'
49X86_START16_DATA = b'start16'
50X86_START16_SPL_DATA = b'start16spl'
51X86_START16_TPL_DATA = b'start16tpl'
Simon Glass2250ee62019-08-24 07:22:48 -060052X86_RESET16_DATA = b'reset16'
53X86_RESET16_SPL_DATA = b'reset16spl'
54X86_RESET16_TPL_DATA = b'reset16tpl'
Simon Glassc6c10e72019-05-17 22:00:46 -060055PPC_MPC85XX_BR_DATA = b'ppcmpc85xxbr'
56U_BOOT_NODTB_DATA = b'nodtb with microcode pointer somewhere in here'
57U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here'
58U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here'
59FSP_DATA = b'fsp'
60CMC_DATA = b'cmc'
61VBT_DATA = b'vbt'
62MRC_DATA = b'mrc'
Simon Glassbb748372018-07-17 13:25:33 -060063TEXT_DATA = 'text'
64TEXT_DATA2 = 'text2'
65TEXT_DATA3 = 'text3'
Simon Glassc6c10e72019-05-17 22:00:46 -060066CROS_EC_RW_DATA = b'ecrw'
67GBB_DATA = b'gbbd'
68BMPBLK_DATA = b'bmp'
69VBLOCK_DATA = b'vblk'
70FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
71 b"sorry you're alive\n")
Simon Glassff5c7e32019-07-08 13:18:42 -060072COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
Simon Glassc6c10e72019-05-17 22:00:46 -060073REFCODE_DATA = b'refcode'
Simon Glassea0fff92019-08-24 07:23:07 -060074FSP_M_DATA = b'fsp_m'
Simon Glassbc6a88f2019-10-20 21:31:35 -060075FSP_S_DATA = b'fsp_s'
Simon Glass998d1482019-10-20 21:31:36 -060076FSP_T_DATA = b'fsp_t'
Simon Glassec127af2018-07-17 13:25:39 -060077
Simon Glass6ccbfcd2019-07-20 12:23:47 -060078# The expected size for the device tree in some tests
Simon Glassf667e452019-07-08 14:25:50 -060079EXTRACT_DTB_SIZE = 0x3c9
80
Simon Glass6ccbfcd2019-07-20 12:23:47 -060081# Properties expected to be in the device tree when update_dtb is used
82BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
83
Simon Glass12bb1a92019-07-20 12:23:51 -060084# Extra properties expected to be in the device tree when allow-repack is used
85REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
86
Simon Glass4f443042016-11-25 20:15:52 -070087
88class TestFunctional(unittest.TestCase):
89 """Functional tests for binman
90
91 Most of these use a sample .dts file to build an image and then check
92 that it looks correct. The sample files are in the test/ subdirectory
93 and are numbered.
94
95 For each entry type a very small test file is created using fixed
96 string contents. This makes it easy to test that things look right, and
97 debug problems.
98
99 In some cases a 'real' file must be used - these are also supplied in
100 the test/ diurectory.
101 """
102 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600103 def setUpClass(cls):
Simon Glass4d5994f2017-11-12 21:52:20 -0700104 global entry
Simon Glass16287932020-04-17 18:09:03 -0600105 from binman import entry
Simon Glass4d5994f2017-11-12 21:52:20 -0700106
Simon Glass4f443042016-11-25 20:15:52 -0700107 # Handle the case where argv[0] is 'python'
Simon Glassb986b3b2019-08-24 07:22:43 -0600108 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
109 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
Simon Glass4f443042016-11-25 20:15:52 -0700110
111 # Create a temporary directory for input files
Simon Glassb986b3b2019-08-24 07:22:43 -0600112 cls._indir = tempfile.mkdtemp(prefix='binmant.')
Simon Glass4f443042016-11-25 20:15:52 -0700113
114 # Create some test files
115 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
116 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
117 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glassb8ef5b62018-07-17 13:25:48 -0600118 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700119 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -0700120 TestFunctional._MakeInputFile('me.bin', ME_DATA)
121 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glassb986b3b2019-08-24 07:22:43 -0600122 cls._ResetDtbs()
Simon Glass2250ee62019-08-24 07:22:48 -0600123
Jagdish Gediya9d368f32018-09-03 21:35:08 +0530124 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glass2250ee62019-08-24 07:22:48 -0600125
Simon Glass5e239182019-08-24 07:22:49 -0600126 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
127 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
Simon Glass87722132017-11-12 21:52:26 -0700128 X86_START16_SPL_DATA)
Simon Glass5e239182019-08-24 07:22:49 -0600129 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
Simon Glass35b384c2018-09-14 04:57:10 -0600130 X86_START16_TPL_DATA)
Simon Glass2250ee62019-08-24 07:22:48 -0600131
132 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
133 X86_RESET16_DATA)
134 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
135 X86_RESET16_SPL_DATA)
136 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
137 X86_RESET16_TPL_DATA)
138
Simon Glass4f443042016-11-25 20:15:52 -0700139 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass6b187df2017-11-12 21:52:27 -0700140 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
141 U_BOOT_SPL_NODTB_DATA)
Simon Glassf0253632018-09-14 04:57:32 -0600142 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
143 U_BOOT_TPL_NODTB_DATA)
Simon Glassda229092016-11-25 20:15:56 -0700144 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
145 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Meng59ea8c22017-08-15 22:41:54 -0700146 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassca4f4ff2017-11-12 21:52:28 -0700147 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassec127af2018-07-17 13:25:39 -0600148 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glass0ef87aa2018-07-17 13:25:44 -0600149 TestFunctional._MakeInputDir('devkeys')
150 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass3ae192c2018-10-01 12:22:31 -0600151 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glassea0fff92019-08-24 07:23:07 -0600152 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
Simon Glassbc6a88f2019-10-20 21:31:35 -0600153 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
Simon Glass998d1482019-10-20 21:31:36 -0600154 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700155
Simon Glass53e22bf2019-08-24 07:22:53 -0600156 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
157 elf_test.BuildElfTestFiles(cls._elf_testdir)
158
Simon Glasse0ff8552016-11-25 20:15:53 -0700159 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glassf514d8f2019-08-24 07:22:54 -0600160 TestFunctional._MakeInputFile('u-boot',
161 tools.ReadFile(cls.ElfTestFile('u_boot_ucode_ptr')))
Simon Glasse0ff8552016-11-25 20:15:53 -0700162
163 # Intel flash descriptor file
Simon Glass0ba4b3d2020-07-09 18:39:41 -0600164 cls._SetupDescriptor()
Simon Glasse0ff8552016-11-25 20:15:53 -0700165
Simon Glassb986b3b2019-08-24 07:22:43 -0600166 shutil.copytree(cls.TestFile('files'),
167 os.path.join(cls._indir, 'files'))
Simon Glass0a98b282018-09-14 04:57:28 -0600168
Simon Glass83d73c22018-09-14 04:57:26 -0600169 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
170
Simon Glassac62fba2019-07-08 13:18:53 -0600171 # Travis-CI may have an old lz4
Simon Glassb986b3b2019-08-24 07:22:43 -0600172 cls.have_lz4 = True
Simon Glassac62fba2019-07-08 13:18:53 -0600173 try:
174 tools.Run('lz4', '--no-frame-crc', '-c',
Simon Glass3b3e3c02019-10-31 07:42:50 -0600175 os.path.join(cls._indir, 'u-boot.bin'), binary=True)
Simon Glassac62fba2019-07-08 13:18:53 -0600176 except:
Simon Glassb986b3b2019-08-24 07:22:43 -0600177 cls.have_lz4 = False
Simon Glassac62fba2019-07-08 13:18:53 -0600178
Simon Glass4f443042016-11-25 20:15:52 -0700179 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600180 def tearDownClass(cls):
Simon Glass4f443042016-11-25 20:15:52 -0700181 """Remove the temporary input directory and its contents"""
Simon Glassb986b3b2019-08-24 07:22:43 -0600182 if cls.preserve_indir:
183 print('Preserving input dir: %s' % cls._indir)
Simon Glassd5164a72019-07-08 13:18:49 -0600184 else:
Simon Glassb986b3b2019-08-24 07:22:43 -0600185 if cls._indir:
186 shutil.rmtree(cls._indir)
187 cls._indir = None
Simon Glass4f443042016-11-25 20:15:52 -0700188
Simon Glassd5164a72019-07-08 13:18:49 -0600189 @classmethod
Simon Glass8acce602019-07-08 13:18:50 -0600190 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
Simon Glass53cd5d92019-07-08 14:25:29 -0600191 toolpath=None, verbosity=None):
Simon Glassd5164a72019-07-08 13:18:49 -0600192 """Accept arguments controlling test execution
193
194 Args:
195 preserve_indir: Preserve the shared input directory used by all
196 tests in this class.
197 preserve_outdir: Preserve the output directories used by tests. Each
198 test has its own, so this is normally only useful when running a
199 single test.
Simon Glass8acce602019-07-08 13:18:50 -0600200 toolpath: ist of paths to use for tools
Simon Glassd5164a72019-07-08 13:18:49 -0600201 """
202 cls.preserve_indir = preserve_indir
203 cls.preserve_outdirs = preserve_outdirs
Simon Glass8acce602019-07-08 13:18:50 -0600204 cls.toolpath = toolpath
Simon Glass53cd5d92019-07-08 14:25:29 -0600205 cls.verbosity = verbosity
Simon Glassd5164a72019-07-08 13:18:49 -0600206
Simon Glassac62fba2019-07-08 13:18:53 -0600207 def _CheckLz4(self):
208 if not self.have_lz4:
209 self.skipTest('lz4 --no-frame-crc not available')
210
Simon Glassbf574f12019-07-20 12:24:09 -0600211 def _CleanupOutputDir(self):
212 """Remove the temporary output directory"""
213 if self.preserve_outdirs:
214 print('Preserving output dir: %s' % tools.outdir)
215 else:
216 tools._FinaliseForTest()
217
Simon Glass4f443042016-11-25 20:15:52 -0700218 def setUp(self):
219 # Enable this to turn on debugging output
220 # tout.Init(tout.DEBUG)
221 command.test_result = None
222
223 def tearDown(self):
224 """Remove the temporary output directory"""
Simon Glassbf574f12019-07-20 12:24:09 -0600225 self._CleanupOutputDir()
Simon Glass4f443042016-11-25 20:15:52 -0700226
Simon Glassf86a7362019-07-20 12:24:10 -0600227 def _SetupImageInTmpdir(self):
228 """Set up the output image in a new temporary directory
229
230 This is used when an image has been generated in the output directory,
231 but we want to run binman again. This will create a new output
232 directory and fail to delete the original one.
233
234 This creates a new temporary directory, copies the image to it (with a
235 new name) and removes the old output directory.
236
237 Returns:
238 Tuple:
239 Temporary directory to use
240 New image filename
241 """
242 image_fname = tools.GetOutputFilename('image.bin')
243 tmpdir = tempfile.mkdtemp(prefix='binman.')
244 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
245 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
246 self._CleanupOutputDir()
247 return tmpdir, updated_fname
248
Simon Glassb8ef5b62018-07-17 13:25:48 -0600249 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600250 def _ResetDtbs(cls):
Simon Glassb8ef5b62018-07-17 13:25:48 -0600251 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
252 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
253 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
254
Simon Glass4f443042016-11-25 20:15:52 -0700255 def _RunBinman(self, *args, **kwargs):
256 """Run binman using the command line
257
258 Args:
259 Arguments to pass, as a list of strings
260 kwargs: Arguments to pass to Command.RunPipe()
261 """
262 result = command.RunPipe([[self._binman_pathname] + list(args)],
263 capture=True, capture_stderr=True, raise_on_error=False)
264 if result.return_code and kwargs.get('raise_on_error', True):
265 raise Exception("Error running '%s': %s" % (' '.join(args),
266 result.stdout + result.stderr))
267 return result
268
Simon Glass53cd5d92019-07-08 14:25:29 -0600269 def _DoBinman(self, *argv):
Simon Glass4f443042016-11-25 20:15:52 -0700270 """Run binman using directly (in the same process)
271
272 Args:
273 Arguments to pass, as a list of strings
274 Returns:
275 Return value (0 for success)
276 """
Simon Glass53cd5d92019-07-08 14:25:29 -0600277 argv = list(argv)
278 args = cmdline.ParseArgs(argv)
279 args.pager = 'binman-invalid-pager'
280 args.build_dir = self._indir
Simon Glass4f443042016-11-25 20:15:52 -0700281
282 # For testing, you can force an increase in verbosity here
Simon Glass53cd5d92019-07-08 14:25:29 -0600283 # args.verbosity = tout.DEBUG
284 return control.Binman(args)
Simon Glass4f443042016-11-25 20:15:52 -0700285
Simon Glass53af22a2018-07-17 13:25:32 -0600286 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glasseb833d82019-04-25 21:58:34 -0600287 entry_args=None, images=None, use_real_dtb=False,
Simon Glass4f9f1052020-07-09 18:39:38 -0600288 verbosity=None, allow_missing=False):
Simon Glass4f443042016-11-25 20:15:52 -0700289 """Run binman with a given test file
290
291 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600292 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600293 debug: True to enable debugging output
Simon Glass3b0c38212018-06-01 09:38:20 -0600294 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600295 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600296 tree before packing it into the image
Simon Glass0bfa7b02018-09-14 04:57:12 -0600297 entry_args: Dict of entry args to supply to binman
298 key: arg name
299 value: value of that arg
300 images: List of image names to build
Simon Glasse9d336d2020-09-01 05:13:55 -0600301 use_real_dtb: True to use the test file as the contents of
302 the u-boot-dtb entry. Normally this is not needed and the
303 test contents (the U_BOOT_DTB_DATA string) can be used.
304 But in some test we need the real contents.
305 verbosity: Verbosity level to use (0-3, None=don't set it)
306 allow_missing: Set the '--allow-missing' flag so that missing
307 external binaries just produce a warning instead of an error
Simon Glass4f443042016-11-25 20:15:52 -0700308 """
Simon Glass53cd5d92019-07-08 14:25:29 -0600309 args = []
Simon Glass7fe91732017-11-13 18:55:00 -0700310 if debug:
311 args.append('-D')
Simon Glass53cd5d92019-07-08 14:25:29 -0600312 if verbosity is not None:
313 args.append('-v%d' % verbosity)
314 elif self.verbosity:
315 args.append('-v%d' % self.verbosity)
316 if self.toolpath:
317 for path in self.toolpath:
318 args += ['--toolpath', path]
319 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass3b0c38212018-06-01 09:38:20 -0600320 if map:
321 args.append('-m')
Simon Glass16b8d6b2018-07-06 10:27:42 -0600322 if update_dtb:
Simon Glass2569e102019-07-08 13:18:47 -0600323 args.append('-u')
Simon Glass93d17412018-09-14 04:57:23 -0600324 if not use_real_dtb:
325 args.append('--fake-dtb')
Simon Glass53af22a2018-07-17 13:25:32 -0600326 if entry_args:
Simon Glass50979152019-05-14 15:53:41 -0600327 for arg, value in entry_args.items():
Simon Glass53af22a2018-07-17 13:25:32 -0600328 args.append('-a%s=%s' % (arg, value))
Simon Glass4f9f1052020-07-09 18:39:38 -0600329 if allow_missing:
330 args.append('-M')
Simon Glass0bfa7b02018-09-14 04:57:12 -0600331 if images:
332 for image in images:
333 args += ['-i', image]
Simon Glass7fe91732017-11-13 18:55:00 -0700334 return self._DoBinman(*args)
Simon Glass4f443042016-11-25 20:15:52 -0700335
336 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glasse0ff8552016-11-25 20:15:53 -0700337 """Set up a new test device-tree file
338
339 The given file is compiled and set up as the device tree to be used
340 for ths test.
341
342 Args:
343 fname: Filename of .dts file to read
Simon Glass7ae5f312018-06-01 09:38:19 -0600344 outfile: Output filename for compiled device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700345
346 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600347 Contents of device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700348 """
Simon Glassa004f292019-07-20 12:23:49 -0600349 tmpdir = tempfile.mkdtemp(prefix='binmant.')
350 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
Simon Glass1d0ebf72019-05-14 15:53:42 -0600351 with open(dtb, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700352 data = fd.read()
353 TestFunctional._MakeInputFile(outfile, data)
Simon Glassa004f292019-07-20 12:23:49 -0600354 shutil.rmtree(tmpdir)
Simon Glasse0e62752018-10-01 21:12:41 -0600355 return data
Simon Glass4f443042016-11-25 20:15:52 -0700356
Simon Glass6ed45ba2018-09-14 04:57:24 -0600357 def _GetDtbContentsForSplTpl(self, dtb_data, name):
358 """Create a version of the main DTB for SPL or SPL
359
360 For testing we don't actually have different versions of the DTB. With
361 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
362 we don't normally have any unwanted nodes.
363
364 We still want the DTBs for SPL and TPL to be different though, since
365 otherwise it is confusing to know which one we are looking at. So add
366 an 'spl' or 'tpl' property to the top-level node.
Simon Glasse9d336d2020-09-01 05:13:55 -0600367
368 Args:
369 dtb_data: dtb data to modify (this should be a value devicetree)
370 name: Name of a new property to add
371
372 Returns:
373 New dtb data with the property added
Simon Glass6ed45ba2018-09-14 04:57:24 -0600374 """
375 dtb = fdt.Fdt.FromData(dtb_data)
376 dtb.Scan()
377 dtb.GetNode('/binman').AddZeroProp(name)
378 dtb.Sync(auto_resize=True)
379 dtb.Pack()
380 return dtb.GetContents()
381
Simon Glass16b8d6b2018-07-06 10:27:42 -0600382 def _DoReadFileDtb(self, fname, use_real_dtb=False, map=False,
Simon Glass6ed45ba2018-09-14 04:57:24 -0600383 update_dtb=False, entry_args=None, reset_dtbs=True):
Simon Glass4f443042016-11-25 20:15:52 -0700384 """Run binman and return the resulting image
385
386 This runs binman with a given test file and then reads the resulting
387 output file. It is a shortcut function since most tests need to do
388 these steps.
389
390 Raises an assertion failure if binman returns a non-zero exit code.
391
392 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600393 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass4f443042016-11-25 20:15:52 -0700394 use_real_dtb: True to use the test file as the contents of
395 the u-boot-dtb entry. Normally this is not needed and the
396 test contents (the U_BOOT_DTB_DATA string) can be used.
397 But in some test we need the real contents.
Simon Glass3b0c38212018-06-01 09:38:20 -0600398 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600399 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600400 tree before packing it into the image
Simon Glasse9d336d2020-09-01 05:13:55 -0600401 entry_args: Dict of entry args to supply to binman
402 key: arg name
403 value: value of that arg
404 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
405 function. If reset_dtbs is True, then the original test dtb
406 is written back before this function finishes
Simon Glasse0ff8552016-11-25 20:15:53 -0700407
408 Returns:
409 Tuple:
410 Resulting image contents
411 Device tree contents
Simon Glass3b0c38212018-06-01 09:38:20 -0600412 Map data showing contents of image (or None if none)
Simon Glassea6922e2018-07-17 13:25:27 -0600413 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass4f443042016-11-25 20:15:52 -0700414 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700415 dtb_data = None
Simon Glass4f443042016-11-25 20:15:52 -0700416 # Use the compiled test file as the u-boot-dtb input
417 if use_real_dtb:
Simon Glasse0ff8552016-11-25 20:15:53 -0700418 dtb_data = self._SetupDtb(fname)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600419
420 # For testing purposes, make a copy of the DT for SPL and TPL. Add
421 # a node indicating which it is, so aid verification.
422 for name in ['spl', 'tpl']:
423 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
424 outfile = os.path.join(self._indir, dtb_fname)
425 TestFunctional._MakeInputFile(dtb_fname,
426 self._GetDtbContentsForSplTpl(dtb_data, name))
Simon Glass4f443042016-11-25 20:15:52 -0700427
428 try:
Simon Glass53af22a2018-07-17 13:25:32 -0600429 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glass6ed45ba2018-09-14 04:57:24 -0600430 entry_args=entry_args, use_real_dtb=use_real_dtb)
Simon Glass4f443042016-11-25 20:15:52 -0700431 self.assertEqual(0, retcode)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600432 out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
Simon Glass4f443042016-11-25 20:15:52 -0700433
434 # Find the (only) image, read it and return its contents
435 image = control.images['image']
Simon Glass16b8d6b2018-07-06 10:27:42 -0600436 image_fname = tools.GetOutputFilename('image.bin')
437 self.assertTrue(os.path.exists(image_fname))
Simon Glass3b0c38212018-06-01 09:38:20 -0600438 if map:
439 map_fname = tools.GetOutputFilename('image.map')
440 with open(map_fname) as fd:
441 map_data = fd.read()
442 else:
443 map_data = None
Simon Glass1d0ebf72019-05-14 15:53:42 -0600444 with open(image_fname, 'rb') as fd:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600445 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass4f443042016-11-25 20:15:52 -0700446 finally:
447 # Put the test file back
Simon Glass6ed45ba2018-09-14 04:57:24 -0600448 if reset_dtbs and use_real_dtb:
Simon Glassb8ef5b62018-07-17 13:25:48 -0600449 self._ResetDtbs()
Simon Glass4f443042016-11-25 20:15:52 -0700450
Simon Glass3c081312019-07-08 14:25:26 -0600451 def _DoReadFileRealDtb(self, fname):
452 """Run binman with a real .dtb file and return the resulting data
453
454 Args:
455 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
456
457 Returns:
458 Resulting image contents
459 """
460 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
461
Simon Glasse0ff8552016-11-25 20:15:53 -0700462 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass7ae5f312018-06-01 09:38:19 -0600463 """Helper function which discards the device-tree binary
464
465 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600466 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600467 use_real_dtb: True to use the test file as the contents of
468 the u-boot-dtb entry. Normally this is not needed and the
469 test contents (the U_BOOT_DTB_DATA string) can be used.
470 But in some test we need the real contents.
Simon Glassea6922e2018-07-17 13:25:27 -0600471
472 Returns:
473 Resulting image contents
Simon Glass7ae5f312018-06-01 09:38:19 -0600474 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700475 return self._DoReadFileDtb(fname, use_real_dtb)[0]
476
Simon Glass4f443042016-11-25 20:15:52 -0700477 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600478 def _MakeInputFile(cls, fname, contents):
Simon Glass4f443042016-11-25 20:15:52 -0700479 """Create a new test input file, creating directories as needed
480
481 Args:
Simon Glass3ab95982018-08-01 15:22:37 -0600482 fname: Filename to create
Simon Glass4f443042016-11-25 20:15:52 -0700483 contents: File contents to write in to the file
484 Returns:
485 Full pathname of file created
486 """
Simon Glassb986b3b2019-08-24 07:22:43 -0600487 pathname = os.path.join(cls._indir, fname)
Simon Glass4f443042016-11-25 20:15:52 -0700488 dirname = os.path.dirname(pathname)
489 if dirname and not os.path.exists(dirname):
490 os.makedirs(dirname)
491 with open(pathname, 'wb') as fd:
492 fd.write(contents)
493 return pathname
494
495 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600496 def _MakeInputDir(cls, dirname):
Simon Glass0ef87aa2018-07-17 13:25:44 -0600497 """Create a new test input directory, creating directories as needed
498
499 Args:
500 dirname: Directory name to create
501
502 Returns:
503 Full pathname of directory created
504 """
Simon Glassb986b3b2019-08-24 07:22:43 -0600505 pathname = os.path.join(cls._indir, dirname)
Simon Glass0ef87aa2018-07-17 13:25:44 -0600506 if not os.path.exists(pathname):
507 os.makedirs(pathname)
508 return pathname
509
510 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600511 def _SetupSplElf(cls, src_fname='bss_data'):
Simon Glass11ae93e2018-10-01 21:12:47 -0600512 """Set up an ELF file with a '_dt_ucode_base_size' symbol
513
514 Args:
515 Filename of ELF file to use as SPL
516 """
Simon Glassc9a0b272019-08-24 07:22:59 -0600517 TestFunctional._MakeInputFile('spl/u-boot-spl',
518 tools.ReadFile(cls.ElfTestFile(src_fname)))
Simon Glass11ae93e2018-10-01 21:12:47 -0600519
520 @classmethod
Simon Glass2090f1e2019-08-24 07:23:00 -0600521 def _SetupTplElf(cls, src_fname='bss_data'):
522 """Set up an ELF file with a '_dt_ucode_base_size' symbol
523
524 Args:
525 Filename of ELF file to use as TPL
526 """
527 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
528 tools.ReadFile(cls.ElfTestFile(src_fname)))
529
530 @classmethod
Simon Glass0ba4b3d2020-07-09 18:39:41 -0600531 def _SetupDescriptor(cls):
532 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
533 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
534
535 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600536 def TestFile(cls, fname):
537 return os.path.join(cls._binman_dir, 'test', fname)
Simon Glass4f443042016-11-25 20:15:52 -0700538
Simon Glass53e22bf2019-08-24 07:22:53 -0600539 @classmethod
540 def ElfTestFile(cls, fname):
541 return os.path.join(cls._elf_testdir, fname)
542
Simon Glass4f443042016-11-25 20:15:52 -0700543 def AssertInList(self, grep_list, target):
544 """Assert that at least one of a list of things is in a target
545
546 Args:
547 grep_list: List of strings to check
548 target: Target string
549 """
550 for grep in grep_list:
551 if grep in target:
552 return
Simon Glass1fc62de2019-05-17 22:00:50 -0600553 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass4f443042016-11-25 20:15:52 -0700554
555 def CheckNoGaps(self, entries):
556 """Check that all entries fit together without gaps
557
558 Args:
559 entries: List of entries to check
560 """
Simon Glass3ab95982018-08-01 15:22:37 -0600561 offset = 0
Simon Glass4f443042016-11-25 20:15:52 -0700562 for entry in entries.values():
Simon Glass3ab95982018-08-01 15:22:37 -0600563 self.assertEqual(offset, entry.offset)
564 offset += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700565
Simon Glasse0ff8552016-11-25 20:15:53 -0700566 def GetFdtLen(self, dtb):
Simon Glass7ae5f312018-06-01 09:38:19 -0600567 """Get the totalsize field from a device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700568
569 Args:
Simon Glass7ae5f312018-06-01 09:38:19 -0600570 dtb: Device-tree binary contents
Simon Glasse0ff8552016-11-25 20:15:53 -0700571
572 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600573 Total size of device-tree binary, from the header
Simon Glasse0ff8552016-11-25 20:15:53 -0700574 """
575 return struct.unpack('>L', dtb[4:8])[0]
576
Simon Glass086cec92019-07-08 14:25:27 -0600577 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glass16b8d6b2018-07-06 10:27:42 -0600578 def AddNode(node, path):
579 if node.name != '/':
580 path += '/' + node.name
Simon Glass086cec92019-07-08 14:25:27 -0600581 for prop in node.props.values():
582 if prop.name in prop_names:
583 prop_path = path + ':' + prop.name
584 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
585 prop.value)
Simon Glass16b8d6b2018-07-06 10:27:42 -0600586 for subnode in node.subnodes:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600587 AddNode(subnode, path)
588
589 tree = {}
Simon Glass16b8d6b2018-07-06 10:27:42 -0600590 AddNode(dtb.GetRoot(), '')
591 return tree
592
Simon Glass4f443042016-11-25 20:15:52 -0700593 def testRun(self):
594 """Test a basic run with valid args"""
595 result = self._RunBinman('-h')
596
597 def testFullHelp(self):
598 """Test that the full help is displayed with -H"""
599 result = self._RunBinman('-H')
600 help_file = os.path.join(self._binman_dir, 'README')
Tom Rini3759df02018-01-16 15:29:50 -0500601 # Remove possible extraneous strings
602 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
603 gothelp = result.stdout.replace(extra, '')
604 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass4f443042016-11-25 20:15:52 -0700605 self.assertEqual(0, len(result.stderr))
606 self.assertEqual(0, result.return_code)
607
608 def testFullHelpInternal(self):
609 """Test that the full help is displayed with -H"""
610 try:
611 command.test_result = command.CommandResult()
612 result = self._DoBinman('-H')
613 help_file = os.path.join(self._binman_dir, 'README')
614 finally:
615 command.test_result = None
616
617 def testHelp(self):
618 """Test that the basic help is displayed with -h"""
619 result = self._RunBinman('-h')
620 self.assertTrue(len(result.stdout) > 200)
621 self.assertEqual(0, len(result.stderr))
622 self.assertEqual(0, result.return_code)
623
Simon Glass4f443042016-11-25 20:15:52 -0700624 def testBoard(self):
625 """Test that we can run it with a specific board"""
Simon Glass741f2d62018-10-01 12:22:30 -0600626 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass4f443042016-11-25 20:15:52 -0700627 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glass53cd5d92019-07-08 14:25:29 -0600628 result = self._DoBinman('build', '-b', 'sandbox')
Simon Glass4f443042016-11-25 20:15:52 -0700629 self.assertEqual(0, result)
630
631 def testNeedBoard(self):
632 """Test that we get an error when no board ius supplied"""
633 with self.assertRaises(ValueError) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600634 result = self._DoBinman('build')
Simon Glass4f443042016-11-25 20:15:52 -0700635 self.assertIn("Must provide a board to process (use -b <board>)",
636 str(e.exception))
637
638 def testMissingDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600639 """Test that an invalid device-tree file generates an error"""
Simon Glass4f443042016-11-25 20:15:52 -0700640 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600641 self._RunBinman('build', '-d', 'missing_file')
Simon Glass4f443042016-11-25 20:15:52 -0700642 # We get one error from libfdt, and a different one from fdtget.
643 self.AssertInList(["Couldn't open blob from 'missing_file'",
644 'No such file or directory'], str(e.exception))
645
646 def testBrokenDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600647 """Test that an invalid device-tree source file generates an error
Simon Glass4f443042016-11-25 20:15:52 -0700648
649 Since this is a source file it should be compiled and the error
650 will come from the device-tree compiler (dtc).
651 """
652 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600653 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700654 self.assertIn("FATAL ERROR: Unable to parse input tree",
655 str(e.exception))
656
657 def testMissingNode(self):
658 """Test that a device tree without a 'binman' node generates an error"""
659 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600660 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700661 self.assertIn("does not have a 'binman' node", str(e.exception))
662
663 def testEmpty(self):
664 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glass53cd5d92019-07-08 14:25:29 -0600665 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700666 self.assertEqual(0, len(result.stderr))
667 self.assertEqual(0, result.return_code)
668
669 def testInvalidEntry(self):
670 """Test that an invalid entry is flagged"""
671 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600672 result = self._RunBinman('build', '-d',
Simon Glass741f2d62018-10-01 12:22:30 -0600673 self.TestFile('004_invalid_entry.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700674 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
675 "'/binman/not-a-valid-type'", str(e.exception))
676
677 def testSimple(self):
678 """Test a simple binman with a single file"""
Simon Glass741f2d62018-10-01 12:22:30 -0600679 data = self._DoReadFile('005_simple.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700680 self.assertEqual(U_BOOT_DATA, data)
681
Simon Glass7fe91732017-11-13 18:55:00 -0700682 def testSimpleDebug(self):
683 """Test a simple binman run with debugging enabled"""
Simon Glasse2705fa2019-07-08 14:25:53 -0600684 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass7fe91732017-11-13 18:55:00 -0700685
Simon Glass4f443042016-11-25 20:15:52 -0700686 def testDual(self):
687 """Test that we can handle creating two images
688
689 This also tests image padding.
690 """
Simon Glass741f2d62018-10-01 12:22:30 -0600691 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700692 self.assertEqual(0, retcode)
693
694 image = control.images['image1']
Simon Glass8beb11e2019-07-08 14:25:47 -0600695 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700696 fname = tools.GetOutputFilename('image1.bin')
697 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600698 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700699 data = fd.read()
700 self.assertEqual(U_BOOT_DATA, data)
701
702 image = control.images['image2']
Simon Glass8beb11e2019-07-08 14:25:47 -0600703 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700704 fname = tools.GetOutputFilename('image2.bin')
705 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600706 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700707 data = fd.read()
708 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glasse6d85ff2019-05-14 15:53:47 -0600709 self.assertEqual(tools.GetBytes(0, 3), data[:3])
710 self.assertEqual(tools.GetBytes(0, 5), data[7:])
Simon Glass4f443042016-11-25 20:15:52 -0700711
712 def testBadAlign(self):
713 """Test that an invalid alignment value is detected"""
714 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600715 self._DoTestFile('007_bad_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700716 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
717 "of two", str(e.exception))
718
719 def testPackSimple(self):
720 """Test that packing works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600721 retcode = self._DoTestFile('008_pack.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700722 self.assertEqual(0, retcode)
723 self.assertIn('image', control.images)
724 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600725 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700726 self.assertEqual(5, len(entries))
727
728 # First u-boot
729 self.assertIn('u-boot', entries)
730 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600731 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700732 self.assertEqual(len(U_BOOT_DATA), entry.size)
733
734 # Second u-boot, aligned to 16-byte boundary
735 self.assertIn('u-boot-align', entries)
736 entry = entries['u-boot-align']
Simon Glass3ab95982018-08-01 15:22:37 -0600737 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700738 self.assertEqual(len(U_BOOT_DATA), entry.size)
739
740 # Third u-boot, size 23 bytes
741 self.assertIn('u-boot-size', entries)
742 entry = entries['u-boot-size']
Simon Glass3ab95982018-08-01 15:22:37 -0600743 self.assertEqual(20, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700744 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
745 self.assertEqual(23, entry.size)
746
747 # Fourth u-boot, placed immediate after the above
748 self.assertIn('u-boot-next', entries)
749 entry = entries['u-boot-next']
Simon Glass3ab95982018-08-01 15:22:37 -0600750 self.assertEqual(43, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700751 self.assertEqual(len(U_BOOT_DATA), entry.size)
752
Simon Glass3ab95982018-08-01 15:22:37 -0600753 # Fifth u-boot, placed at a fixed offset
Simon Glass4f443042016-11-25 20:15:52 -0700754 self.assertIn('u-boot-fixed', entries)
755 entry = entries['u-boot-fixed']
Simon Glass3ab95982018-08-01 15:22:37 -0600756 self.assertEqual(61, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700757 self.assertEqual(len(U_BOOT_DATA), entry.size)
758
Simon Glass8beb11e2019-07-08 14:25:47 -0600759 self.assertEqual(65, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700760
761 def testPackExtra(self):
762 """Test that extra packing feature works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600763 retcode = self._DoTestFile('009_pack_extra.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700764
765 self.assertEqual(0, retcode)
766 self.assertIn('image', control.images)
767 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600768 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700769 self.assertEqual(5, len(entries))
770
771 # First u-boot with padding before and after
772 self.assertIn('u-boot', entries)
773 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600774 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700775 self.assertEqual(3, entry.pad_before)
776 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
777
778 # Second u-boot has an aligned size, but it has no effect
779 self.assertIn('u-boot-align-size-nop', entries)
780 entry = entries['u-boot-align-size-nop']
Simon Glass3ab95982018-08-01 15:22:37 -0600781 self.assertEqual(12, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700782 self.assertEqual(4, entry.size)
783
784 # Third u-boot has an aligned size too
785 self.assertIn('u-boot-align-size', entries)
786 entry = entries['u-boot-align-size']
Simon Glass3ab95982018-08-01 15:22:37 -0600787 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700788 self.assertEqual(32, entry.size)
789
790 # Fourth u-boot has an aligned end
791 self.assertIn('u-boot-align-end', entries)
792 entry = entries['u-boot-align-end']
Simon Glass3ab95982018-08-01 15:22:37 -0600793 self.assertEqual(48, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700794 self.assertEqual(16, entry.size)
795
796 # Fifth u-boot immediately afterwards
797 self.assertIn('u-boot-align-both', entries)
798 entry = entries['u-boot-align-both']
Simon Glass3ab95982018-08-01 15:22:37 -0600799 self.assertEqual(64, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700800 self.assertEqual(64, entry.size)
801
802 self.CheckNoGaps(entries)
Simon Glass8beb11e2019-07-08 14:25:47 -0600803 self.assertEqual(128, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700804
805 def testPackAlignPowerOf2(self):
806 """Test that invalid entry alignment is detected"""
807 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600808 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700809 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
810 "of two", str(e.exception))
811
812 def testPackAlignSizePowerOf2(self):
813 """Test that invalid entry size alignment is detected"""
814 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600815 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700816 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
817 "power of two", str(e.exception))
818
819 def testPackInvalidAlign(self):
Simon Glass3ab95982018-08-01 15:22:37 -0600820 """Test detection of an offset that does not match its alignment"""
Simon Glass4f443042016-11-25 20:15:52 -0700821 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600822 self._DoTestFile('012_pack_inv_align.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600823 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700824 "align 0x4 (4)", str(e.exception))
825
826 def testPackInvalidSizeAlign(self):
827 """Test that invalid entry size alignment is detected"""
828 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600829 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700830 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
831 "align-size 0x4 (4)", str(e.exception))
832
833 def testPackOverlap(self):
834 """Test that overlapping regions are detected"""
835 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600836 self._DoTestFile('014_pack_overlap.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600837 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -0700838 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
839 str(e.exception))
840
841 def testPackEntryOverflow(self):
842 """Test that entries that overflow their size are detected"""
843 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600844 self._DoTestFile('015_pack_overflow.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700845 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
846 "but entry size is 0x3 (3)", str(e.exception))
847
848 def testPackImageOverflow(self):
849 """Test that entries which overflow the image size are detected"""
850 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600851 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600852 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass4f443042016-11-25 20:15:52 -0700853 "size 0x3 (3)", str(e.exception))
854
855 def testPackImageSize(self):
856 """Test that the image size can be set"""
Simon Glass741f2d62018-10-01 12:22:30 -0600857 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700858 self.assertEqual(0, retcode)
859 self.assertIn('image', control.images)
860 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -0600861 self.assertEqual(7, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700862
863 def testPackImageSizeAlign(self):
864 """Test that image size alignemnt works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600865 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700866 self.assertEqual(0, retcode)
867 self.assertIn('image', control.images)
868 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -0600869 self.assertEqual(16, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700870
871 def testPackInvalidImageAlign(self):
872 """Test that invalid image alignment is detected"""
873 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600874 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600875 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700876 "align-size 0x8 (8)", str(e.exception))
877
878 def testPackAlignPowerOf2(self):
879 """Test that invalid image alignment is detected"""
880 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600881 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -0600882 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass4f443042016-11-25 20:15:52 -0700883 "two", str(e.exception))
884
885 def testImagePadByte(self):
886 """Test that the image pad byte can be specified"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600887 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600888 data = self._DoReadFile('021_image_pad.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -0600889 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0xff, 1) +
890 U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -0700891
892 def testImageName(self):
893 """Test that image files can be named"""
Simon Glass741f2d62018-10-01 12:22:30 -0600894 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700895 self.assertEqual(0, retcode)
896 image = control.images['image1']
897 fname = tools.GetOutputFilename('test-name')
898 self.assertTrue(os.path.exists(fname))
899
900 image = control.images['image2']
901 fname = tools.GetOutputFilename('test-name.xx')
902 self.assertTrue(os.path.exists(fname))
903
904 def testBlobFilename(self):
905 """Test that generic blobs can be provided by filename"""
Simon Glass741f2d62018-10-01 12:22:30 -0600906 data = self._DoReadFile('023_blob.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700907 self.assertEqual(BLOB_DATA, data)
908
909 def testPackSorted(self):
910 """Test that entries can be sorted"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600911 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600912 data = self._DoReadFile('024_sorted.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -0600913 self.assertEqual(tools.GetBytes(0, 1) + U_BOOT_SPL_DATA +
914 tools.GetBytes(0, 2) + U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -0700915
Simon Glass3ab95982018-08-01 15:22:37 -0600916 def testPackZeroOffset(self):
917 """Test that an entry at offset 0 is not given a new offset"""
Simon Glass4f443042016-11-25 20:15:52 -0700918 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600919 self._DoTestFile('025_pack_zero_size.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600920 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -0700921 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
922 str(e.exception))
923
924 def testPackUbootDtb(self):
925 """Test that a device tree can be added to U-Boot"""
Simon Glass741f2d62018-10-01 12:22:30 -0600926 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700927 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glasse0ff8552016-11-25 20:15:53 -0700928
929 def testPackX86RomNoSize(self):
930 """Test that the end-at-4gb property requires a size property"""
931 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600932 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -0600933 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glasse0ff8552016-11-25 20:15:53 -0700934 "using end-at-4gb", str(e.exception))
935
Jagdish Gediya94b57db2018-09-03 21:35:07 +0530936 def test4gbAndSkipAtStartTogether(self):
937 """Test that the end-at-4gb and skip-at-size property can't be used
938 together"""
939 with self.assertRaises(ValueError) as e:
Simon Glassdfdd2b62019-08-24 07:23:02 -0600940 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -0600941 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya94b57db2018-09-03 21:35:07 +0530942 "'skip-at-start'", str(e.exception))
943
Simon Glasse0ff8552016-11-25 20:15:53 -0700944 def testPackX86RomOutside(self):
Simon Glass3ab95982018-08-01 15:22:37 -0600945 """Test that the end-at-4gb property checks for offset boundaries"""
Simon Glasse0ff8552016-11-25 20:15:53 -0700946 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600947 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600948 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) is outside "
Simon Glass8f1da502018-06-01 09:38:12 -0600949 "the section starting at 0xffffffe0 (4294967264)",
Simon Glasse0ff8552016-11-25 20:15:53 -0700950 str(e.exception))
951
952 def testPackX86Rom(self):
953 """Test that a basic x86 ROM can be created"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600954 self._SetupSplElf()
Simon Glass9255f3c2019-08-24 07:23:01 -0600955 data = self._DoReadFile('029_x86_rom.dts')
Simon Glasseb0086f2019-08-24 07:23:04 -0600956 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 3) + U_BOOT_SPL_DATA +
Simon Glasse6d85ff2019-05-14 15:53:47 -0600957 tools.GetBytes(0, 2), data)
Simon Glasse0ff8552016-11-25 20:15:53 -0700958
959 def testPackX86RomMeNoDesc(self):
960 """Test that an invalid Intel descriptor entry is detected"""
Simon Glass0ba4b3d2020-07-09 18:39:41 -0600961 try:
Simon Glass52b10dd2020-07-25 15:11:19 -0600962 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
Simon Glass0ba4b3d2020-07-09 18:39:41 -0600963 with self.assertRaises(ValueError) as e:
Simon Glass52b10dd2020-07-25 15:11:19 -0600964 self._DoTestFile('163_x86_rom_me_empty.dts')
Simon Glass0ba4b3d2020-07-09 18:39:41 -0600965 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
966 str(e.exception))
967 finally:
968 self._SetupDescriptor()
Simon Glasse0ff8552016-11-25 20:15:53 -0700969
970 def testPackX86RomBadDesc(self):
971 """Test that the Intel requires a descriptor entry"""
972 with self.assertRaises(ValueError) as e:
Simon Glass9255f3c2019-08-24 07:23:01 -0600973 self._DoTestFile('030_x86_rom_me_no_desc.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600974 self.assertIn("Node '/binman/intel-me': No offset set with "
975 "offset-unset: should another entry provide this correct "
976 "offset?", str(e.exception))
Simon Glasse0ff8552016-11-25 20:15:53 -0700977
978 def testPackX86RomMe(self):
979 """Test that an x86 ROM with an ME region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -0600980 data = self._DoReadFile('031_x86_rom_me.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -0600981 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
982 if data[:0x1000] != expected_desc:
983 self.fail('Expected descriptor binary at start of image')
Simon Glasse0ff8552016-11-25 20:15:53 -0700984 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
985
986 def testPackVga(self):
987 """Test that an image with a VGA binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -0600988 data = self._DoReadFile('032_intel_vga.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -0700989 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
990
991 def testPackStart16(self):
992 """Test that an image with an x86 start16 region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -0600993 data = self._DoReadFile('033_x86_start16.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -0700994 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
995
Jagdish Gediya9d368f32018-09-03 21:35:08 +0530996 def testPackPowerpcMpc85xxBootpgResetvec(self):
997 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
998 created"""
Simon Glassdfdd2b62019-08-24 07:23:02 -0600999 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
Jagdish Gediya9d368f32018-09-03 21:35:08 +05301000 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1001
Simon Glass736bb0a2018-07-06 10:27:17 -06001002 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glassadc57012018-07-06 10:27:16 -06001003 """Handle running a test for insertion of microcode
1004
1005 Args:
1006 dts_fname: Name of test .dts file
1007 nodtb_data: Data that we expect in the first section
Simon Glass736bb0a2018-07-06 10:27:17 -06001008 ucode_second: True if the microsecond entry is second instead of
1009 third
Simon Glassadc57012018-07-06 10:27:16 -06001010
1011 Returns:
1012 Tuple:
1013 Contents of first region (U-Boot or SPL)
Simon Glass3ab95982018-08-01 15:22:37 -06001014 Offset and size components of microcode pointer, as inserted
Simon Glassadc57012018-07-06 10:27:16 -06001015 in the above (two 4-byte words)
1016 """
Simon Glass6b187df2017-11-12 21:52:27 -07001017 data = self._DoReadFile(dts_fname, True)
Simon Glasse0ff8552016-11-25 20:15:53 -07001018
1019 # Now check the device tree has no microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001020 if ucode_second:
1021 ucode_content = data[len(nodtb_data):]
1022 ucode_pos = len(nodtb_data)
1023 dtb_with_ucode = ucode_content[16:]
1024 fdt_len = self.GetFdtLen(dtb_with_ucode)
1025 else:
1026 dtb_with_ucode = data[len(nodtb_data):]
1027 fdt_len = self.GetFdtLen(dtb_with_ucode)
1028 ucode_content = dtb_with_ucode[fdt_len:]
1029 ucode_pos = len(nodtb_data) + fdt_len
Simon Glasse0ff8552016-11-25 20:15:53 -07001030 fname = tools.GetOutputFilename('test.dtb')
1031 with open(fname, 'wb') as fd:
Simon Glassadc57012018-07-06 10:27:16 -06001032 fd.write(dtb_with_ucode)
Simon Glassec3f3782017-05-27 07:38:29 -06001033 dtb = fdt.FdtScan(fname)
1034 ucode = dtb.GetNode('/microcode')
Simon Glasse0ff8552016-11-25 20:15:53 -07001035 self.assertTrue(ucode)
1036 for node in ucode.subnodes:
1037 self.assertFalse(node.props.get('data'))
1038
Simon Glasse0ff8552016-11-25 20:15:53 -07001039 # Check that the microcode appears immediately after the Fdt
1040 # This matches the concatenation of the data properties in
Simon Glass87722132017-11-12 21:52:26 -07001041 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glasse0ff8552016-11-25 20:15:53 -07001042 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1043 0x78235609)
Simon Glassadc57012018-07-06 10:27:16 -06001044 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glasse0ff8552016-11-25 20:15:53 -07001045
1046 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -06001047 # expected offset and size
Simon Glasse0ff8552016-11-25 20:15:53 -07001048 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1049 len(ucode_data))
Simon Glass736bb0a2018-07-06 10:27:17 -06001050 u_boot = data[:len(nodtb_data)]
1051 return u_boot, pos_and_size
Simon Glass6b187df2017-11-12 21:52:27 -07001052
1053 def testPackUbootMicrocode(self):
1054 """Test that x86 microcode can be handled correctly
1055
1056 We expect to see the following in the image, in order:
1057 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1058 place
1059 u-boot.dtb with the microcode removed
1060 the microcode
1061 """
Simon Glass741f2d62018-10-01 12:22:30 -06001062 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass6b187df2017-11-12 21:52:27 -07001063 U_BOOT_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001064 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1065 b' somewhere in here', first)
Simon Glasse0ff8552016-11-25 20:15:53 -07001066
Simon Glass160a7662017-05-27 07:38:26 -06001067 def _RunPackUbootSingleMicrocode(self):
Simon Glasse0ff8552016-11-25 20:15:53 -07001068 """Test that x86 microcode can be handled correctly
1069
1070 We expect to see the following in the image, in order:
1071 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1072 place
1073 u-boot.dtb with the microcode
1074 an empty microcode region
1075 """
1076 # We need the libfdt library to run this test since only that allows
1077 # finding the offset of a property. This is required by
1078 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass741f2d62018-10-01 12:22:30 -06001079 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glasse0ff8552016-11-25 20:15:53 -07001080
1081 second = data[len(U_BOOT_NODTB_DATA):]
1082
1083 fdt_len = self.GetFdtLen(second)
1084 third = second[fdt_len:]
1085 second = second[:fdt_len]
1086
Simon Glass160a7662017-05-27 07:38:26 -06001087 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1088 self.assertIn(ucode_data, second)
1089 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -07001090
Simon Glass160a7662017-05-27 07:38:26 -06001091 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -06001092 # expected offset and size
Simon Glass160a7662017-05-27 07:38:26 -06001093 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1094 len(ucode_data))
1095 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glassc6c10e72019-05-17 22:00:46 -06001096 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1097 b' somewhere in here', first)
Simon Glassc49deb82016-11-25 20:15:54 -07001098
Simon Glass75db0862016-11-25 20:15:55 -07001099 def testPackUbootSingleMicrocode(self):
1100 """Test that x86 microcode can be handled correctly with fdt_normal.
1101 """
Simon Glass160a7662017-05-27 07:38:26 -06001102 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001103
Simon Glassc49deb82016-11-25 20:15:54 -07001104 def testUBootImg(self):
1105 """Test that u-boot.img can be put in a file"""
Simon Glass741f2d62018-10-01 12:22:30 -06001106 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glassc49deb82016-11-25 20:15:54 -07001107 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glass75db0862016-11-25 20:15:55 -07001108
1109 def testNoMicrocode(self):
1110 """Test that a missing microcode region is detected"""
1111 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001112 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001113 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1114 "node found in ", str(e.exception))
1115
1116 def testMicrocodeWithoutNode(self):
1117 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1118 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001119 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001120 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1121 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1122
1123 def testMicrocodeWithoutNode2(self):
1124 """Test that a missing u-boot-ucode node is detected"""
1125 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001126 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001127 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1128 "microcode region u-boot-ucode", str(e.exception))
1129
1130 def testMicrocodeWithoutPtrInElf(self):
1131 """Test that a U-Boot binary without the microcode symbol is detected"""
1132 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glass75db0862016-11-25 20:15:55 -07001133 try:
Simon Glassbccd91d2019-08-24 07:22:55 -06001134 TestFunctional._MakeInputFile('u-boot',
1135 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass75db0862016-11-25 20:15:55 -07001136
1137 with self.assertRaises(ValueError) as e:
Simon Glass160a7662017-05-27 07:38:26 -06001138 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001139 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1140 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1141
1142 finally:
1143 # Put the original file back
Simon Glassf514d8f2019-08-24 07:22:54 -06001144 TestFunctional._MakeInputFile('u-boot',
1145 tools.ReadFile(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glass75db0862016-11-25 20:15:55 -07001146
1147 def testMicrocodeNotInImage(self):
1148 """Test that microcode must be placed within the image"""
1149 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001150 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001151 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1152 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glass25ac0e62018-06-01 09:38:14 -06001153 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glass75db0862016-11-25 20:15:55 -07001154
1155 def testWithoutMicrocode(self):
1156 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glassbccd91d2019-08-24 07:22:55 -06001157 TestFunctional._MakeInputFile('u-boot',
1158 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass741f2d62018-10-01 12:22:30 -06001159 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001160
1161 # Now check the device tree has no microcode
1162 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1163 second = data[len(U_BOOT_NODTB_DATA):]
1164
1165 fdt_len = self.GetFdtLen(second)
1166 self.assertEqual(dtb, second[:fdt_len])
1167
1168 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1169 third = data[used_len:]
Simon Glasse6d85ff2019-05-14 15:53:47 -06001170 self.assertEqual(tools.GetBytes(0, 0x200 - used_len), third)
Simon Glass75db0862016-11-25 20:15:55 -07001171
1172 def testUnknownPosSize(self):
1173 """Test that microcode must be placed within the image"""
1174 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001175 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glass3ab95982018-08-01 15:22:37 -06001176 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glass75db0862016-11-25 20:15:55 -07001177 "entry 'invalid-entry'", str(e.exception))
Simon Glassda229092016-11-25 20:15:56 -07001178
1179 def testPackFsp(self):
1180 """Test that an image with a FSP binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001181 data = self._DoReadFile('042_intel_fsp.dts')
Simon Glassda229092016-11-25 20:15:56 -07001182 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1183
1184 def testPackCmc(self):
Bin Meng59ea8c22017-08-15 22:41:54 -07001185 """Test that an image with a CMC binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001186 data = self._DoReadFile('043_intel_cmc.dts')
Simon Glassda229092016-11-25 20:15:56 -07001187 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Meng59ea8c22017-08-15 22:41:54 -07001188
1189 def testPackVbt(self):
1190 """Test that an image with a VBT binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001191 data = self._DoReadFile('046_intel_vbt.dts')
Bin Meng59ea8c22017-08-15 22:41:54 -07001192 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glass9fc60b42017-11-12 21:52:22 -07001193
Simon Glass56509842017-11-12 21:52:25 -07001194 def testSplBssPad(self):
1195 """Test that we can pad SPL's BSS with zeros"""
Simon Glass6b187df2017-11-12 21:52:27 -07001196 # ELF file with a '__bss_size' symbol
Simon Glass11ae93e2018-10-01 21:12:47 -06001197 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001198 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001199 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
1200 data)
Simon Glass56509842017-11-12 21:52:25 -07001201
Simon Glass86af5112018-10-01 21:12:42 -06001202 def testSplBssPadMissing(self):
1203 """Test that a missing symbol is detected"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001204 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glassb50e5612017-11-13 18:54:54 -07001205 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001206 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassb50e5612017-11-13 18:54:54 -07001207 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1208 str(e.exception))
1209
Simon Glass87722132017-11-12 21:52:26 -07001210 def testPackStart16Spl(self):
Simon Glass35b384c2018-09-14 04:57:10 -06001211 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001212 data = self._DoReadFile('048_x86_start16_spl.dts')
Simon Glass87722132017-11-12 21:52:26 -07001213 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1214
Simon Glass736bb0a2018-07-06 10:27:17 -06001215 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1216 """Helper function for microcode tests
Simon Glass6b187df2017-11-12 21:52:27 -07001217
1218 We expect to see the following in the image, in order:
1219 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1220 correct place
1221 u-boot.dtb with the microcode removed
1222 the microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001223
1224 Args:
1225 dts: Device tree file to use for test
1226 ucode_second: True if the microsecond entry is second instead of
1227 third
Simon Glass6b187df2017-11-12 21:52:27 -07001228 """
Simon Glass11ae93e2018-10-01 21:12:47 -06001229 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass736bb0a2018-07-06 10:27:17 -06001230 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1231 ucode_second=ucode_second)
Simon Glassc6c10e72019-05-17 22:00:46 -06001232 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1233 b'ter somewhere in here', first)
Simon Glass6b187df2017-11-12 21:52:27 -07001234
Simon Glass736bb0a2018-07-06 10:27:17 -06001235 def testPackUbootSplMicrocode(self):
1236 """Test that x86 microcode can be handled correctly in SPL"""
Simon Glass741f2d62018-10-01 12:22:30 -06001237 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass736bb0a2018-07-06 10:27:17 -06001238
1239 def testPackUbootSplMicrocodeReorder(self):
1240 """Test that order doesn't matter for microcode entries
1241
1242 This is the same as testPackUbootSplMicrocode but when we process the
1243 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1244 entry, so we reply on binman to try later.
1245 """
Simon Glass741f2d62018-10-01 12:22:30 -06001246 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass736bb0a2018-07-06 10:27:17 -06001247 ucode_second=True)
1248
Simon Glassca4f4ff2017-11-12 21:52:28 -07001249 def testPackMrc(self):
1250 """Test that an image with an MRC binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001251 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassca4f4ff2017-11-12 21:52:28 -07001252 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1253
Simon Glass47419ea2017-11-13 18:54:55 -07001254 def testSplDtb(self):
1255 """Test that an image with spl/u-boot-spl.dtb can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001256 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass47419ea2017-11-13 18:54:55 -07001257 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1258
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001259 def testSplNoDtb(self):
1260 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001261 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001262 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1263
Simon Glass19790632017-11-13 18:55:01 -07001264 def testSymbols(self):
1265 """Test binman can assign symbols embedded in U-Boot"""
Simon Glass1542c8b2019-08-24 07:22:56 -06001266 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass19790632017-11-13 18:55:01 -07001267 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1268 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Simon Glass3ab95982018-08-01 15:22:37 -06001269 self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr)
Simon Glass19790632017-11-13 18:55:01 -07001270
Simon Glass11ae93e2018-10-01 21:12:47 -06001271 self._SetupSplElf('u_boot_binman_syms')
Simon Glass741f2d62018-10-01 12:22:30 -06001272 data = self._DoReadFile('053_symbols.dts')
Simon Glass7c150132019-11-06 17:22:44 -07001273 sym_values = struct.pack('<LQLL', 0x00, 0x1c, 0x28, 0x04)
Simon Glassb87064c2019-08-24 07:23:05 -06001274 expected = (sym_values + U_BOOT_SPL_DATA[20:] +
Simon Glasse6d85ff2019-05-14 15:53:47 -06001275 tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
Simon Glassb87064c2019-08-24 07:23:05 -06001276 U_BOOT_SPL_DATA[20:])
Simon Glass19790632017-11-13 18:55:01 -07001277 self.assertEqual(expected, data)
1278
Simon Glassdd57c132018-06-01 09:38:11 -06001279 def testPackUnitAddress(self):
1280 """Test that we support multiple binaries with the same name"""
Simon Glass741f2d62018-10-01 12:22:30 -06001281 data = self._DoReadFile('054_unit_address.dts')
Simon Glassdd57c132018-06-01 09:38:11 -06001282 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1283
Simon Glass18546952018-06-01 09:38:16 -06001284 def testSections(self):
1285 """Basic test of sections"""
Simon Glass741f2d62018-10-01 12:22:30 -06001286 data = self._DoReadFile('055_sections.dts')
Simon Glassc6c10e72019-05-17 22:00:46 -06001287 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1288 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
1289 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
Simon Glass18546952018-06-01 09:38:16 -06001290 self.assertEqual(expected, data)
Simon Glass9fc60b42017-11-12 21:52:22 -07001291
Simon Glass3b0c38212018-06-01 09:38:20 -06001292 def testMap(self):
1293 """Tests outputting a map of the images"""
Simon Glass741f2d62018-10-01 12:22:30 -06001294 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001295 self.assertEqual('''ImagePos Offset Size Name
129600000000 00000000 00000028 main-section
129700000000 00000000 00000010 section@0
129800000000 00000000 00000004 u-boot
129900000010 00000010 00000010 section@1
130000000010 00000000 00000004 u-boot
130100000020 00000020 00000004 section@2
130200000020 00000000 00000004 u-boot
Simon Glass3b0c38212018-06-01 09:38:20 -06001303''', map_data)
1304
Simon Glassc8d48ef2018-06-01 09:38:21 -06001305 def testNamePrefix(self):
1306 """Tests that name prefixes are used"""
Simon Glass741f2d62018-10-01 12:22:30 -06001307 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001308 self.assertEqual('''ImagePos Offset Size Name
130900000000 00000000 00000028 main-section
131000000000 00000000 00000010 section@0
131100000000 00000000 00000004 ro-u-boot
131200000010 00000010 00000010 section@1
131300000010 00000000 00000004 rw-u-boot
Simon Glassc8d48ef2018-06-01 09:38:21 -06001314''', map_data)
1315
Simon Glass736bb0a2018-07-06 10:27:17 -06001316 def testUnknownContents(self):
1317 """Test that obtaining the contents works as expected"""
1318 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001319 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass8beb11e2019-07-08 14:25:47 -06001320 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glass16287932020-04-17 18:09:03 -06001321 "processing of contents: remaining ["
1322 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass736bb0a2018-07-06 10:27:17 -06001323
Simon Glass5c890232018-07-06 10:27:19 -06001324 def testBadChangeSize(self):
1325 """Test that trying to change the size of an entry fails"""
Simon Glassc52c9e72019-07-08 14:25:37 -06001326 try:
1327 state.SetAllowEntryExpansion(False)
1328 with self.assertRaises(ValueError) as e:
1329 self._DoReadFile('059_change_size.dts', True)
Simon Glass79d3c582019-07-20 12:23:57 -06001330 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glassc52c9e72019-07-08 14:25:37 -06001331 str(e.exception))
1332 finally:
1333 state.SetAllowEntryExpansion(True)
Simon Glass5c890232018-07-06 10:27:19 -06001334
Simon Glass16b8d6b2018-07-06 10:27:42 -06001335 def testUpdateFdt(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001336 """Test that we can update the device tree with offset/size info"""
Simon Glass741f2d62018-10-01 12:22:30 -06001337 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glass16b8d6b2018-07-06 10:27:42 -06001338 update_dtb=True)
Simon Glasscee02e62018-07-17 13:25:52 -06001339 dtb = fdt.Fdt(out_dtb_fname)
1340 dtb.Scan()
Simon Glass12bb1a92019-07-20 12:23:51 -06001341 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001342 self.assertEqual({
Simon Glassdbf6be92018-08-01 15:22:42 -06001343 'image-pos': 0,
Simon Glass8122f392018-07-17 13:25:28 -06001344 'offset': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001345 '_testing:offset': 32,
Simon Glass79d3c582019-07-20 12:23:57 -06001346 '_testing:size': 2,
Simon Glassdbf6be92018-08-01 15:22:42 -06001347 '_testing:image-pos': 32,
Simon Glass3ab95982018-08-01 15:22:37 -06001348 'section@0/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001349 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001350 'section@0/u-boot:image-pos': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001351 'section@0:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001352 'section@0:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001353 'section@0:image-pos': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001354
Simon Glass3ab95982018-08-01 15:22:37 -06001355 'section@1/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001356 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001357 'section@1/u-boot:image-pos': 16,
Simon Glass3ab95982018-08-01 15:22:37 -06001358 'section@1:offset': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001359 'section@1:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001360 'section@1:image-pos': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001361 'size': 40
1362 }, props)
1363
1364 def testUpdateFdtBad(self):
1365 """Test that we detect when ProcessFdt never completes"""
1366 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001367 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001368 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glass16287932020-04-17 18:09:03 -06001369 '[<binman.etype._testing.Entry__testing',
1370 str(e.exception))
Simon Glass5c890232018-07-06 10:27:19 -06001371
Simon Glass53af22a2018-07-17 13:25:32 -06001372 def testEntryArgs(self):
1373 """Test passing arguments to entries from the command line"""
1374 entry_args = {
1375 'test-str-arg': 'test1',
1376 'test-int-arg': '456',
1377 }
Simon Glass741f2d62018-10-01 12:22:30 -06001378 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001379 self.assertIn('image', control.images)
1380 entry = control.images['image'].GetEntries()['_testing']
1381 self.assertEqual('test0', entry.test_str_fdt)
1382 self.assertEqual('test1', entry.test_str_arg)
1383 self.assertEqual(123, entry.test_int_fdt)
1384 self.assertEqual(456, entry.test_int_arg)
1385
1386 def testEntryArgsMissing(self):
1387 """Test missing arguments and properties"""
1388 entry_args = {
1389 'test-int-arg': '456',
1390 }
Simon Glass741f2d62018-10-01 12:22:30 -06001391 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001392 entry = control.images['image'].GetEntries()['_testing']
1393 self.assertEqual('test0', entry.test_str_fdt)
1394 self.assertEqual(None, entry.test_str_arg)
1395 self.assertEqual(None, entry.test_int_fdt)
1396 self.assertEqual(456, entry.test_int_arg)
1397
1398 def testEntryArgsRequired(self):
1399 """Test missing arguments and properties"""
1400 entry_args = {
1401 'test-int-arg': '456',
1402 }
1403 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001404 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass3decfa32020-09-01 05:13:54 -06001405 self.assertIn("Node '/binman/_testing': "
1406 'Missing required properties/entry args: test-str-arg, '
1407 'test-int-fdt, test-int-arg',
Simon Glass53af22a2018-07-17 13:25:32 -06001408 str(e.exception))
1409
1410 def testEntryArgsInvalidFormat(self):
1411 """Test that an invalid entry-argument format is detected"""
Simon Glass53cd5d92019-07-08 14:25:29 -06001412 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1413 '-ano-value']
Simon Glass53af22a2018-07-17 13:25:32 -06001414 with self.assertRaises(ValueError) as e:
1415 self._DoBinman(*args)
1416 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1417
1418 def testEntryArgsInvalidInteger(self):
1419 """Test that an invalid entry-argument integer is detected"""
1420 entry_args = {
1421 'test-int-arg': 'abc',
1422 }
1423 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001424 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001425 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1426 "'test-int-arg' (value 'abc') to integer",
1427 str(e.exception))
1428
1429 def testEntryArgsInvalidDatatype(self):
1430 """Test that an invalid entry-argument datatype is detected
1431
1432 This test could be written in entry_test.py except that it needs
1433 access to control.entry_args, which seems more than that module should
1434 be able to see.
1435 """
1436 entry_args = {
1437 'test-bad-datatype-arg': '12',
1438 }
1439 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001440 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass53af22a2018-07-17 13:25:32 -06001441 entry_args=entry_args)
1442 self.assertIn('GetArg() internal error: Unknown data type ',
1443 str(e.exception))
1444
Simon Glassbb748372018-07-17 13:25:33 -06001445 def testText(self):
1446 """Test for a text entry type"""
1447 entry_args = {
1448 'test-id': TEXT_DATA,
1449 'test-id2': TEXT_DATA2,
1450 'test-id3': TEXT_DATA3,
1451 }
Simon Glass741f2d62018-10-01 12:22:30 -06001452 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glassbb748372018-07-17 13:25:33 -06001453 entry_args=entry_args)
Simon Glassc6c10e72019-05-17 22:00:46 -06001454 expected = (tools.ToBytes(TEXT_DATA) +
1455 tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1456 tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
Simon Glassaa88b502019-07-08 13:18:40 -06001457 b'some text' + b'more text')
Simon Glassbb748372018-07-17 13:25:33 -06001458 self.assertEqual(expected, data)
1459
Simon Glassfd8d1f72018-07-17 13:25:36 -06001460 def testEntryDocs(self):
1461 """Test for creation of entry documentation"""
1462 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass87d43322020-08-05 13:27:46 -06001463 control.WriteEntryDocs(control.GetEntryModules())
Simon Glassfd8d1f72018-07-17 13:25:36 -06001464 self.assertTrue(len(stdout.getvalue()) > 0)
1465
1466 def testEntryDocsMissing(self):
1467 """Test handling of missing entry documentation"""
1468 with self.assertRaises(ValueError) as e:
1469 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass87d43322020-08-05 13:27:46 -06001470 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glassfd8d1f72018-07-17 13:25:36 -06001471 self.assertIn('Documentation is missing for modules: u_boot',
1472 str(e.exception))
1473
Simon Glass11e36cc2018-07-17 13:25:38 -06001474 def testFmap(self):
1475 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001476 data = self._DoReadFile('067_fmap.dts')
Simon Glass11e36cc2018-07-17 13:25:38 -06001477 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc6c10e72019-05-17 22:00:46 -06001478 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1479 U_BOOT_DATA + tools.GetBytes(ord('a'), 12))
Simon Glass11e36cc2018-07-17 13:25:38 -06001480 self.assertEqual(expected, data[:32])
Simon Glassc6c10e72019-05-17 22:00:46 -06001481 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass11e36cc2018-07-17 13:25:38 -06001482 self.assertEqual(1, fhdr.ver_major)
1483 self.assertEqual(0, fhdr.ver_minor)
1484 self.assertEqual(0, fhdr.base)
1485 self.assertEqual(16 + 16 +
1486 fmap_util.FMAP_HEADER_LEN +
1487 fmap_util.FMAP_AREA_LEN * 3, fhdr.image_size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001488 self.assertEqual(b'FMAP', fhdr.name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001489 self.assertEqual(3, fhdr.nareas)
1490 for fentry in fentries:
1491 self.assertEqual(0, fentry.flags)
1492
1493 self.assertEqual(0, fentries[0].offset)
1494 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001495 self.assertEqual(b'RO_U_BOOT', fentries[0].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001496
1497 self.assertEqual(16, fentries[1].offset)
1498 self.assertEqual(4, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001499 self.assertEqual(b'RW_U_BOOT', fentries[1].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001500
1501 self.assertEqual(32, fentries[2].offset)
1502 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1503 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001504 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001505
Simon Glassec127af2018-07-17 13:25:39 -06001506 def testBlobNamedByArg(self):
1507 """Test we can add a blob with the filename coming from an entry arg"""
1508 entry_args = {
1509 'cros-ec-rw-path': 'ecrw.bin',
1510 }
Simon Glass3decfa32020-09-01 05:13:54 -06001511 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassec127af2018-07-17 13:25:39 -06001512
Simon Glass3af8e492018-07-17 13:25:40 -06001513 def testFill(self):
1514 """Test for an fill entry type"""
Simon Glass741f2d62018-10-01 12:22:30 -06001515 data = self._DoReadFile('069_fill.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001516 expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
Simon Glass3af8e492018-07-17 13:25:40 -06001517 self.assertEqual(expected, data)
1518
1519 def testFillNoSize(self):
1520 """Test for an fill entry type with no size"""
1521 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001522 self._DoReadFile('070_fill_no_size.dts')
Simon Glass3af8e492018-07-17 13:25:40 -06001523 self.assertIn("'fill' entry must have a size property",
1524 str(e.exception))
1525
Simon Glass0ef87aa2018-07-17 13:25:44 -06001526 def _HandleGbbCommand(self, pipe_list):
1527 """Fake calls to the futility utility"""
1528 if pipe_list[0][0] == 'futility':
1529 fname = pipe_list[0][-1]
1530 # Append our GBB data to the file, which will happen every time the
1531 # futility command is called.
Simon Glass1d0ebf72019-05-14 15:53:42 -06001532 with open(fname, 'ab') as fd:
Simon Glass0ef87aa2018-07-17 13:25:44 -06001533 fd.write(GBB_DATA)
1534 return command.CommandResult()
1535
1536 def testGbb(self):
1537 """Test for the Chromium OS Google Binary Block"""
1538 command.test_result = self._HandleGbbCommand
1539 entry_args = {
1540 'keydir': 'devkeys',
1541 'bmpblk': 'bmpblk.bin',
1542 }
Simon Glass741f2d62018-10-01 12:22:30 -06001543 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glass0ef87aa2018-07-17 13:25:44 -06001544
1545 # Since futility
Simon Glasse6d85ff2019-05-14 15:53:47 -06001546 expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1547 tools.GetBytes(0, 0x2180 - 16))
Simon Glass0ef87aa2018-07-17 13:25:44 -06001548 self.assertEqual(expected, data)
1549
1550 def testGbbTooSmall(self):
1551 """Test for the Chromium OS Google Binary Block being large enough"""
1552 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001553 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001554 self.assertIn("Node '/binman/gbb': GBB is too small",
1555 str(e.exception))
1556
1557 def testGbbNoSize(self):
1558 """Test for the Chromium OS Google Binary Block having a size"""
1559 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001560 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001561 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1562 str(e.exception))
1563
Simon Glass24d0d3c2018-07-17 13:25:47 -06001564 def _HandleVblockCommand(self, pipe_list):
1565 """Fake calls to the futility utility"""
1566 if pipe_list[0][0] == 'futility':
1567 fname = pipe_list[0][3]
Simon Glassa326b492018-09-14 04:57:11 -06001568 with open(fname, 'wb') as fd:
Simon Glass24d0d3c2018-07-17 13:25:47 -06001569 fd.write(VBLOCK_DATA)
1570 return command.CommandResult()
1571
1572 def testVblock(self):
1573 """Test for the Chromium OS Verified Boot Block"""
1574 command.test_result = self._HandleVblockCommand
1575 entry_args = {
1576 'keydir': 'devkeys',
1577 }
Simon Glass741f2d62018-10-01 12:22:30 -06001578 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass24d0d3c2018-07-17 13:25:47 -06001579 entry_args=entry_args)
1580 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1581 self.assertEqual(expected, data)
1582
1583 def testVblockNoContent(self):
1584 """Test we detect a vblock which has no content to sign"""
1585 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001586 self._DoReadFile('075_vblock_no_content.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001587 self.assertIn("Node '/binman/vblock': Vblock must have a 'content' "
1588 'property', str(e.exception))
1589
1590 def testVblockBadPhandle(self):
1591 """Test that we detect a vblock with an invalid phandle in contents"""
1592 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001593 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001594 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1595 '1000', str(e.exception))
1596
1597 def testVblockBadEntry(self):
1598 """Test that we detect an entry that points to a non-entry"""
1599 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001600 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001601 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1602 "'other'", str(e.exception))
1603
Simon Glassb8ef5b62018-07-17 13:25:48 -06001604 def testTpl(self):
Simon Glass2090f1e2019-08-24 07:23:00 -06001605 """Test that an image with TPL and its device tree can be created"""
Simon Glassb8ef5b62018-07-17 13:25:48 -06001606 # ELF file with a '__bss_size' symbol
Simon Glass2090f1e2019-08-24 07:23:00 -06001607 self._SetupTplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001608 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glassb8ef5b62018-07-17 13:25:48 -06001609 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1610
Simon Glass15a587c2018-07-17 13:25:51 -06001611 def testUsesPos(self):
1612 """Test that the 'pos' property cannot be used anymore"""
1613 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001614 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass15a587c2018-07-17 13:25:51 -06001615 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1616 "'pos'", str(e.exception))
1617
Simon Glassd178eab2018-09-14 04:57:08 -06001618 def testFillZero(self):
1619 """Test for an fill entry type with a size of 0"""
Simon Glass741f2d62018-10-01 12:22:30 -06001620 data = self._DoReadFile('080_fill_empty.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001621 self.assertEqual(tools.GetBytes(0, 16), data)
Simon Glassd178eab2018-09-14 04:57:08 -06001622
Simon Glass0b489362018-09-14 04:57:09 -06001623 def testTextMissing(self):
1624 """Test for a text entry type where there is no text"""
1625 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001626 self._DoReadFileDtb('066_text.dts',)
Simon Glass0b489362018-09-14 04:57:09 -06001627 self.assertIn("Node '/binman/text': No value provided for text label "
1628 "'test-id'", str(e.exception))
1629
Simon Glass35b384c2018-09-14 04:57:10 -06001630 def testPackStart16Tpl(self):
1631 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001632 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glass35b384c2018-09-14 04:57:10 -06001633 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1634
Simon Glass0bfa7b02018-09-14 04:57:12 -06001635 def testSelectImage(self):
1636 """Test that we can select which images to build"""
Simon Glasseb833d82019-04-25 21:58:34 -06001637 expected = 'Skipping images: image1'
Simon Glass0bfa7b02018-09-14 04:57:12 -06001638
Simon Glasseb833d82019-04-25 21:58:34 -06001639 # We should only get the expected message in verbose mode
Simon Glassee0c9a72019-07-08 13:18:48 -06001640 for verbosity in (0, 2):
Simon Glasseb833d82019-04-25 21:58:34 -06001641 with test_util.capture_sys_output() as (stdout, stderr):
1642 retcode = self._DoTestFile('006_dual_image.dts',
1643 verbosity=verbosity,
1644 images=['image2'])
1645 self.assertEqual(0, retcode)
1646 if verbosity:
1647 self.assertIn(expected, stdout.getvalue())
1648 else:
1649 self.assertNotIn(expected, stdout.getvalue())
1650
1651 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1652 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
Simon Glassf86a7362019-07-20 12:24:10 -06001653 self._CleanupOutputDir()
Simon Glass0bfa7b02018-09-14 04:57:12 -06001654
Simon Glass6ed45ba2018-09-14 04:57:24 -06001655 def testUpdateFdtAll(self):
1656 """Test that all device trees are updated with offset/size info"""
Simon Glass3c081312019-07-08 14:25:26 -06001657 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glass6ed45ba2018-09-14 04:57:24 -06001658
1659 base_expected = {
1660 'section:image-pos': 0,
1661 'u-boot-tpl-dtb:size': 513,
1662 'u-boot-spl-dtb:size': 513,
1663 'u-boot-spl-dtb:offset': 493,
1664 'image-pos': 0,
1665 'section/u-boot-dtb:image-pos': 0,
1666 'u-boot-spl-dtb:image-pos': 493,
1667 'section/u-boot-dtb:size': 493,
1668 'u-boot-tpl-dtb:image-pos': 1006,
1669 'section/u-boot-dtb:offset': 0,
1670 'section:size': 493,
1671 'offset': 0,
1672 'section:offset': 0,
1673 'u-boot-tpl-dtb:offset': 1006,
1674 'size': 1519
1675 }
1676
1677 # We expect three device-tree files in the output, one after the other.
1678 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1679 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1680 # main U-Boot tree. All three should have the same postions and offset.
1681 start = 0
1682 for item in ['', 'spl', 'tpl']:
1683 dtb = fdt.Fdt.FromData(data[start:])
1684 dtb.Scan()
Simon Glass12bb1a92019-07-20 12:23:51 -06001685 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
1686 ['spl', 'tpl'])
Simon Glass6ed45ba2018-09-14 04:57:24 -06001687 expected = dict(base_expected)
1688 if item:
1689 expected[item] = 0
1690 self.assertEqual(expected, props)
1691 start += dtb._fdt_obj.totalsize()
1692
1693 def testUpdateFdtOutput(self):
1694 """Test that output DTB files are updated"""
1695 try:
Simon Glass741f2d62018-10-01 12:22:30 -06001696 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glass6ed45ba2018-09-14 04:57:24 -06001697 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1698
1699 # Unfortunately, compiling a source file always results in a file
1700 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass741f2d62018-10-01 12:22:30 -06001701 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glass6ed45ba2018-09-14 04:57:24 -06001702 # binman as a file called u-boot.dtb. To fix this, copy the file
1703 # over to the expected place.
Simon Glass6ed45ba2018-09-14 04:57:24 -06001704 start = 0
1705 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1706 'tpl/u-boot-tpl.dtb.out']:
1707 dtb = fdt.Fdt.FromData(data[start:])
1708 size = dtb._fdt_obj.totalsize()
1709 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1710 outdata = tools.ReadFile(pathname)
1711 name = os.path.split(fname)[0]
1712
1713 if name:
1714 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1715 else:
1716 orig_indata = dtb_data
1717 self.assertNotEqual(outdata, orig_indata,
1718 "Expected output file '%s' be updated" % pathname)
1719 self.assertEqual(outdata, data[start:start + size],
1720 "Expected output file '%s' to match output image" %
1721 pathname)
1722 start += size
1723 finally:
1724 self._ResetDtbs()
1725
Simon Glass83d73c22018-09-14 04:57:26 -06001726 def _decompress(self, data):
Simon Glassff5c7e32019-07-08 13:18:42 -06001727 return tools.Decompress(data, 'lz4')
Simon Glass83d73c22018-09-14 04:57:26 -06001728
1729 def testCompress(self):
1730 """Test compression of blobs"""
Simon Glassac62fba2019-07-08 13:18:53 -06001731 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06001732 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass83d73c22018-09-14 04:57:26 -06001733 use_real_dtb=True, update_dtb=True)
1734 dtb = fdt.Fdt(out_dtb_fname)
1735 dtb.Scan()
1736 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1737 orig = self._decompress(data)
1738 self.assertEquals(COMPRESS_DATA, orig)
1739 expected = {
1740 'blob:uncomp-size': len(COMPRESS_DATA),
1741 'blob:size': len(data),
1742 'size': len(data),
1743 }
1744 self.assertEqual(expected, props)
1745
Simon Glass0a98b282018-09-14 04:57:28 -06001746 def testFiles(self):
1747 """Test bringing in multiple files"""
Simon Glass741f2d62018-10-01 12:22:30 -06001748 data = self._DoReadFile('084_files.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001749 self.assertEqual(FILES_DATA, data)
1750
1751 def testFilesCompress(self):
1752 """Test bringing in multiple files and compressing them"""
Simon Glassac62fba2019-07-08 13:18:53 -06001753 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06001754 data = self._DoReadFile('085_files_compress.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001755
1756 image = control.images['image']
1757 entries = image.GetEntries()
1758 files = entries['files']
Simon Glass8beb11e2019-07-08 14:25:47 -06001759 entries = files._entries
Simon Glass0a98b282018-09-14 04:57:28 -06001760
Simon Glassc6c10e72019-05-17 22:00:46 -06001761 orig = b''
Simon Glass0a98b282018-09-14 04:57:28 -06001762 for i in range(1, 3):
1763 key = '%d.dat' % i
1764 start = entries[key].image_pos
1765 len = entries[key].size
1766 chunk = data[start:start + len]
1767 orig += self._decompress(chunk)
1768
1769 self.assertEqual(FILES_DATA, orig)
1770
1771 def testFilesMissing(self):
1772 """Test missing files"""
1773 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001774 data = self._DoReadFile('086_files_none.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001775 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1776 'no files', str(e.exception))
1777
1778 def testFilesNoPattern(self):
1779 """Test missing files"""
1780 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001781 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001782 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1783 str(e.exception))
1784
Simon Glassba64a0b2018-09-14 04:57:29 -06001785 def testExpandSize(self):
1786 """Test an expanding entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001787 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
Simon Glassba64a0b2018-09-14 04:57:29 -06001788 map=True)
Simon Glassc6c10e72019-05-17 22:00:46 -06001789 expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA +
1790 MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA +
1791 tools.GetBytes(ord('c'), 8) + U_BOOT_DATA +
1792 tools.GetBytes(ord('d'), 8))
Simon Glassba64a0b2018-09-14 04:57:29 -06001793 self.assertEqual(expect, data)
1794 self.assertEqual('''ImagePos Offset Size Name
179500000000 00000000 00000028 main-section
179600000000 00000000 00000008 fill
179700000008 00000008 00000004 u-boot
17980000000c 0000000c 00000004 section
17990000000c 00000000 00000003 intel-mrc
180000000010 00000010 00000004 u-boot2
180100000014 00000014 0000000c section2
180200000014 00000000 00000008 fill
18030000001c 00000008 00000004 u-boot
180400000020 00000020 00000008 fill2
1805''', map_data)
1806
1807 def testExpandSizeBad(self):
1808 """Test an expanding entry which fails to provide contents"""
Simon Glass163ed6c2018-09-14 04:57:36 -06001809 with test_util.capture_sys_output() as (stdout, stderr):
1810 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001811 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
Simon Glassba64a0b2018-09-14 04:57:29 -06001812 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
1813 'expanding entry', str(e.exception))
1814
Simon Glasse0e5df92018-09-14 04:57:31 -06001815 def testHash(self):
1816 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001817 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06001818 use_real_dtb=True, update_dtb=True)
1819 dtb = fdt.Fdt(out_dtb_fname)
1820 dtb.Scan()
1821 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
1822 m = hashlib.sha256()
1823 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001824 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06001825
1826 def testHashNoAlgo(self):
1827 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001828 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06001829 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
1830 'hash node', str(e.exception))
1831
1832 def testHashBadAlgo(self):
1833 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001834 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06001835 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
1836 str(e.exception))
1837
1838 def testHashSection(self):
1839 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001840 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06001841 use_real_dtb=True, update_dtb=True)
1842 dtb = fdt.Fdt(out_dtb_fname)
1843 dtb.Scan()
1844 hash_node = dtb.GetNode('/binman/section/hash').props['value']
1845 m = hashlib.sha256()
1846 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001847 m.update(tools.GetBytes(ord('a'), 16))
1848 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06001849
Simon Glassf0253632018-09-14 04:57:32 -06001850 def testPackUBootTplMicrocode(self):
1851 """Test that x86 microcode can be handled correctly in TPL
1852
1853 We expect to see the following in the image, in order:
1854 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
1855 place
1856 u-boot-tpl.dtb with the microcode removed
1857 the microcode
1858 """
Simon Glass2090f1e2019-08-24 07:23:00 -06001859 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass741f2d62018-10-01 12:22:30 -06001860 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glassf0253632018-09-14 04:57:32 -06001861 U_BOOT_TPL_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001862 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
1863 b'ter somewhere in here', first)
Simon Glassf0253632018-09-14 04:57:32 -06001864
Simon Glassf8f8df62018-09-14 04:57:34 -06001865 def testFmapX86(self):
1866 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001867 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassf8f8df62018-09-14 04:57:34 -06001868 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc6c10e72019-05-17 22:00:46 -06001869 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06001870 self.assertEqual(expected, data[:32])
1871 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1872
1873 self.assertEqual(0x100, fhdr.image_size)
1874
1875 self.assertEqual(0, fentries[0].offset)
1876 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001877 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001878
1879 self.assertEqual(4, fentries[1].offset)
1880 self.assertEqual(3, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001881 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001882
1883 self.assertEqual(32, fentries[2].offset)
1884 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1885 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001886 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001887
1888 def testFmapX86Section(self):
1889 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001890 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glassc6c10e72019-05-17 22:00:46 -06001891 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06001892 self.assertEqual(expected, data[:32])
1893 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
1894
1895 self.assertEqual(0x100, fhdr.image_size)
1896
1897 self.assertEqual(0, fentries[0].offset)
1898 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001899 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001900
1901 self.assertEqual(4, fentries[1].offset)
1902 self.assertEqual(3, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001903 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001904
1905 self.assertEqual(36, fentries[2].offset)
1906 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1907 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001908 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001909
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001910 def testElf(self):
1911 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001912 self._SetupSplElf()
Simon Glass2090f1e2019-08-24 07:23:00 -06001913 self._SetupTplElf()
Simon Glass53e22bf2019-08-24 07:22:53 -06001914 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001915 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001916 data = self._DoReadFile('096_elf.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001917
Simon Glass093d1682019-07-08 13:18:25 -06001918 def testElfStrip(self):
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001919 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001920 self._SetupSplElf()
Simon Glass53e22bf2019-08-24 07:22:53 -06001921 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001922 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001923 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001924
Simon Glass163ed6c2018-09-14 04:57:36 -06001925 def testPackOverlapMap(self):
1926 """Test that overlapping regions are detected"""
1927 with test_util.capture_sys_output() as (stdout, stderr):
1928 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001929 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glass163ed6c2018-09-14 04:57:36 -06001930 map_fname = tools.GetOutputFilename('image.map')
1931 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
1932 stdout.getvalue())
1933
1934 # We should not get an inmage, but there should be a map file
1935 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
1936 self.assertTrue(os.path.exists(map_fname))
Simon Glasseb546ac2019-05-17 22:00:51 -06001937 map_data = tools.ReadFile(map_fname, binary=False)
Simon Glass163ed6c2018-09-14 04:57:36 -06001938 self.assertEqual('''ImagePos Offset Size Name
1939<none> 00000000 00000007 main-section
1940<none> 00000000 00000004 u-boot
1941<none> 00000003 00000004 u-boot-align
1942''', map_data)
1943
Simon Glass093d1682019-07-08 13:18:25 -06001944 def testPackRefCode(self):
Simon Glass3ae192c2018-10-01 12:22:31 -06001945 """Test that an image with an Intel Reference code binary works"""
1946 data = self._DoReadFile('100_intel_refcode.dts')
1947 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
1948
Simon Glass9481c802019-04-25 21:58:39 -06001949 def testSectionOffset(self):
1950 """Tests use of a section with an offset"""
1951 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
1952 map=True)
1953 self.assertEqual('''ImagePos Offset Size Name
195400000000 00000000 00000038 main-section
195500000004 00000004 00000010 section@0
195600000004 00000000 00000004 u-boot
195700000018 00000018 00000010 section@1
195800000018 00000000 00000004 u-boot
19590000002c 0000002c 00000004 section@2
19600000002c 00000000 00000004 u-boot
1961''', map_data)
1962 self.assertEqual(data,
Simon Glasse6d85ff2019-05-14 15:53:47 -06001963 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1964 tools.GetBytes(0x21, 12) +
1965 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1966 tools.GetBytes(0x61, 12) +
1967 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1968 tools.GetBytes(0x26, 8))
Simon Glass9481c802019-04-25 21:58:39 -06001969
Simon Glassac62fba2019-07-08 13:18:53 -06001970 def testCbfsRaw(self):
1971 """Test base handling of a Coreboot Filesystem (CBFS)
1972
1973 The exact contents of the CBFS is verified by similar tests in
1974 cbfs_util_test.py. The tests here merely check that the files added to
1975 the CBFS can be found in the final image.
1976 """
1977 data = self._DoReadFile('102_cbfs_raw.dts')
1978 size = 0xb0
1979
1980 cbfs = cbfs_util.CbfsReader(data)
1981 self.assertEqual(size, cbfs.rom_size)
1982
1983 self.assertIn('u-boot-dtb', cbfs.files)
1984 cfile = cbfs.files['u-boot-dtb']
1985 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
1986
1987 def testCbfsArch(self):
1988 """Test on non-x86 architecture"""
1989 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
1990 size = 0x100
1991
1992 cbfs = cbfs_util.CbfsReader(data)
1993 self.assertEqual(size, cbfs.rom_size)
1994
1995 self.assertIn('u-boot-dtb', cbfs.files)
1996 cfile = cbfs.files['u-boot-dtb']
1997 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
1998
1999 def testCbfsStage(self):
2000 """Tests handling of a Coreboot Filesystem (CBFS)"""
2001 if not elf.ELF_TOOLS:
2002 self.skipTest('Python elftools not available')
2003 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2004 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2005 size = 0xb0
2006
2007 data = self._DoReadFile('104_cbfs_stage.dts')
2008 cbfs = cbfs_util.CbfsReader(data)
2009 self.assertEqual(size, cbfs.rom_size)
2010
2011 self.assertIn('u-boot', cbfs.files)
2012 cfile = cbfs.files['u-boot']
2013 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2014
2015 def testCbfsRawCompress(self):
2016 """Test handling of compressing raw files"""
2017 self._CheckLz4()
2018 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2019 size = 0x140
2020
2021 cbfs = cbfs_util.CbfsReader(data)
2022 self.assertIn('u-boot', cbfs.files)
2023 cfile = cbfs.files['u-boot']
2024 self.assertEqual(COMPRESS_DATA, cfile.data)
2025
2026 def testCbfsBadArch(self):
2027 """Test handling of a bad architecture"""
2028 with self.assertRaises(ValueError) as e:
2029 self._DoReadFile('106_cbfs_bad_arch.dts')
2030 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2031
2032 def testCbfsNoSize(self):
2033 """Test handling of a missing size property"""
2034 with self.assertRaises(ValueError) as e:
2035 self._DoReadFile('107_cbfs_no_size.dts')
2036 self.assertIn('entry must have a size property', str(e.exception))
2037
2038 def testCbfsNoCOntents(self):
2039 """Test handling of a CBFS entry which does not provide contentsy"""
2040 with self.assertRaises(ValueError) as e:
2041 self._DoReadFile('108_cbfs_no_contents.dts')
2042 self.assertIn('Could not complete processing of contents',
2043 str(e.exception))
2044
2045 def testCbfsBadCompress(self):
2046 """Test handling of a bad architecture"""
2047 with self.assertRaises(ValueError) as e:
2048 self._DoReadFile('109_cbfs_bad_compress.dts')
2049 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2050 str(e.exception))
2051
2052 def testCbfsNamedEntries(self):
2053 """Test handling of named entries"""
2054 data = self._DoReadFile('110_cbfs_name.dts')
2055
2056 cbfs = cbfs_util.CbfsReader(data)
2057 self.assertIn('FRED', cbfs.files)
2058 cfile1 = cbfs.files['FRED']
2059 self.assertEqual(U_BOOT_DATA, cfile1.data)
2060
2061 self.assertIn('hello', cbfs.files)
2062 cfile2 = cbfs.files['hello']
2063 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2064
Simon Glassc5ac1382019-07-08 13:18:54 -06002065 def _SetupIfwi(self, fname):
2066 """Set up to run an IFWI test
2067
2068 Args:
2069 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2070 """
2071 self._SetupSplElf()
Simon Glass2090f1e2019-08-24 07:23:00 -06002072 self._SetupTplElf()
Simon Glassc5ac1382019-07-08 13:18:54 -06002073
2074 # Intel Integrated Firmware Image (IFWI) file
2075 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2076 data = fd.read()
2077 TestFunctional._MakeInputFile(fname,data)
2078
2079 def _CheckIfwi(self, data):
2080 """Check that an image with an IFWI contains the correct output
2081
2082 Args:
2083 data: Conents of output file
2084 """
2085 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
2086 if data[:0x1000] != expected_desc:
2087 self.fail('Expected descriptor binary at start of image')
2088
2089 # We expect to find the TPL wil in subpart IBBP entry IBBL
2090 image_fname = tools.GetOutputFilename('image.bin')
2091 tpl_fname = tools.GetOutputFilename('tpl.out')
2092 tools.RunIfwiTool(image_fname, tools.CMD_EXTRACT, fname=tpl_fname,
2093 subpart='IBBP', entry_name='IBBL')
2094
2095 tpl_data = tools.ReadFile(tpl_fname)
Simon Glasse95be632019-08-24 07:22:51 -06002096 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glassc5ac1382019-07-08 13:18:54 -06002097
2098 def testPackX86RomIfwi(self):
2099 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2100 self._SetupIfwi('fitimage.bin')
Simon Glass9255f3c2019-08-24 07:23:01 -06002101 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002102 self._CheckIfwi(data)
2103
2104 def testPackX86RomIfwiNoDesc(self):
2105 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2106 self._SetupIfwi('ifwi.bin')
Simon Glass9255f3c2019-08-24 07:23:01 -06002107 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002108 self._CheckIfwi(data)
2109
2110 def testPackX86RomIfwiNoData(self):
2111 """Test that an x86 ROM with IFWI handles missing data"""
2112 self._SetupIfwi('ifwi.bin')
2113 with self.assertRaises(ValueError) as e:
Simon Glass9255f3c2019-08-24 07:23:01 -06002114 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002115 self.assertIn('Could not complete processing of contents',
2116 str(e.exception))
Simon Glass53af22a2018-07-17 13:25:32 -06002117
Simon Glasse073d4e2019-07-08 13:18:56 -06002118 def testCbfsOffset(self):
2119 """Test a CBFS with files at particular offsets
2120
2121 Like all CFBS tests, this is just checking the logic that calls
2122 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2123 """
2124 data = self._DoReadFile('114_cbfs_offset.dts')
2125 size = 0x200
2126
2127 cbfs = cbfs_util.CbfsReader(data)
2128 self.assertEqual(size, cbfs.rom_size)
2129
2130 self.assertIn('u-boot', cbfs.files)
2131 cfile = cbfs.files['u-boot']
2132 self.assertEqual(U_BOOT_DATA, cfile.data)
2133 self.assertEqual(0x40, cfile.cbfs_offset)
2134
2135 self.assertIn('u-boot-dtb', cbfs.files)
2136 cfile2 = cbfs.files['u-boot-dtb']
2137 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2138 self.assertEqual(0x140, cfile2.cbfs_offset)
2139
Simon Glass086cec92019-07-08 14:25:27 -06002140 def testFdtmap(self):
2141 """Test an FDT map can be inserted in the image"""
2142 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2143 fdtmap_data = data[len(U_BOOT_DATA):]
2144 magic = fdtmap_data[:8]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002145 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass086cec92019-07-08 14:25:27 -06002146 self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
2147
2148 fdt_data = fdtmap_data[16:]
2149 dtb = fdt.Fdt.FromData(fdt_data)
2150 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002151 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass086cec92019-07-08 14:25:27 -06002152 self.assertEqual({
2153 'image-pos': 0,
2154 'offset': 0,
2155 'u-boot:offset': 0,
2156 'u-boot:size': len(U_BOOT_DATA),
2157 'u-boot:image-pos': 0,
2158 'fdtmap:image-pos': 4,
2159 'fdtmap:offset': 4,
2160 'fdtmap:size': len(fdtmap_data),
2161 'size': len(data),
2162 }, props)
2163
2164 def testFdtmapNoMatch(self):
2165 """Check handling of an FDT map when the section cannot be found"""
2166 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2167
2168 # Mangle the section name, which should cause a mismatch between the
2169 # correct FDT path and the one expected by the section
2170 image = control.images['image']
Simon Glasscf228942019-07-08 14:25:28 -06002171 image._node.path += '-suffix'
Simon Glass086cec92019-07-08 14:25:27 -06002172 entries = image.GetEntries()
2173 fdtmap = entries['fdtmap']
2174 with self.assertRaises(ValueError) as e:
2175 fdtmap._GetFdtmap()
2176 self.assertIn("Cannot locate node for path '/binman-suffix'",
2177 str(e.exception))
2178
Simon Glasscf228942019-07-08 14:25:28 -06002179 def testFdtmapHeader(self):
2180 """Test an FDT map and image header can be inserted in the image"""
2181 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2182 fdtmap_pos = len(U_BOOT_DATA)
2183 fdtmap_data = data[fdtmap_pos:]
2184 fdt_data = fdtmap_data[16:]
2185 dtb = fdt.Fdt.FromData(fdt_data)
2186 fdt_size = dtb.GetFdtObj().totalsize()
2187 hdr_data = data[-8:]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002188 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002189 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2190 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2191
2192 def testFdtmapHeaderStart(self):
2193 """Test an image header can be inserted at the image start"""
2194 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2195 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2196 hdr_data = data[:8]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002197 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002198 offset = struct.unpack('<I', hdr_data[4:])[0]
2199 self.assertEqual(fdtmap_pos, offset)
2200
2201 def testFdtmapHeaderPos(self):
2202 """Test an image header can be inserted at a chosen position"""
2203 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2204 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2205 hdr_data = data[0x80:0x88]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002206 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002207 offset = struct.unpack('<I', hdr_data[4:])[0]
2208 self.assertEqual(fdtmap_pos, offset)
2209
2210 def testHeaderMissingFdtmap(self):
2211 """Test an image header requires an fdtmap"""
2212 with self.assertRaises(ValueError) as e:
2213 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2214 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2215 str(e.exception))
2216
2217 def testHeaderNoLocation(self):
2218 """Test an image header with a no specified location is detected"""
2219 with self.assertRaises(ValueError) as e:
2220 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2221 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2222 str(e.exception))
2223
Simon Glassc52c9e72019-07-08 14:25:37 -06002224 def testEntryExpand(self):
2225 """Test expanding an entry after it is packed"""
2226 data = self._DoReadFile('121_entry_expand.dts')
Simon Glass79d3c582019-07-20 12:23:57 -06002227 self.assertEqual(b'aaa', data[:3])
2228 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2229 self.assertEqual(b'aaa', data[-3:])
Simon Glassc52c9e72019-07-08 14:25:37 -06002230
2231 def testEntryExpandBad(self):
2232 """Test expanding an entry after it is packed, twice"""
2233 with self.assertRaises(ValueError) as e:
2234 self._DoReadFile('122_entry_expand_twice.dts')
Simon Glass61ec04f2019-07-20 12:23:58 -06002235 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glassc52c9e72019-07-08 14:25:37 -06002236 str(e.exception))
2237
2238 def testEntryExpandSection(self):
2239 """Test expanding an entry within a section after it is packed"""
2240 data = self._DoReadFile('123_entry_expand_section.dts')
Simon Glass79d3c582019-07-20 12:23:57 -06002241 self.assertEqual(b'aaa', data[:3])
2242 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2243 self.assertEqual(b'aaa', data[-3:])
Simon Glassc52c9e72019-07-08 14:25:37 -06002244
Simon Glass6c223fd2019-07-08 14:25:38 -06002245 def testCompressDtb(self):
2246 """Test that compress of device-tree files is supported"""
2247 self._CheckLz4()
2248 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2249 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2250 comp_data = data[len(U_BOOT_DATA):]
2251 orig = self._decompress(comp_data)
2252 dtb = fdt.Fdt.FromData(orig)
2253 dtb.Scan()
2254 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2255 expected = {
2256 'u-boot:size': len(U_BOOT_DATA),
2257 'u-boot-dtb:uncomp-size': len(orig),
2258 'u-boot-dtb:size': len(comp_data),
2259 'size': len(data),
2260 }
2261 self.assertEqual(expected, props)
2262
Simon Glass69f7cb32019-07-08 14:25:41 -06002263 def testCbfsUpdateFdt(self):
2264 """Test that we can update the device tree with CBFS offset/size info"""
2265 self._CheckLz4()
2266 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2267 update_dtb=True)
2268 dtb = fdt.Fdt(out_dtb_fname)
2269 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002270 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass69f7cb32019-07-08 14:25:41 -06002271 del props['cbfs/u-boot:size']
2272 self.assertEqual({
2273 'offset': 0,
2274 'size': len(data),
2275 'image-pos': 0,
2276 'cbfs:offset': 0,
2277 'cbfs:size': len(data),
2278 'cbfs:image-pos': 0,
2279 'cbfs/u-boot:offset': 0x38,
2280 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2281 'cbfs/u-boot:image-pos': 0x38,
2282 'cbfs/u-boot-dtb:offset': 0xb8,
2283 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2284 'cbfs/u-boot-dtb:image-pos': 0xb8,
2285 }, props)
2286
Simon Glass8a1ad062019-07-08 14:25:42 -06002287 def testCbfsBadType(self):
2288 """Test an image header with a no specified location is detected"""
2289 with self.assertRaises(ValueError) as e:
2290 self._DoReadFile('126_cbfs_bad_type.dts')
2291 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2292
Simon Glass41b8ba02019-07-08 14:25:43 -06002293 def testList(self):
2294 """Test listing the files in an image"""
2295 self._CheckLz4()
2296 data = self._DoReadFile('127_list.dts')
2297 image = control.images['image']
2298 entries = image.BuildEntryList()
2299 self.assertEqual(7, len(entries))
2300
2301 ent = entries[0]
2302 self.assertEqual(0, ent.indent)
2303 self.assertEqual('main-section', ent.name)
2304 self.assertEqual('section', ent.etype)
2305 self.assertEqual(len(data), ent.size)
2306 self.assertEqual(0, ent.image_pos)
2307 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002308 self.assertEqual(0, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002309
2310 ent = entries[1]
2311 self.assertEqual(1, ent.indent)
2312 self.assertEqual('u-boot', ent.name)
2313 self.assertEqual('u-boot', ent.etype)
2314 self.assertEqual(len(U_BOOT_DATA), ent.size)
2315 self.assertEqual(0, ent.image_pos)
2316 self.assertEqual(None, ent.uncomp_size)
2317 self.assertEqual(0, ent.offset)
2318
2319 ent = entries[2]
2320 self.assertEqual(1, ent.indent)
2321 self.assertEqual('section', ent.name)
2322 self.assertEqual('section', ent.etype)
2323 section_size = ent.size
2324 self.assertEqual(0x100, ent.image_pos)
2325 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002326 self.assertEqual(0x100, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002327
2328 ent = entries[3]
2329 self.assertEqual(2, ent.indent)
2330 self.assertEqual('cbfs', ent.name)
2331 self.assertEqual('cbfs', ent.etype)
2332 self.assertEqual(0x400, ent.size)
2333 self.assertEqual(0x100, ent.image_pos)
2334 self.assertEqual(None, ent.uncomp_size)
2335 self.assertEqual(0, ent.offset)
2336
2337 ent = entries[4]
2338 self.assertEqual(3, ent.indent)
2339 self.assertEqual('u-boot', ent.name)
2340 self.assertEqual('u-boot', ent.etype)
2341 self.assertEqual(len(U_BOOT_DATA), ent.size)
2342 self.assertEqual(0x138, ent.image_pos)
2343 self.assertEqual(None, ent.uncomp_size)
2344 self.assertEqual(0x38, ent.offset)
2345
2346 ent = entries[5]
2347 self.assertEqual(3, ent.indent)
2348 self.assertEqual('u-boot-dtb', ent.name)
2349 self.assertEqual('text', ent.etype)
2350 self.assertGreater(len(COMPRESS_DATA), ent.size)
2351 self.assertEqual(0x178, ent.image_pos)
2352 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2353 self.assertEqual(0x78, ent.offset)
2354
2355 ent = entries[6]
2356 self.assertEqual(2, ent.indent)
2357 self.assertEqual('u-boot-dtb', ent.name)
2358 self.assertEqual('u-boot-dtb', ent.etype)
2359 self.assertEqual(0x500, ent.image_pos)
2360 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2361 dtb_size = ent.size
2362 # Compressing this data expands it since headers are added
2363 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2364 self.assertEqual(0x400, ent.offset)
2365
2366 self.assertEqual(len(data), 0x100 + section_size)
2367 self.assertEqual(section_size, 0x400 + dtb_size)
2368
Simon Glasse1925fa2019-07-08 14:25:44 -06002369 def testFindFdtmap(self):
2370 """Test locating an FDT map in an image"""
2371 self._CheckLz4()
2372 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2373 image = control.images['image']
2374 entries = image.GetEntries()
2375 entry = entries['fdtmap']
2376 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2377
2378 def testFindFdtmapMissing(self):
2379 """Test failing to locate an FDP map"""
2380 data = self._DoReadFile('005_simple.dts')
2381 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2382
Simon Glass2d260032019-07-08 14:25:45 -06002383 def testFindImageHeader(self):
2384 """Test locating a image header"""
2385 self._CheckLz4()
Simon Glassffded752019-07-08 14:25:46 -06002386 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002387 image = control.images['image']
2388 entries = image.GetEntries()
2389 entry = entries['fdtmap']
2390 # The header should point to the FDT map
2391 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2392
2393 def testFindImageHeaderStart(self):
2394 """Test locating a image header located at the start of an image"""
Simon Glassffded752019-07-08 14:25:46 -06002395 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002396 image = control.images['image']
2397 entries = image.GetEntries()
2398 entry = entries['fdtmap']
2399 # The header should point to the FDT map
2400 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2401
2402 def testFindImageHeaderMissing(self):
2403 """Test failing to locate an image header"""
2404 data = self._DoReadFile('005_simple.dts')
2405 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2406
Simon Glassffded752019-07-08 14:25:46 -06002407 def testReadImage(self):
2408 """Test reading an image and accessing its FDT map"""
2409 self._CheckLz4()
2410 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2411 image_fname = tools.GetOutputFilename('image.bin')
2412 orig_image = control.images['image']
2413 image = Image.FromFile(image_fname)
2414 self.assertEqual(orig_image.GetEntries().keys(),
2415 image.GetEntries().keys())
2416
2417 orig_entry = orig_image.GetEntries()['fdtmap']
2418 entry = image.GetEntries()['fdtmap']
2419 self.assertEquals(orig_entry.offset, entry.offset)
2420 self.assertEquals(orig_entry.size, entry.size)
2421 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2422
2423 def testReadImageNoHeader(self):
2424 """Test accessing an image's FDT map without an image header"""
2425 self._CheckLz4()
2426 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
2427 image_fname = tools.GetOutputFilename('image.bin')
2428 image = Image.FromFile(image_fname)
2429 self.assertTrue(isinstance(image, Image))
Simon Glass10f9d002019-07-20 12:23:50 -06002430 self.assertEqual('image', image.image_name[-5:])
Simon Glassffded752019-07-08 14:25:46 -06002431
2432 def testReadImageFail(self):
2433 """Test failing to read an image image's FDT map"""
2434 self._DoReadFile('005_simple.dts')
2435 image_fname = tools.GetOutputFilename('image.bin')
2436 with self.assertRaises(ValueError) as e:
2437 image = Image.FromFile(image_fname)
2438 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glasse073d4e2019-07-08 13:18:56 -06002439
Simon Glass61f564d2019-07-08 14:25:48 -06002440 def testListCmd(self):
2441 """Test listing the files in an image using an Fdtmap"""
2442 self._CheckLz4()
2443 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2444
2445 # lz4 compression size differs depending on the version
2446 image = control.images['image']
2447 entries = image.GetEntries()
2448 section_size = entries['section'].size
2449 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2450 fdtmap_offset = entries['fdtmap'].offset
2451
Simon Glassf86a7362019-07-20 12:24:10 -06002452 try:
2453 tmpdir, updated_fname = self._SetupImageInTmpdir()
2454 with test_util.capture_sys_output() as (stdout, stderr):
2455 self._DoBinman('ls', '-i', updated_fname)
2456 finally:
2457 shutil.rmtree(tmpdir)
Simon Glass61f564d2019-07-08 14:25:48 -06002458 lines = stdout.getvalue().splitlines()
2459 expected = [
2460'Name Image-pos Size Entry-type Offset Uncomp-size',
2461'----------------------------------------------------------------------',
2462'main-section 0 c00 section 0',
2463' u-boot 0 4 u-boot 0',
2464' section 100 %x section 100' % section_size,
2465' cbfs 100 400 cbfs 0',
2466' u-boot 138 4 u-boot 38',
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002467' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glass61f564d2019-07-08 14:25:48 -06002468' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002469' fdtmap %x 3bd fdtmap %x' %
Simon Glass61f564d2019-07-08 14:25:48 -06002470 (fdtmap_offset, fdtmap_offset),
2471' image-header bf8 8 image-header bf8',
2472 ]
2473 self.assertEqual(expected, lines)
2474
2475 def testListCmdFail(self):
2476 """Test failing to list an image"""
2477 self._DoReadFile('005_simple.dts')
Simon Glassf86a7362019-07-20 12:24:10 -06002478 try:
2479 tmpdir, updated_fname = self._SetupImageInTmpdir()
2480 with self.assertRaises(ValueError) as e:
2481 self._DoBinman('ls', '-i', updated_fname)
2482 finally:
2483 shutil.rmtree(tmpdir)
Simon Glass61f564d2019-07-08 14:25:48 -06002484 self.assertIn("Cannot find FDT map in image", str(e.exception))
2485
2486 def _RunListCmd(self, paths, expected):
2487 """List out entries and check the result
2488
2489 Args:
2490 paths: List of paths to pass to the list command
2491 expected: Expected list of filenames to be returned, in order
2492 """
2493 self._CheckLz4()
2494 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2495 image_fname = tools.GetOutputFilename('image.bin')
2496 image = Image.FromFile(image_fname)
2497 lines = image.GetListEntries(paths)[1]
2498 files = [line[0].strip() for line in lines[1:]]
2499 self.assertEqual(expected, files)
2500
2501 def testListCmdSection(self):
2502 """Test listing the files in a section"""
2503 self._RunListCmd(['section'],
2504 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2505
2506 def testListCmdFile(self):
2507 """Test listing a particular file"""
2508 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2509
2510 def testListCmdWildcard(self):
2511 """Test listing a wildcarded file"""
2512 self._RunListCmd(['*boot*'],
2513 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2514
2515 def testListCmdWildcardMulti(self):
2516 """Test listing a wildcarded file"""
2517 self._RunListCmd(['*cb*', '*head*'],
2518 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2519
2520 def testListCmdEmpty(self):
2521 """Test listing a wildcarded file"""
2522 self._RunListCmd(['nothing'], [])
2523
2524 def testListCmdPath(self):
2525 """Test listing the files in a sub-entry of a section"""
2526 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2527
Simon Glassf667e452019-07-08 14:25:50 -06002528 def _RunExtractCmd(self, entry_name, decomp=True):
2529 """Extract an entry from an image
2530
2531 Args:
2532 entry_name: Entry name to extract
2533 decomp: True to decompress the data if compressed, False to leave
2534 it in its raw uncompressed format
2535
2536 Returns:
2537 data from entry
2538 """
2539 self._CheckLz4()
2540 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2541 image_fname = tools.GetOutputFilename('image.bin')
2542 return control.ReadEntry(image_fname, entry_name, decomp)
2543
2544 def testExtractSimple(self):
2545 """Test extracting a single file"""
2546 data = self._RunExtractCmd('u-boot')
2547 self.assertEqual(U_BOOT_DATA, data)
2548
Simon Glass71ce0ba2019-07-08 14:25:52 -06002549 def testExtractSection(self):
2550 """Test extracting the files in a section"""
2551 data = self._RunExtractCmd('section')
2552 cbfs_data = data[:0x400]
2553 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002554 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass71ce0ba2019-07-08 14:25:52 -06002555 dtb_data = data[0x400:]
2556 dtb = self._decompress(dtb_data)
2557 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2558
2559 def testExtractCompressed(self):
2560 """Test extracting compressed data"""
2561 data = self._RunExtractCmd('section/u-boot-dtb')
2562 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2563
2564 def testExtractRaw(self):
2565 """Test extracting compressed data without decompressing it"""
2566 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2567 dtb = self._decompress(data)
2568 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2569
2570 def testExtractCbfs(self):
2571 """Test extracting CBFS data"""
2572 data = self._RunExtractCmd('section/cbfs/u-boot')
2573 self.assertEqual(U_BOOT_DATA, data)
2574
2575 def testExtractCbfsCompressed(self):
2576 """Test extracting CBFS compressed data"""
2577 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2578 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2579
2580 def testExtractCbfsRaw(self):
2581 """Test extracting CBFS compressed data without decompressing it"""
2582 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Simon Glasseb0f4a42019-07-20 12:24:06 -06002583 dtb = tools.Decompress(data, 'lzma', with_header=False)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002584 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2585
Simon Glassf667e452019-07-08 14:25:50 -06002586 def testExtractBadEntry(self):
2587 """Test extracting a bad section path"""
2588 with self.assertRaises(ValueError) as e:
2589 self._RunExtractCmd('section/does-not-exist')
2590 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2591 str(e.exception))
2592
2593 def testExtractMissingFile(self):
2594 """Test extracting file that does not exist"""
2595 with self.assertRaises(IOError) as e:
2596 control.ReadEntry('missing-file', 'name')
2597
2598 def testExtractBadFile(self):
2599 """Test extracting an invalid file"""
2600 fname = os.path.join(self._indir, 'badfile')
2601 tools.WriteFile(fname, b'')
2602 with self.assertRaises(ValueError) as e:
2603 control.ReadEntry(fname, 'name')
2604
Simon Glass71ce0ba2019-07-08 14:25:52 -06002605 def testExtractCmd(self):
2606 """Test extracting a file fron an image on the command line"""
2607 self._CheckLz4()
2608 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass71ce0ba2019-07-08 14:25:52 -06002609 fname = os.path.join(self._indir, 'output.extact')
Simon Glassf86a7362019-07-20 12:24:10 -06002610 try:
2611 tmpdir, updated_fname = self._SetupImageInTmpdir()
2612 with test_util.capture_sys_output() as (stdout, stderr):
2613 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2614 '-f', fname)
2615 finally:
2616 shutil.rmtree(tmpdir)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002617 data = tools.ReadFile(fname)
2618 self.assertEqual(U_BOOT_DATA, data)
2619
2620 def testExtractOneEntry(self):
2621 """Test extracting a single entry fron an image """
2622 self._CheckLz4()
2623 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2624 image_fname = tools.GetOutputFilename('image.bin')
2625 fname = os.path.join(self._indir, 'output.extact')
2626 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
2627 data = tools.ReadFile(fname)
2628 self.assertEqual(U_BOOT_DATA, data)
2629
2630 def _CheckExtractOutput(self, decomp):
2631 """Helper to test file output with and without decompression
2632
2633 Args:
2634 decomp: True to decompress entry data, False to output it raw
2635 """
2636 def _CheckPresent(entry_path, expect_data, expect_size=None):
2637 """Check and remove expected file
2638
2639 This checks the data/size of a file and removes the file both from
2640 the outfiles set and from the output directory. Once all files are
2641 processed, both the set and directory should be empty.
2642
2643 Args:
2644 entry_path: Entry path
2645 expect_data: Data to expect in file, or None to skip check
2646 expect_size: Size of data to expect in file, or None to skip
2647 """
2648 path = os.path.join(outdir, entry_path)
2649 data = tools.ReadFile(path)
2650 os.remove(path)
2651 if expect_data:
2652 self.assertEqual(expect_data, data)
2653 elif expect_size:
2654 self.assertEqual(expect_size, len(data))
2655 outfiles.remove(path)
2656
2657 def _CheckDirPresent(name):
2658 """Remove expected directory
2659
2660 This gives an error if the directory does not exist as expected
2661
2662 Args:
2663 name: Name of directory to remove
2664 """
2665 path = os.path.join(outdir, name)
2666 os.rmdir(path)
2667
2668 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2669 image_fname = tools.GetOutputFilename('image.bin')
2670 outdir = os.path.join(self._indir, 'extract')
2671 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2672
2673 # Create a set of all file that were output (should be 9)
2674 outfiles = set()
2675 for root, dirs, files in os.walk(outdir):
2676 outfiles |= set([os.path.join(root, fname) for fname in files])
2677 self.assertEqual(9, len(outfiles))
2678 self.assertEqual(9, len(einfos))
2679
2680 image = control.images['image']
2681 entries = image.GetEntries()
2682
2683 # Check the 9 files in various ways
2684 section = entries['section']
2685 section_entries = section.GetEntries()
2686 cbfs_entries = section_entries['cbfs'].GetEntries()
2687 _CheckPresent('u-boot', U_BOOT_DATA)
2688 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
2689 dtb_len = EXTRACT_DTB_SIZE
2690 if not decomp:
2691 dtb_len = cbfs_entries['u-boot-dtb'].size
2692 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
2693 if not decomp:
2694 dtb_len = section_entries['u-boot-dtb'].size
2695 _CheckPresent('section/u-boot-dtb', None, dtb_len)
2696
2697 fdtmap = entries['fdtmap']
2698 _CheckPresent('fdtmap', fdtmap.data)
2699 hdr = entries['image-header']
2700 _CheckPresent('image-header', hdr.data)
2701
2702 _CheckPresent('section/root', section.data)
2703 cbfs = section_entries['cbfs']
2704 _CheckPresent('section/cbfs/root', cbfs.data)
2705 data = tools.ReadFile(image_fname)
2706 _CheckPresent('root', data)
2707
2708 # There should be no files left. Remove all the directories to check.
2709 # If there are any files/dirs remaining, one of these checks will fail.
2710 self.assertEqual(0, len(outfiles))
2711 _CheckDirPresent('section/cbfs')
2712 _CheckDirPresent('section')
2713 _CheckDirPresent('')
2714 self.assertFalse(os.path.exists(outdir))
2715
2716 def testExtractAllEntries(self):
2717 """Test extracting all entries"""
2718 self._CheckLz4()
2719 self._CheckExtractOutput(decomp=True)
2720
2721 def testExtractAllEntriesRaw(self):
2722 """Test extracting all entries without decompressing them"""
2723 self._CheckLz4()
2724 self._CheckExtractOutput(decomp=False)
2725
2726 def testExtractSelectedEntries(self):
2727 """Test extracting some entries"""
2728 self._CheckLz4()
2729 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2730 image_fname = tools.GetOutputFilename('image.bin')
2731 outdir = os.path.join(self._indir, 'extract')
2732 einfos = control.ExtractEntries(image_fname, None, outdir,
2733 ['*cb*', '*head*'])
2734
2735 # File output is tested by testExtractAllEntries(), so just check that
2736 # the expected entries are selected
2737 names = [einfo.name for einfo in einfos]
2738 self.assertEqual(names,
2739 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2740
2741 def testExtractNoEntryPaths(self):
2742 """Test extracting some entries"""
2743 self._CheckLz4()
2744 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2745 image_fname = tools.GetOutputFilename('image.bin')
2746 with self.assertRaises(ValueError) as e:
2747 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassbb5edc12019-07-20 12:24:14 -06002748 self.assertIn('Must specify an entry path to write with -f',
Simon Glass71ce0ba2019-07-08 14:25:52 -06002749 str(e.exception))
2750
2751 def testExtractTooManyEntryPaths(self):
2752 """Test extracting some entries"""
2753 self._CheckLz4()
2754 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2755 image_fname = tools.GetOutputFilename('image.bin')
2756 with self.assertRaises(ValueError) as e:
2757 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassbb5edc12019-07-20 12:24:14 -06002758 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass71ce0ba2019-07-08 14:25:52 -06002759 str(e.exception))
2760
Simon Glasse2705fa2019-07-08 14:25:53 -06002761 def testPackAlignSection(self):
2762 """Test that sections can have alignment"""
2763 self._DoReadFile('131_pack_align_section.dts')
2764
2765 self.assertIn('image', control.images)
2766 image = control.images['image']
2767 entries = image.GetEntries()
2768 self.assertEqual(3, len(entries))
2769
2770 # First u-boot
2771 self.assertIn('u-boot', entries)
2772 entry = entries['u-boot']
2773 self.assertEqual(0, entry.offset)
2774 self.assertEqual(0, entry.image_pos)
2775 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2776 self.assertEqual(len(U_BOOT_DATA), entry.size)
2777
2778 # Section0
2779 self.assertIn('section0', entries)
2780 section0 = entries['section0']
2781 self.assertEqual(0x10, section0.offset)
2782 self.assertEqual(0x10, section0.image_pos)
2783 self.assertEqual(len(U_BOOT_DATA), section0.size)
2784
2785 # Second u-boot
2786 section_entries = section0.GetEntries()
2787 self.assertIn('u-boot', section_entries)
2788 entry = section_entries['u-boot']
2789 self.assertEqual(0, entry.offset)
2790 self.assertEqual(0x10, entry.image_pos)
2791 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2792 self.assertEqual(len(U_BOOT_DATA), entry.size)
2793
2794 # Section1
2795 self.assertIn('section1', entries)
2796 section1 = entries['section1']
2797 self.assertEqual(0x14, section1.offset)
2798 self.assertEqual(0x14, section1.image_pos)
2799 self.assertEqual(0x20, section1.size)
2800
2801 # Second u-boot
2802 section_entries = section1.GetEntries()
2803 self.assertIn('u-boot', section_entries)
2804 entry = section_entries['u-boot']
2805 self.assertEqual(0, entry.offset)
2806 self.assertEqual(0x14, entry.image_pos)
2807 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2808 self.assertEqual(len(U_BOOT_DATA), entry.size)
2809
2810 # Section2
2811 self.assertIn('section2', section_entries)
2812 section2 = section_entries['section2']
2813 self.assertEqual(0x4, section2.offset)
2814 self.assertEqual(0x18, section2.image_pos)
2815 self.assertEqual(4, section2.size)
2816
2817 # Third u-boot
2818 section_entries = section2.GetEntries()
2819 self.assertIn('u-boot', section_entries)
2820 entry = section_entries['u-boot']
2821 self.assertEqual(0, entry.offset)
2822 self.assertEqual(0x18, entry.image_pos)
2823 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2824 self.assertEqual(len(U_BOOT_DATA), entry.size)
2825
Simon Glass51014aa2019-07-20 12:23:56 -06002826 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
2827 dts='132_replace.dts'):
Simon Glass10f9d002019-07-20 12:23:50 -06002828 """Replace an entry in an image
2829
2830 This writes the entry data to update it, then opens the updated file and
2831 returns the value that it now finds there.
2832
2833 Args:
2834 entry_name: Entry name to replace
2835 data: Data to replace it with
2836 decomp: True to compress the data if needed, False if data is
2837 already compressed so should be used as is
Simon Glass51014aa2019-07-20 12:23:56 -06002838 allow_resize: True to allow entries to change size, False to raise
2839 an exception
Simon Glass10f9d002019-07-20 12:23:50 -06002840
2841 Returns:
2842 Tuple:
2843 data from entry
2844 data from fdtmap (excluding header)
Simon Glass51014aa2019-07-20 12:23:56 -06002845 Image object that was modified
Simon Glass10f9d002019-07-20 12:23:50 -06002846 """
Simon Glass51014aa2019-07-20 12:23:56 -06002847 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass10f9d002019-07-20 12:23:50 -06002848 update_dtb=True)[1]
2849
2850 self.assertIn('image', control.images)
2851 image = control.images['image']
2852 entries = image.GetEntries()
2853 orig_dtb_data = entries['u-boot-dtb'].data
2854 orig_fdtmap_data = entries['fdtmap'].data
2855
2856 image_fname = tools.GetOutputFilename('image.bin')
2857 updated_fname = tools.GetOutputFilename('image-updated.bin')
2858 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
Simon Glass51014aa2019-07-20 12:23:56 -06002859 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
2860 allow_resize)
Simon Glass10f9d002019-07-20 12:23:50 -06002861 data = control.ReadEntry(updated_fname, entry_name, decomp)
2862
Simon Glass51014aa2019-07-20 12:23:56 -06002863 # The DT data should not change unless resized:
2864 if not allow_resize:
2865 new_dtb_data = entries['u-boot-dtb'].data
2866 self.assertEqual(new_dtb_data, orig_dtb_data)
2867 new_fdtmap_data = entries['fdtmap'].data
2868 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass10f9d002019-07-20 12:23:50 -06002869
Simon Glass51014aa2019-07-20 12:23:56 -06002870 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass10f9d002019-07-20 12:23:50 -06002871
2872 def testReplaceSimple(self):
2873 """Test replacing a single file"""
2874 expected = b'x' * len(U_BOOT_DATA)
Simon Glass51014aa2019-07-20 12:23:56 -06002875 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
2876 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06002877 self.assertEqual(expected, data)
2878
2879 # Test that the state looks right. There should be an FDT for the fdtmap
2880 # that we jsut read back in, and it should match what we find in the
2881 # 'control' tables. Checking for an FDT that does not exist should
2882 # return None.
2883 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glass51014aa2019-07-20 12:23:56 -06002884 self.assertIsNotNone(path)
Simon Glass10f9d002019-07-20 12:23:50 -06002885 self.assertEqual(expected_fdtmap, fdtmap)
2886
2887 dtb = state.GetFdtForEtype('fdtmap')
2888 self.assertEqual(dtb.GetContents(), fdtmap)
2889
2890 missing_path, missing_fdtmap = state.GetFdtContents('missing')
2891 self.assertIsNone(missing_path)
2892 self.assertIsNone(missing_fdtmap)
2893
2894 missing_dtb = state.GetFdtForEtype('missing')
2895 self.assertIsNone(missing_dtb)
2896
2897 self.assertEqual('/binman', state.fdt_path_prefix)
2898
2899 def testReplaceResizeFail(self):
2900 """Test replacing a file by something larger"""
2901 expected = U_BOOT_DATA + b'x'
2902 with self.assertRaises(ValueError) as e:
Simon Glass51014aa2019-07-20 12:23:56 -06002903 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
2904 dts='139_replace_repack.dts')
Simon Glass10f9d002019-07-20 12:23:50 -06002905 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
2906 str(e.exception))
2907
2908 def testReplaceMulti(self):
2909 """Test replacing entry data where multiple images are generated"""
2910 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
2911 update_dtb=True)[0]
2912 expected = b'x' * len(U_BOOT_DATA)
2913 updated_fname = tools.GetOutputFilename('image-updated.bin')
2914 tools.WriteFile(updated_fname, data)
2915 entry_name = 'u-boot'
Simon Glass51014aa2019-07-20 12:23:56 -06002916 control.WriteEntry(updated_fname, entry_name, expected,
2917 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06002918 data = control.ReadEntry(updated_fname, entry_name)
2919 self.assertEqual(expected, data)
2920
2921 # Check the state looks right.
2922 self.assertEqual('/binman/image', state.fdt_path_prefix)
2923
2924 # Now check we can write the first image
2925 image_fname = tools.GetOutputFilename('first-image.bin')
2926 updated_fname = tools.GetOutputFilename('first-updated.bin')
2927 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
2928 entry_name = 'u-boot'
Simon Glass51014aa2019-07-20 12:23:56 -06002929 control.WriteEntry(updated_fname, entry_name, expected,
2930 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06002931 data = control.ReadEntry(updated_fname, entry_name)
2932 self.assertEqual(expected, data)
2933
2934 # Check the state looks right.
2935 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass8beb11e2019-07-08 14:25:47 -06002936
Simon Glass12bb1a92019-07-20 12:23:51 -06002937 def testUpdateFdtAllRepack(self):
2938 """Test that all device trees are updated with offset/size info"""
2939 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
2940 SECTION_SIZE = 0x300
2941 DTB_SIZE = 602
2942 FDTMAP_SIZE = 608
2943 base_expected = {
2944 'offset': 0,
2945 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
2946 'image-pos': 0,
2947 'section:offset': 0,
2948 'section:size': SECTION_SIZE,
2949 'section:image-pos': 0,
2950 'section/u-boot-dtb:offset': 4,
2951 'section/u-boot-dtb:size': 636,
2952 'section/u-boot-dtb:image-pos': 4,
2953 'u-boot-spl-dtb:offset': SECTION_SIZE,
2954 'u-boot-spl-dtb:size': DTB_SIZE,
2955 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
2956 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
2957 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
2958 'u-boot-tpl-dtb:size': DTB_SIZE,
2959 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
2960 'fdtmap:size': FDTMAP_SIZE,
2961 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
2962 }
2963 main_expected = {
2964 'section:orig-size': SECTION_SIZE,
2965 'section/u-boot-dtb:orig-offset': 4,
2966 }
2967
2968 # We expect three device-tree files in the output, with the first one
2969 # within a fixed-size section.
2970 # Read them in sequence. We look for an 'spl' property in the SPL tree,
2971 # and 'tpl' in the TPL tree, to make sure they are distinct from the
2972 # main U-Boot tree. All three should have the same positions and offset
2973 # except that the main tree should include the main_expected properties
2974 start = 4
2975 for item in ['', 'spl', 'tpl', None]:
2976 if item is None:
2977 start += 16 # Move past fdtmap header
2978 dtb = fdt.Fdt.FromData(data[start:])
2979 dtb.Scan()
2980 props = self._GetPropTree(dtb,
2981 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
2982 prefix='/' if item is None else '/binman/')
2983 expected = dict(base_expected)
2984 if item:
2985 expected[item] = 0
2986 else:
2987 # Main DTB and fdtdec should include the 'orig-' properties
2988 expected.update(main_expected)
2989 # Helpful for debugging:
2990 #for prop in sorted(props):
2991 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
2992 self.assertEqual(expected, props)
2993 if item == '':
2994 start = SECTION_SIZE
2995 else:
2996 start += dtb._fdt_obj.totalsize()
2997
Simon Glasseba1f0c2019-07-20 12:23:55 -06002998 def testFdtmapHeaderMiddle(self):
2999 """Test an FDT map in the middle of an image when it should be at end"""
3000 with self.assertRaises(ValueError) as e:
3001 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3002 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3003 str(e.exception))
3004
3005 def testFdtmapHeaderStartBad(self):
3006 """Test an FDT map in middle of an image when it should be at start"""
3007 with self.assertRaises(ValueError) as e:
3008 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3009 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3010 str(e.exception))
3011
3012 def testFdtmapHeaderEndBad(self):
3013 """Test an FDT map at the start of an image when it should be at end"""
3014 with self.assertRaises(ValueError) as e:
3015 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3016 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3017 str(e.exception))
3018
3019 def testFdtmapHeaderNoSize(self):
3020 """Test an image header at the end of an image with undefined size"""
3021 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3022
Simon Glass51014aa2019-07-20 12:23:56 -06003023 def testReplaceResize(self):
3024 """Test replacing a single file in an entry with a larger file"""
3025 expected = U_BOOT_DATA + b'x'
3026 data, _, image = self._RunReplaceCmd('u-boot', expected,
3027 dts='139_replace_repack.dts')
3028 self.assertEqual(expected, data)
3029
3030 entries = image.GetEntries()
3031 dtb_data = entries['u-boot-dtb'].data
3032 dtb = fdt.Fdt.FromData(dtb_data)
3033 dtb.Scan()
3034
3035 # The u-boot section should now be larger in the dtb
3036 node = dtb.GetNode('/binman/u-boot')
3037 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3038
3039 # Same for the fdtmap
3040 fdata = entries['fdtmap'].data
3041 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3042 fdtb.Scan()
3043 fnode = fdtb.GetNode('/u-boot')
3044 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3045
3046 def testReplaceResizeNoRepack(self):
3047 """Test replacing an entry with a larger file when not allowed"""
3048 expected = U_BOOT_DATA + b'x'
3049 with self.assertRaises(ValueError) as e:
3050 self._RunReplaceCmd('u-boot', expected)
3051 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3052 str(e.exception))
3053
Simon Glass61ec04f2019-07-20 12:23:58 -06003054 def testEntryShrink(self):
3055 """Test contracting an entry after it is packed"""
3056 try:
3057 state.SetAllowEntryContraction(True)
3058 data = self._DoReadFileDtb('140_entry_shrink.dts',
3059 update_dtb=True)[0]
3060 finally:
3061 state.SetAllowEntryContraction(False)
3062 self.assertEqual(b'a', data[:1])
3063 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3064 self.assertEqual(b'a', data[-1:])
3065
3066 def testEntryShrinkFail(self):
3067 """Test not being allowed to contract an entry after it is packed"""
3068 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3069
3070 # In this case there is a spare byte at the end of the data. The size of
3071 # the contents is only 1 byte but we still have the size before it
3072 # shrunk.
3073 self.assertEqual(b'a\0', data[:2])
3074 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3075 self.assertEqual(b'a\0', data[-2:])
3076
Simon Glass27145fd2019-07-20 12:24:01 -06003077 def testDescriptorOffset(self):
3078 """Test that the Intel descriptor is always placed at at the start"""
3079 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3080 image = control.images['image']
3081 entries = image.GetEntries()
3082 desc = entries['intel-descriptor']
3083 self.assertEqual(0xff800000, desc.offset);
3084 self.assertEqual(0xff800000, desc.image_pos);
3085
Simon Glasseb0f4a42019-07-20 12:24:06 -06003086 def testReplaceCbfs(self):
3087 """Test replacing a single file in CBFS without changing the size"""
3088 self._CheckLz4()
3089 expected = b'x' * len(U_BOOT_DATA)
3090 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3091 updated_fname = tools.GetOutputFilename('image-updated.bin')
3092 tools.WriteFile(updated_fname, data)
3093 entry_name = 'section/cbfs/u-boot'
3094 control.WriteEntry(updated_fname, entry_name, expected,
3095 allow_resize=True)
3096 data = control.ReadEntry(updated_fname, entry_name)
3097 self.assertEqual(expected, data)
3098
3099 def testReplaceResizeCbfs(self):
3100 """Test replacing a single file in CBFS with one of a different size"""
3101 self._CheckLz4()
3102 expected = U_BOOT_DATA + b'x'
3103 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3104 updated_fname = tools.GetOutputFilename('image-updated.bin')
3105 tools.WriteFile(updated_fname, data)
3106 entry_name = 'section/cbfs/u-boot'
3107 control.WriteEntry(updated_fname, entry_name, expected,
3108 allow_resize=True)
3109 data = control.ReadEntry(updated_fname, entry_name)
3110 self.assertEqual(expected, data)
3111
Simon Glassa6cb9952019-07-20 12:24:15 -06003112 def _SetupForReplace(self):
3113 """Set up some files to use to replace entries
3114
3115 This generates an image, copies it to a new file, extracts all the files
3116 in it and updates some of them
3117
3118 Returns:
3119 List
3120 Image filename
3121 Output directory
3122 Expected values for updated entries, each a string
3123 """
3124 data = self._DoReadFileRealDtb('143_replace_all.dts')
3125
3126 updated_fname = tools.GetOutputFilename('image-updated.bin')
3127 tools.WriteFile(updated_fname, data)
3128
3129 outdir = os.path.join(self._indir, 'extract')
3130 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3131
3132 expected1 = b'x' + U_BOOT_DATA + b'y'
3133 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3134 tools.WriteFile(u_boot_fname1, expected1)
3135
3136 expected2 = b'a' + U_BOOT_DATA + b'b'
3137 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
3138 tools.WriteFile(u_boot_fname2, expected2)
3139
3140 expected_text = b'not the same text'
3141 text_fname = os.path.join(outdir, 'text')
3142 tools.WriteFile(text_fname, expected_text)
3143
3144 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3145 dtb = fdt.FdtScan(dtb_fname)
3146 node = dtb.GetNode('/binman/text')
3147 node.AddString('my-property', 'the value')
3148 dtb.Sync(auto_resize=True)
3149 dtb.Flush()
3150
3151 return updated_fname, outdir, expected1, expected2, expected_text
3152
3153 def _CheckReplaceMultiple(self, entry_paths):
3154 """Handle replacing the contents of multiple entries
3155
3156 Args:
3157 entry_paths: List of entry paths to replace
3158
3159 Returns:
3160 List
3161 Dict of entries in the image:
3162 key: Entry name
3163 Value: Entry object
3164 Expected values for updated entries, each a string
3165 """
3166 updated_fname, outdir, expected1, expected2, expected_text = (
3167 self._SetupForReplace())
3168 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3169
3170 image = Image.FromFile(updated_fname)
3171 image.LoadData()
3172 return image.GetEntries(), expected1, expected2, expected_text
3173
3174 def testReplaceAll(self):
3175 """Test replacing the contents of all entries"""
3176 entries, expected1, expected2, expected_text = (
3177 self._CheckReplaceMultiple([]))
3178 data = entries['u-boot'].data
3179 self.assertEqual(expected1, data)
3180
3181 data = entries['u-boot2'].data
3182 self.assertEqual(expected2, data)
3183
3184 data = entries['text'].data
3185 self.assertEqual(expected_text, data)
3186
3187 # Check that the device tree is updated
3188 data = entries['u-boot-dtb'].data
3189 dtb = fdt.Fdt.FromData(data)
3190 dtb.Scan()
3191 node = dtb.GetNode('/binman/text')
3192 self.assertEqual('the value', node.props['my-property'].value)
3193
3194 def testReplaceSome(self):
3195 """Test replacing the contents of a few entries"""
3196 entries, expected1, expected2, expected_text = (
3197 self._CheckReplaceMultiple(['u-boot2', 'text']))
3198
3199 # This one should not change
3200 data = entries['u-boot'].data
3201 self.assertEqual(U_BOOT_DATA, data)
3202
3203 data = entries['u-boot2'].data
3204 self.assertEqual(expected2, data)
3205
3206 data = entries['text'].data
3207 self.assertEqual(expected_text, data)
3208
3209 def testReplaceCmd(self):
3210 """Test replacing a file fron an image on the command line"""
3211 self._DoReadFileRealDtb('143_replace_all.dts')
3212
3213 try:
3214 tmpdir, updated_fname = self._SetupImageInTmpdir()
3215
3216 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3217 expected = b'x' * len(U_BOOT_DATA)
3218 tools.WriteFile(fname, expected)
3219
3220 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
3221 data = tools.ReadFile(updated_fname)
3222 self.assertEqual(expected, data[:len(expected)])
3223 map_fname = os.path.join(tmpdir, 'image-updated.map')
3224 self.assertFalse(os.path.exists(map_fname))
3225 finally:
3226 shutil.rmtree(tmpdir)
3227
3228 def testReplaceCmdSome(self):
3229 """Test replacing some files fron an image on the command line"""
3230 updated_fname, outdir, expected1, expected2, expected_text = (
3231 self._SetupForReplace())
3232
3233 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3234 'u-boot2', 'text')
3235
3236 tools.PrepareOutputDir(None)
3237 image = Image.FromFile(updated_fname)
3238 image.LoadData()
3239 entries = image.GetEntries()
3240
3241 # This one should not change
3242 data = entries['u-boot'].data
3243 self.assertEqual(U_BOOT_DATA, data)
3244
3245 data = entries['u-boot2'].data
3246 self.assertEqual(expected2, data)
3247
3248 data = entries['text'].data
3249 self.assertEqual(expected_text, data)
3250
3251 def testReplaceMissing(self):
3252 """Test replacing entries where the file is missing"""
3253 updated_fname, outdir, expected1, expected2, expected_text = (
3254 self._SetupForReplace())
3255
3256 # Remove one of the files, to generate a warning
3257 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3258 os.remove(u_boot_fname1)
3259
3260 with test_util.capture_sys_output() as (stdout, stderr):
3261 control.ReplaceEntries(updated_fname, None, outdir, [])
3262 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass38fdb4c2020-07-09 18:39:39 -06003263 stderr.getvalue())
Simon Glassa6cb9952019-07-20 12:24:15 -06003264
3265 def testReplaceCmdMap(self):
3266 """Test replacing a file fron an image on the command line"""
3267 self._DoReadFileRealDtb('143_replace_all.dts')
3268
3269 try:
3270 tmpdir, updated_fname = self._SetupImageInTmpdir()
3271
3272 fname = os.path.join(self._indir, 'update-u-boot.bin')
3273 expected = b'x' * len(U_BOOT_DATA)
3274 tools.WriteFile(fname, expected)
3275
3276 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3277 '-f', fname, '-m')
3278 map_fname = os.path.join(tmpdir, 'image-updated.map')
3279 self.assertTrue(os.path.exists(map_fname))
3280 finally:
3281 shutil.rmtree(tmpdir)
3282
3283 def testReplaceNoEntryPaths(self):
3284 """Test replacing an entry without an entry path"""
3285 self._DoReadFileRealDtb('143_replace_all.dts')
3286 image_fname = tools.GetOutputFilename('image.bin')
3287 with self.assertRaises(ValueError) as e:
3288 control.ReplaceEntries(image_fname, 'fname', None, [])
3289 self.assertIn('Must specify an entry path to read with -f',
3290 str(e.exception))
3291
3292 def testReplaceTooManyEntryPaths(self):
3293 """Test extracting some entries"""
3294 self._DoReadFileRealDtb('143_replace_all.dts')
3295 image_fname = tools.GetOutputFilename('image.bin')
3296 with self.assertRaises(ValueError) as e:
3297 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3298 self.assertIn('Must specify exactly one entry path to write with -f',
3299 str(e.exception))
3300
Simon Glass2250ee62019-08-24 07:22:48 -06003301 def testPackReset16(self):
3302 """Test that an image with an x86 reset16 region can be created"""
3303 data = self._DoReadFile('144_x86_reset16.dts')
3304 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3305
3306 def testPackReset16Spl(self):
3307 """Test that an image with an x86 reset16-spl region can be created"""
3308 data = self._DoReadFile('145_x86_reset16_spl.dts')
3309 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3310
3311 def testPackReset16Tpl(self):
3312 """Test that an image with an x86 reset16-tpl region can be created"""
3313 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3314 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3315
Simon Glass5af12072019-08-24 07:22:50 -06003316 def testPackIntelFit(self):
3317 """Test that an image with an Intel FIT and pointer can be created"""
3318 data = self._DoReadFile('147_intel_fit.dts')
3319 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3320 fit = data[16:32];
3321 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3322 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3323
3324 image = control.images['image']
3325 entries = image.GetEntries()
3326 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3327 self.assertEqual(expected_ptr, ptr)
3328
3329 def testPackIntelFitMissing(self):
3330 """Test detection of a FIT pointer with not FIT region"""
3331 with self.assertRaises(ValueError) as e:
3332 self._DoReadFile('148_intel_fit_missing.dts')
3333 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3334 str(e.exception))
3335
Simon Glass7c150132019-11-06 17:22:44 -07003336 def _CheckSymbolsTplSection(self, dts, expected_vals):
3337 data = self._DoReadFile(dts)
3338 sym_values = struct.pack('<LQLL', *expected_vals)
Simon Glass2090f1e2019-08-24 07:23:00 -06003339 upto1 = 4 + len(U_BOOT_SPL_DATA)
Simon Glassb87064c2019-08-24 07:23:05 -06003340 expected1 = tools.GetBytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[20:]
Simon Glass2090f1e2019-08-24 07:23:00 -06003341 self.assertEqual(expected1, data[:upto1])
3342
3343 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Simon Glassb87064c2019-08-24 07:23:05 -06003344 expected2 = tools.GetBytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[20:]
Simon Glass2090f1e2019-08-24 07:23:00 -06003345 self.assertEqual(expected2, data[upto1:upto2])
3346
Simon Glasseb0086f2019-08-24 07:23:04 -06003347 upto3 = 0x34 + len(U_BOOT_DATA)
3348 expected3 = tools.GetBytes(0xff, 1) + U_BOOT_DATA
Simon Glass2090f1e2019-08-24 07:23:00 -06003349 self.assertEqual(expected3, data[upto2:upto3])
3350
Simon Glassb87064c2019-08-24 07:23:05 -06003351 expected4 = sym_values + U_BOOT_TPL_DATA[20:]
Simon Glass7c150132019-11-06 17:22:44 -07003352 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3353
3354 def testSymbolsTplSection(self):
3355 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3356 self._SetupSplElf('u_boot_binman_syms')
3357 self._SetupTplElf('u_boot_binman_syms')
3358 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
3359 [0x04, 0x1c, 0x10 + 0x34, 0x04])
3360
3361 def testSymbolsTplSectionX86(self):
3362 """Test binman can assign symbols in a section with end-at-4gb"""
3363 self._SetupSplElf('u_boot_binman_syms_x86')
3364 self._SetupTplElf('u_boot_binman_syms_x86')
3365 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
3366 [0xffffff04, 0xffffff1c, 0xffffff34,
3367 0x04])
Simon Glass2090f1e2019-08-24 07:23:00 -06003368
Simon Glassbf4d0e22019-08-24 07:23:03 -06003369 def testPackX86RomIfwiSectiom(self):
3370 """Test that a section can be placed in an IFWI region"""
3371 self._SetupIfwi('fitimage.bin')
3372 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3373 self._CheckIfwi(data)
3374
Simon Glassea0fff92019-08-24 07:23:07 -06003375 def testPackFspM(self):
3376 """Test that an image with a FSP memory-init binary can be created"""
3377 data = self._DoReadFile('152_intel_fsp_m.dts')
3378 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3379
Simon Glassbc6a88f2019-10-20 21:31:35 -06003380 def testPackFspS(self):
3381 """Test that an image with a FSP silicon-init binary can be created"""
3382 data = self._DoReadFile('153_intel_fsp_s.dts')
3383 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassea0fff92019-08-24 07:23:07 -06003384
Simon Glass998d1482019-10-20 21:31:36 -06003385 def testPackFspT(self):
3386 """Test that an image with a FSP temp-ram-init binary can be created"""
3387 data = self._DoReadFile('154_intel_fsp_t.dts')
3388 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3389
Simon Glass0dc706f2020-07-09 18:39:31 -06003390 def testMkimage(self):
3391 """Test using mkimage to build an image"""
3392 data = self._DoReadFile('156_mkimage.dts')
3393
3394 # Just check that the data appears in the file somewhere
3395 self.assertIn(U_BOOT_SPL_DATA, data)
3396
Simon Glassce867ad2020-07-09 18:39:36 -06003397 def testExtblob(self):
3398 """Test an image with an external blob"""
3399 data = self._DoReadFile('157_blob_ext.dts')
3400 self.assertEqual(REFCODE_DATA, data)
3401
3402 def testExtblobMissing(self):
3403 """Test an image with a missing external blob"""
3404 with self.assertRaises(ValueError) as e:
3405 self._DoReadFile('158_blob_ext_missing.dts')
3406 self.assertIn("Filename 'missing-file' not found in input path",
3407 str(e.exception))
3408
Simon Glass4f9f1052020-07-09 18:39:38 -06003409 def testExtblobMissingOk(self):
3410 """Test an image with an missing external blob that is allowed"""
Simon Glassb1cca952020-07-09 18:39:40 -06003411 with test_util.capture_sys_output() as (stdout, stderr):
3412 self._DoTestFile('158_blob_ext_missing.dts', allow_missing=True)
3413 err = stderr.getvalue()
3414 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
3415
3416 def testExtblobMissingOkSect(self):
3417 """Test an image with an missing external blob that is allowed"""
3418 with test_util.capture_sys_output() as (stdout, stderr):
3419 self._DoTestFile('159_blob_ext_missing_sect.dts',
3420 allow_missing=True)
3421 err = stderr.getvalue()
3422 self.assertRegex(err, "Image 'main-section'.*missing.*: "
3423 "blob-ext blob-ext2")
Simon Glass4f9f1052020-07-09 18:39:38 -06003424
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003425 def testPackX86RomMeMissingDesc(self):
3426 """Test that an missing Intel descriptor entry is allowed"""
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003427 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass52b10dd2020-07-25 15:11:19 -06003428 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003429 err = stderr.getvalue()
3430 self.assertRegex(err,
3431 "Image 'main-section'.*missing.*: intel-descriptor")
3432
3433 def testPackX86RomMissingIfwi(self):
3434 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3435 self._SetupIfwi('fitimage.bin')
3436 pathname = os.path.join(self._indir, 'fitimage.bin')
3437 os.remove(pathname)
3438 with test_util.capture_sys_output() as (stdout, stderr):
3439 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3440 err = stderr.getvalue()
3441 self.assertRegex(err, "Image 'main-section'.*missing.*: intel-ifwi")
3442
Simon Glassb3295fd2020-07-09 18:39:42 -06003443 def testPackOverlap(self):
3444 """Test that zero-size overlapping regions are ignored"""
3445 self._DoTestFile('160_pack_overlap_zero.dts')
3446
Simon Glassfdc34362020-07-09 18:39:45 -06003447 def testSimpleFit(self):
3448 """Test an image with a FIT inside"""
3449 data = self._DoReadFile('161_fit.dts')
3450 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3451 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3452 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3453
3454 # The data should be inside the FIT
3455 dtb = fdt.Fdt.FromData(fit_data)
3456 dtb.Scan()
3457 fnode = dtb.GetNode('/images/kernel')
3458 self.assertIn('data', fnode.props)
3459
3460 fname = os.path.join(self._indir, 'fit_data.fit')
3461 tools.WriteFile(fname, fit_data)
3462 out = tools.Run('dumpimage', '-l', fname)
3463
3464 # Check a few features to make sure the plumbing works. We don't need
3465 # to test the operation of mkimage or dumpimage here. First convert the
3466 # output into a dict where the keys are the fields printed by dumpimage
3467 # and the values are a list of values for each field
3468 lines = out.splitlines()
3469
3470 # Converts "Compression: gzip compressed" into two groups:
3471 # 'Compression' and 'gzip compressed'
3472 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3473 vals = collections.defaultdict(list)
3474 for line in lines:
3475 mat = re_line.match(line)
3476 vals[mat.group(1)].append(mat.group(2))
3477
3478 self.assertEquals('FIT description: test-desc', lines[0])
3479 self.assertIn('Created:', lines[1])
3480 self.assertIn('Image 0 (kernel)', vals)
3481 self.assertIn('Hash value', vals)
3482 data_sizes = vals.get('Data Size')
3483 self.assertIsNotNone(data_sizes)
3484 self.assertEqual(2, len(data_sizes))
3485 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
3486 self.assertEqual(len(U_BOOT_DATA), int(data_sizes[0].split()[0]))
3487 self.assertEqual(len(U_BOOT_SPL_DTB_DATA), int(data_sizes[1].split()[0]))
3488
3489 def testFitExternal(self):
Simon Glasse9d336d2020-09-01 05:13:55 -06003490 """Test an image with an FIT with external images"""
Simon Glassfdc34362020-07-09 18:39:45 -06003491 data = self._DoReadFile('162_fit_external.dts')
3492 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3493
3494 # The data should be outside the FIT
3495 dtb = fdt.Fdt.FromData(fit_data)
3496 dtb.Scan()
3497 fnode = dtb.GetNode('/images/kernel')
3498 self.assertNotIn('data', fnode.props)
Simon Glass12bb1a92019-07-20 12:23:51 -06003499
Alper Nebi Yasak8001d0b2020-08-31 12:58:18 +03003500 def testSectionIgnoreHashSignature(self):
3501 """Test that sections ignore hash, signature nodes for its data"""
3502 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
3503 expected = (U_BOOT_DATA + U_BOOT_DATA)
3504 self.assertEqual(expected, data)
3505
Alper Nebi Yasak3fdeb142020-08-31 12:58:19 +03003506 def testPadInSections(self):
3507 """Test pad-before, pad-after for entries in sections"""
3508 data = self._DoReadFile('166_pad_in_sections.dts')
3509 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
3510 U_BOOT_DATA + tools.GetBytes(ord('!'), 6) +
3511 U_BOOT_DATA)
3512 self.assertEqual(expected, data)
3513
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03003514 def testFitImageSubentryAlignment(self):
3515 """Test relative alignability of FIT image subentries"""
3516 entry_args = {
3517 'test-id': TEXT_DATA,
3518 }
3519 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
3520 entry_args=entry_args)
3521 dtb = fdt.Fdt.FromData(data)
3522 dtb.Scan()
3523
3524 node = dtb.GetNode('/images/kernel')
3525 data = dtb.GetProps(node)["data"].bytes
3526 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
3527 expected = (tools.GetBytes(0, 0x20) + U_BOOT_SPL_DATA +
3528 tools.GetBytes(0, align_pad) + U_BOOT_DATA)
3529 self.assertEqual(expected, data)
3530
3531 node = dtb.GetNode('/images/fdt-1')
3532 data = dtb.GetProps(node)["data"].bytes
3533 expected = (U_BOOT_SPL_DTB_DATA + tools.GetBytes(0, 20) +
3534 tools.ToBytes(TEXT_DATA) + tools.GetBytes(0, 30) +
3535 U_BOOT_DTB_DATA)
3536 self.assertEqual(expected, data)
3537
3538 def testFitExtblobMissingOk(self):
3539 """Test a FIT with a missing external blob that is allowed"""
3540 with test_util.capture_sys_output() as (stdout, stderr):
3541 self._DoTestFile('168_fit_missing_blob.dts',
3542 allow_missing=True)
3543 err = stderr.getvalue()
3544 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
3545
Simon Glass3decfa32020-09-01 05:13:54 -06003546 def testBlobNamedByArgMissing(self):
3547 """Test handling of a missing entry arg"""
3548 with self.assertRaises(ValueError) as e:
3549 self._DoReadFile('068_blob_named_by_arg.dts')
3550 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
3551 str(e.exception))
3552
Simon Glass9fc60b42017-11-12 21:52:22 -07003553if __name__ == "__main__":
3554 unittest.main()