blob: fedcc1ada1bc94ce623654c1b72591da05718c6e [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 Glassffded752019-07-08 14:25:46 -060032from 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 Glass4f443042016-11-25 20:15:52 -0700301 """
Simon Glass53cd5d92019-07-08 14:25:29 -0600302 args = []
Simon Glass7fe91732017-11-13 18:55:00 -0700303 if debug:
304 args.append('-D')
Simon Glass53cd5d92019-07-08 14:25:29 -0600305 if verbosity is not None:
306 args.append('-v%d' % verbosity)
307 elif self.verbosity:
308 args.append('-v%d' % self.verbosity)
309 if self.toolpath:
310 for path in self.toolpath:
311 args += ['--toolpath', path]
312 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass3b0c38212018-06-01 09:38:20 -0600313 if map:
314 args.append('-m')
Simon Glass16b8d6b2018-07-06 10:27:42 -0600315 if update_dtb:
Simon Glass2569e102019-07-08 13:18:47 -0600316 args.append('-u')
Simon Glass93d17412018-09-14 04:57:23 -0600317 if not use_real_dtb:
318 args.append('--fake-dtb')
Simon Glass53af22a2018-07-17 13:25:32 -0600319 if entry_args:
Simon Glass50979152019-05-14 15:53:41 -0600320 for arg, value in entry_args.items():
Simon Glass53af22a2018-07-17 13:25:32 -0600321 args.append('-a%s=%s' % (arg, value))
Simon Glass4f9f1052020-07-09 18:39:38 -0600322 if allow_missing:
323 args.append('-M')
Simon Glass0bfa7b02018-09-14 04:57:12 -0600324 if images:
325 for image in images:
326 args += ['-i', image]
Simon Glass7fe91732017-11-13 18:55:00 -0700327 return self._DoBinman(*args)
Simon Glass4f443042016-11-25 20:15:52 -0700328
329 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glasse0ff8552016-11-25 20:15:53 -0700330 """Set up a new test device-tree file
331
332 The given file is compiled and set up as the device tree to be used
333 for ths test.
334
335 Args:
336 fname: Filename of .dts file to read
Simon Glass7ae5f312018-06-01 09:38:19 -0600337 outfile: Output filename for compiled device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700338
339 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600340 Contents of device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700341 """
Simon Glassa004f292019-07-20 12:23:49 -0600342 tmpdir = tempfile.mkdtemp(prefix='binmant.')
343 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
Simon Glass1d0ebf72019-05-14 15:53:42 -0600344 with open(dtb, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700345 data = fd.read()
346 TestFunctional._MakeInputFile(outfile, data)
Simon Glassa004f292019-07-20 12:23:49 -0600347 shutil.rmtree(tmpdir)
Simon Glasse0e62752018-10-01 21:12:41 -0600348 return data
Simon Glass4f443042016-11-25 20:15:52 -0700349
Simon Glass6ed45ba2018-09-14 04:57:24 -0600350 def _GetDtbContentsForSplTpl(self, dtb_data, name):
351 """Create a version of the main DTB for SPL or SPL
352
353 For testing we don't actually have different versions of the DTB. With
354 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
355 we don't normally have any unwanted nodes.
356
357 We still want the DTBs for SPL and TPL to be different though, since
358 otherwise it is confusing to know which one we are looking at. So add
359 an 'spl' or 'tpl' property to the top-level node.
360 """
361 dtb = fdt.Fdt.FromData(dtb_data)
362 dtb.Scan()
363 dtb.GetNode('/binman').AddZeroProp(name)
364 dtb.Sync(auto_resize=True)
365 dtb.Pack()
366 return dtb.GetContents()
367
Simon Glass16b8d6b2018-07-06 10:27:42 -0600368 def _DoReadFileDtb(self, fname, use_real_dtb=False, map=False,
Simon Glass6ed45ba2018-09-14 04:57:24 -0600369 update_dtb=False, entry_args=None, reset_dtbs=True):
Simon Glass4f443042016-11-25 20:15:52 -0700370 """Run binman and return the resulting image
371
372 This runs binman with a given test file and then reads the resulting
373 output file. It is a shortcut function since most tests need to do
374 these steps.
375
376 Raises an assertion failure if binman returns a non-zero exit code.
377
378 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600379 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass4f443042016-11-25 20:15:52 -0700380 use_real_dtb: True to use the test file as the contents of
381 the u-boot-dtb entry. Normally this is not needed and the
382 test contents (the U_BOOT_DTB_DATA string) can be used.
383 But in some test we need the real contents.
Simon Glass3b0c38212018-06-01 09:38:20 -0600384 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600385 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600386 tree before packing it into the image
Simon Glasse0ff8552016-11-25 20:15:53 -0700387
388 Returns:
389 Tuple:
390 Resulting image contents
391 Device tree contents
Simon Glass3b0c38212018-06-01 09:38:20 -0600392 Map data showing contents of image (or None if none)
Simon Glassea6922e2018-07-17 13:25:27 -0600393 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass4f443042016-11-25 20:15:52 -0700394 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700395 dtb_data = None
Simon Glass4f443042016-11-25 20:15:52 -0700396 # Use the compiled test file as the u-boot-dtb input
397 if use_real_dtb:
Simon Glasse0ff8552016-11-25 20:15:53 -0700398 dtb_data = self._SetupDtb(fname)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600399
400 # For testing purposes, make a copy of the DT for SPL and TPL. Add
401 # a node indicating which it is, so aid verification.
402 for name in ['spl', 'tpl']:
403 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
404 outfile = os.path.join(self._indir, dtb_fname)
405 TestFunctional._MakeInputFile(dtb_fname,
406 self._GetDtbContentsForSplTpl(dtb_data, name))
Simon Glass4f443042016-11-25 20:15:52 -0700407
408 try:
Simon Glass53af22a2018-07-17 13:25:32 -0600409 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glass6ed45ba2018-09-14 04:57:24 -0600410 entry_args=entry_args, use_real_dtb=use_real_dtb)
Simon Glass4f443042016-11-25 20:15:52 -0700411 self.assertEqual(0, retcode)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600412 out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
Simon Glass4f443042016-11-25 20:15:52 -0700413
414 # Find the (only) image, read it and return its contents
415 image = control.images['image']
Simon Glass16b8d6b2018-07-06 10:27:42 -0600416 image_fname = tools.GetOutputFilename('image.bin')
417 self.assertTrue(os.path.exists(image_fname))
Simon Glass3b0c38212018-06-01 09:38:20 -0600418 if map:
419 map_fname = tools.GetOutputFilename('image.map')
420 with open(map_fname) as fd:
421 map_data = fd.read()
422 else:
423 map_data = None
Simon Glass1d0ebf72019-05-14 15:53:42 -0600424 with open(image_fname, 'rb') as fd:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600425 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass4f443042016-11-25 20:15:52 -0700426 finally:
427 # Put the test file back
Simon Glass6ed45ba2018-09-14 04:57:24 -0600428 if reset_dtbs and use_real_dtb:
Simon Glassb8ef5b62018-07-17 13:25:48 -0600429 self._ResetDtbs()
Simon Glass4f443042016-11-25 20:15:52 -0700430
Simon Glass3c081312019-07-08 14:25:26 -0600431 def _DoReadFileRealDtb(self, fname):
432 """Run binman with a real .dtb file and return the resulting data
433
434 Args:
435 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
436
437 Returns:
438 Resulting image contents
439 """
440 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
441
Simon Glasse0ff8552016-11-25 20:15:53 -0700442 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass7ae5f312018-06-01 09:38:19 -0600443 """Helper function which discards the device-tree binary
444
445 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600446 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600447 use_real_dtb: True to use the test file as the contents of
448 the u-boot-dtb entry. Normally this is not needed and the
449 test contents (the U_BOOT_DTB_DATA string) can be used.
450 But in some test we need the real contents.
Simon Glassea6922e2018-07-17 13:25:27 -0600451
452 Returns:
453 Resulting image contents
Simon Glass7ae5f312018-06-01 09:38:19 -0600454 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700455 return self._DoReadFileDtb(fname, use_real_dtb)[0]
456
Simon Glass4f443042016-11-25 20:15:52 -0700457 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600458 def _MakeInputFile(cls, fname, contents):
Simon Glass4f443042016-11-25 20:15:52 -0700459 """Create a new test input file, creating directories as needed
460
461 Args:
Simon Glass3ab95982018-08-01 15:22:37 -0600462 fname: Filename to create
Simon Glass4f443042016-11-25 20:15:52 -0700463 contents: File contents to write in to the file
464 Returns:
465 Full pathname of file created
466 """
Simon Glassb986b3b2019-08-24 07:22:43 -0600467 pathname = os.path.join(cls._indir, fname)
Simon Glass4f443042016-11-25 20:15:52 -0700468 dirname = os.path.dirname(pathname)
469 if dirname and not os.path.exists(dirname):
470 os.makedirs(dirname)
471 with open(pathname, 'wb') as fd:
472 fd.write(contents)
473 return pathname
474
475 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600476 def _MakeInputDir(cls, dirname):
Simon Glass0ef87aa2018-07-17 13:25:44 -0600477 """Create a new test input directory, creating directories as needed
478
479 Args:
480 dirname: Directory name to create
481
482 Returns:
483 Full pathname of directory created
484 """
Simon Glassb986b3b2019-08-24 07:22:43 -0600485 pathname = os.path.join(cls._indir, dirname)
Simon Glass0ef87aa2018-07-17 13:25:44 -0600486 if not os.path.exists(pathname):
487 os.makedirs(pathname)
488 return pathname
489
490 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600491 def _SetupSplElf(cls, src_fname='bss_data'):
Simon Glass11ae93e2018-10-01 21:12:47 -0600492 """Set up an ELF file with a '_dt_ucode_base_size' symbol
493
494 Args:
495 Filename of ELF file to use as SPL
496 """
Simon Glassc9a0b272019-08-24 07:22:59 -0600497 TestFunctional._MakeInputFile('spl/u-boot-spl',
498 tools.ReadFile(cls.ElfTestFile(src_fname)))
Simon Glass11ae93e2018-10-01 21:12:47 -0600499
500 @classmethod
Simon Glass2090f1e2019-08-24 07:23:00 -0600501 def _SetupTplElf(cls, src_fname='bss_data'):
502 """Set up an ELF file with a '_dt_ucode_base_size' symbol
503
504 Args:
505 Filename of ELF file to use as TPL
506 """
507 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
508 tools.ReadFile(cls.ElfTestFile(src_fname)))
509
510 @classmethod
Simon Glass0ba4b3d2020-07-09 18:39:41 -0600511 def _SetupDescriptor(cls):
512 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
513 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
514
515 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600516 def TestFile(cls, fname):
517 return os.path.join(cls._binman_dir, 'test', fname)
Simon Glass4f443042016-11-25 20:15:52 -0700518
Simon Glass53e22bf2019-08-24 07:22:53 -0600519 @classmethod
520 def ElfTestFile(cls, fname):
521 return os.path.join(cls._elf_testdir, fname)
522
Simon Glass4f443042016-11-25 20:15:52 -0700523 def AssertInList(self, grep_list, target):
524 """Assert that at least one of a list of things is in a target
525
526 Args:
527 grep_list: List of strings to check
528 target: Target string
529 """
530 for grep in grep_list:
531 if grep in target:
532 return
Simon Glass1fc62de2019-05-17 22:00:50 -0600533 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass4f443042016-11-25 20:15:52 -0700534
535 def CheckNoGaps(self, entries):
536 """Check that all entries fit together without gaps
537
538 Args:
539 entries: List of entries to check
540 """
Simon Glass3ab95982018-08-01 15:22:37 -0600541 offset = 0
Simon Glass4f443042016-11-25 20:15:52 -0700542 for entry in entries.values():
Simon Glass3ab95982018-08-01 15:22:37 -0600543 self.assertEqual(offset, entry.offset)
544 offset += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700545
Simon Glasse0ff8552016-11-25 20:15:53 -0700546 def GetFdtLen(self, dtb):
Simon Glass7ae5f312018-06-01 09:38:19 -0600547 """Get the totalsize field from a device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700548
549 Args:
Simon Glass7ae5f312018-06-01 09:38:19 -0600550 dtb: Device-tree binary contents
Simon Glasse0ff8552016-11-25 20:15:53 -0700551
552 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600553 Total size of device-tree binary, from the header
Simon Glasse0ff8552016-11-25 20:15:53 -0700554 """
555 return struct.unpack('>L', dtb[4:8])[0]
556
Simon Glass086cec92019-07-08 14:25:27 -0600557 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glass16b8d6b2018-07-06 10:27:42 -0600558 def AddNode(node, path):
559 if node.name != '/':
560 path += '/' + node.name
Simon Glass086cec92019-07-08 14:25:27 -0600561 for prop in node.props.values():
562 if prop.name in prop_names:
563 prop_path = path + ':' + prop.name
564 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
565 prop.value)
Simon Glass16b8d6b2018-07-06 10:27:42 -0600566 for subnode in node.subnodes:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600567 AddNode(subnode, path)
568
569 tree = {}
Simon Glass16b8d6b2018-07-06 10:27:42 -0600570 AddNode(dtb.GetRoot(), '')
571 return tree
572
Simon Glass4f443042016-11-25 20:15:52 -0700573 def testRun(self):
574 """Test a basic run with valid args"""
575 result = self._RunBinman('-h')
576
577 def testFullHelp(self):
578 """Test that the full help is displayed with -H"""
579 result = self._RunBinman('-H')
580 help_file = os.path.join(self._binman_dir, 'README')
Tom Rini3759df02018-01-16 15:29:50 -0500581 # Remove possible extraneous strings
582 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
583 gothelp = result.stdout.replace(extra, '')
584 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass4f443042016-11-25 20:15:52 -0700585 self.assertEqual(0, len(result.stderr))
586 self.assertEqual(0, result.return_code)
587
588 def testFullHelpInternal(self):
589 """Test that the full help is displayed with -H"""
590 try:
591 command.test_result = command.CommandResult()
592 result = self._DoBinman('-H')
593 help_file = os.path.join(self._binman_dir, 'README')
594 finally:
595 command.test_result = None
596
597 def testHelp(self):
598 """Test that the basic help is displayed with -h"""
599 result = self._RunBinman('-h')
600 self.assertTrue(len(result.stdout) > 200)
601 self.assertEqual(0, len(result.stderr))
602 self.assertEqual(0, result.return_code)
603
Simon Glass4f443042016-11-25 20:15:52 -0700604 def testBoard(self):
605 """Test that we can run it with a specific board"""
Simon Glass741f2d62018-10-01 12:22:30 -0600606 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass4f443042016-11-25 20:15:52 -0700607 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glass53cd5d92019-07-08 14:25:29 -0600608 result = self._DoBinman('build', '-b', 'sandbox')
Simon Glass4f443042016-11-25 20:15:52 -0700609 self.assertEqual(0, result)
610
611 def testNeedBoard(self):
612 """Test that we get an error when no board ius supplied"""
613 with self.assertRaises(ValueError) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600614 result = self._DoBinman('build')
Simon Glass4f443042016-11-25 20:15:52 -0700615 self.assertIn("Must provide a board to process (use -b <board>)",
616 str(e.exception))
617
618 def testMissingDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600619 """Test that an invalid device-tree file generates an error"""
Simon Glass4f443042016-11-25 20:15:52 -0700620 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600621 self._RunBinman('build', '-d', 'missing_file')
Simon Glass4f443042016-11-25 20:15:52 -0700622 # We get one error from libfdt, and a different one from fdtget.
623 self.AssertInList(["Couldn't open blob from 'missing_file'",
624 'No such file or directory'], str(e.exception))
625
626 def testBrokenDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600627 """Test that an invalid device-tree source file generates an error
Simon Glass4f443042016-11-25 20:15:52 -0700628
629 Since this is a source file it should be compiled and the error
630 will come from the device-tree compiler (dtc).
631 """
632 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600633 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700634 self.assertIn("FATAL ERROR: Unable to parse input tree",
635 str(e.exception))
636
637 def testMissingNode(self):
638 """Test that a device tree without a 'binman' node generates an error"""
639 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600640 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700641 self.assertIn("does not have a 'binman' node", str(e.exception))
642
643 def testEmpty(self):
644 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glass53cd5d92019-07-08 14:25:29 -0600645 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700646 self.assertEqual(0, len(result.stderr))
647 self.assertEqual(0, result.return_code)
648
649 def testInvalidEntry(self):
650 """Test that an invalid entry is flagged"""
651 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600652 result = self._RunBinman('build', '-d',
Simon Glass741f2d62018-10-01 12:22:30 -0600653 self.TestFile('004_invalid_entry.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700654 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
655 "'/binman/not-a-valid-type'", str(e.exception))
656
657 def testSimple(self):
658 """Test a simple binman with a single file"""
Simon Glass741f2d62018-10-01 12:22:30 -0600659 data = self._DoReadFile('005_simple.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700660 self.assertEqual(U_BOOT_DATA, data)
661
Simon Glass7fe91732017-11-13 18:55:00 -0700662 def testSimpleDebug(self):
663 """Test a simple binman run with debugging enabled"""
Simon Glasse2705fa2019-07-08 14:25:53 -0600664 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass7fe91732017-11-13 18:55:00 -0700665
Simon Glass4f443042016-11-25 20:15:52 -0700666 def testDual(self):
667 """Test that we can handle creating two images
668
669 This also tests image padding.
670 """
Simon Glass741f2d62018-10-01 12:22:30 -0600671 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700672 self.assertEqual(0, retcode)
673
674 image = control.images['image1']
Simon Glass8beb11e2019-07-08 14:25:47 -0600675 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700676 fname = tools.GetOutputFilename('image1.bin')
677 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600678 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700679 data = fd.read()
680 self.assertEqual(U_BOOT_DATA, data)
681
682 image = control.images['image2']
Simon Glass8beb11e2019-07-08 14:25:47 -0600683 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700684 fname = tools.GetOutputFilename('image2.bin')
685 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600686 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700687 data = fd.read()
688 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glasse6d85ff2019-05-14 15:53:47 -0600689 self.assertEqual(tools.GetBytes(0, 3), data[:3])
690 self.assertEqual(tools.GetBytes(0, 5), data[7:])
Simon Glass4f443042016-11-25 20:15:52 -0700691
692 def testBadAlign(self):
693 """Test that an invalid alignment value is detected"""
694 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600695 self._DoTestFile('007_bad_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700696 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
697 "of two", str(e.exception))
698
699 def testPackSimple(self):
700 """Test that packing works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600701 retcode = self._DoTestFile('008_pack.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700702 self.assertEqual(0, retcode)
703 self.assertIn('image', control.images)
704 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600705 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700706 self.assertEqual(5, len(entries))
707
708 # First u-boot
709 self.assertIn('u-boot', entries)
710 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600711 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700712 self.assertEqual(len(U_BOOT_DATA), entry.size)
713
714 # Second u-boot, aligned to 16-byte boundary
715 self.assertIn('u-boot-align', entries)
716 entry = entries['u-boot-align']
Simon Glass3ab95982018-08-01 15:22:37 -0600717 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700718 self.assertEqual(len(U_BOOT_DATA), entry.size)
719
720 # Third u-boot, size 23 bytes
721 self.assertIn('u-boot-size', entries)
722 entry = entries['u-boot-size']
Simon Glass3ab95982018-08-01 15:22:37 -0600723 self.assertEqual(20, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700724 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
725 self.assertEqual(23, entry.size)
726
727 # Fourth u-boot, placed immediate after the above
728 self.assertIn('u-boot-next', entries)
729 entry = entries['u-boot-next']
Simon Glass3ab95982018-08-01 15:22:37 -0600730 self.assertEqual(43, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700731 self.assertEqual(len(U_BOOT_DATA), entry.size)
732
Simon Glass3ab95982018-08-01 15:22:37 -0600733 # Fifth u-boot, placed at a fixed offset
Simon Glass4f443042016-11-25 20:15:52 -0700734 self.assertIn('u-boot-fixed', entries)
735 entry = entries['u-boot-fixed']
Simon Glass3ab95982018-08-01 15:22:37 -0600736 self.assertEqual(61, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700737 self.assertEqual(len(U_BOOT_DATA), entry.size)
738
Simon Glass8beb11e2019-07-08 14:25:47 -0600739 self.assertEqual(65, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700740
741 def testPackExtra(self):
742 """Test that extra packing feature works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600743 retcode = self._DoTestFile('009_pack_extra.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700744
745 self.assertEqual(0, retcode)
746 self.assertIn('image', control.images)
747 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600748 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700749 self.assertEqual(5, len(entries))
750
751 # First u-boot with padding before and after
752 self.assertIn('u-boot', entries)
753 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600754 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700755 self.assertEqual(3, entry.pad_before)
756 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
757
758 # Second u-boot has an aligned size, but it has no effect
759 self.assertIn('u-boot-align-size-nop', entries)
760 entry = entries['u-boot-align-size-nop']
Simon Glass3ab95982018-08-01 15:22:37 -0600761 self.assertEqual(12, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700762 self.assertEqual(4, entry.size)
763
764 # Third u-boot has an aligned size too
765 self.assertIn('u-boot-align-size', entries)
766 entry = entries['u-boot-align-size']
Simon Glass3ab95982018-08-01 15:22:37 -0600767 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700768 self.assertEqual(32, entry.size)
769
770 # Fourth u-boot has an aligned end
771 self.assertIn('u-boot-align-end', entries)
772 entry = entries['u-boot-align-end']
Simon Glass3ab95982018-08-01 15:22:37 -0600773 self.assertEqual(48, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700774 self.assertEqual(16, entry.size)
775
776 # Fifth u-boot immediately afterwards
777 self.assertIn('u-boot-align-both', entries)
778 entry = entries['u-boot-align-both']
Simon Glass3ab95982018-08-01 15:22:37 -0600779 self.assertEqual(64, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700780 self.assertEqual(64, entry.size)
781
782 self.CheckNoGaps(entries)
Simon Glass8beb11e2019-07-08 14:25:47 -0600783 self.assertEqual(128, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700784
785 def testPackAlignPowerOf2(self):
786 """Test that invalid entry alignment is detected"""
787 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600788 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700789 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
790 "of two", str(e.exception))
791
792 def testPackAlignSizePowerOf2(self):
793 """Test that invalid entry size alignment is detected"""
794 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600795 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700796 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
797 "power of two", str(e.exception))
798
799 def testPackInvalidAlign(self):
Simon Glass3ab95982018-08-01 15:22:37 -0600800 """Test detection of an offset that does not match its alignment"""
Simon Glass4f443042016-11-25 20:15:52 -0700801 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600802 self._DoTestFile('012_pack_inv_align.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600803 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700804 "align 0x4 (4)", str(e.exception))
805
806 def testPackInvalidSizeAlign(self):
807 """Test that invalid entry size alignment is detected"""
808 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600809 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700810 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
811 "align-size 0x4 (4)", str(e.exception))
812
813 def testPackOverlap(self):
814 """Test that overlapping regions are detected"""
815 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600816 self._DoTestFile('014_pack_overlap.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600817 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -0700818 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
819 str(e.exception))
820
821 def testPackEntryOverflow(self):
822 """Test that entries that overflow their size are detected"""
823 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600824 self._DoTestFile('015_pack_overflow.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700825 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
826 "but entry size is 0x3 (3)", str(e.exception))
827
828 def testPackImageOverflow(self):
829 """Test that entries which overflow the image size are detected"""
830 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600831 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600832 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass4f443042016-11-25 20:15:52 -0700833 "size 0x3 (3)", str(e.exception))
834
835 def testPackImageSize(self):
836 """Test that the image size can be set"""
Simon Glass741f2d62018-10-01 12:22:30 -0600837 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700838 self.assertEqual(0, retcode)
839 self.assertIn('image', control.images)
840 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -0600841 self.assertEqual(7, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700842
843 def testPackImageSizeAlign(self):
844 """Test that image size alignemnt works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600845 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700846 self.assertEqual(0, retcode)
847 self.assertIn('image', control.images)
848 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -0600849 self.assertEqual(16, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700850
851 def testPackInvalidImageAlign(self):
852 """Test that invalid image alignment is detected"""
853 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600854 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600855 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700856 "align-size 0x8 (8)", str(e.exception))
857
858 def testPackAlignPowerOf2(self):
859 """Test that invalid image alignment is detected"""
860 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600861 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -0600862 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass4f443042016-11-25 20:15:52 -0700863 "two", str(e.exception))
864
865 def testImagePadByte(self):
866 """Test that the image pad byte can be specified"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600867 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600868 data = self._DoReadFile('021_image_pad.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -0600869 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0xff, 1) +
870 U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -0700871
872 def testImageName(self):
873 """Test that image files can be named"""
Simon Glass741f2d62018-10-01 12:22:30 -0600874 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700875 self.assertEqual(0, retcode)
876 image = control.images['image1']
877 fname = tools.GetOutputFilename('test-name')
878 self.assertTrue(os.path.exists(fname))
879
880 image = control.images['image2']
881 fname = tools.GetOutputFilename('test-name.xx')
882 self.assertTrue(os.path.exists(fname))
883
884 def testBlobFilename(self):
885 """Test that generic blobs can be provided by filename"""
Simon Glass741f2d62018-10-01 12:22:30 -0600886 data = self._DoReadFile('023_blob.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700887 self.assertEqual(BLOB_DATA, data)
888
889 def testPackSorted(self):
890 """Test that entries can be sorted"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600891 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600892 data = self._DoReadFile('024_sorted.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -0600893 self.assertEqual(tools.GetBytes(0, 1) + U_BOOT_SPL_DATA +
894 tools.GetBytes(0, 2) + U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -0700895
Simon Glass3ab95982018-08-01 15:22:37 -0600896 def testPackZeroOffset(self):
897 """Test that an entry at offset 0 is not given a new offset"""
Simon Glass4f443042016-11-25 20:15:52 -0700898 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600899 self._DoTestFile('025_pack_zero_size.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600900 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -0700901 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
902 str(e.exception))
903
904 def testPackUbootDtb(self):
905 """Test that a device tree can be added to U-Boot"""
Simon Glass741f2d62018-10-01 12:22:30 -0600906 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700907 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glasse0ff8552016-11-25 20:15:53 -0700908
909 def testPackX86RomNoSize(self):
910 """Test that the end-at-4gb property requires a size property"""
911 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600912 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -0600913 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glasse0ff8552016-11-25 20:15:53 -0700914 "using end-at-4gb", str(e.exception))
915
Jagdish Gediya94b57db2018-09-03 21:35:07 +0530916 def test4gbAndSkipAtStartTogether(self):
917 """Test that the end-at-4gb and skip-at-size property can't be used
918 together"""
919 with self.assertRaises(ValueError) as e:
Simon Glassdfdd2b62019-08-24 07:23:02 -0600920 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -0600921 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya94b57db2018-09-03 21:35:07 +0530922 "'skip-at-start'", str(e.exception))
923
Simon Glasse0ff8552016-11-25 20:15:53 -0700924 def testPackX86RomOutside(self):
Simon Glass3ab95982018-08-01 15:22:37 -0600925 """Test that the end-at-4gb property checks for offset boundaries"""
Simon Glasse0ff8552016-11-25 20:15:53 -0700926 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600927 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600928 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) is outside "
Simon Glass8f1da502018-06-01 09:38:12 -0600929 "the section starting at 0xffffffe0 (4294967264)",
Simon Glasse0ff8552016-11-25 20:15:53 -0700930 str(e.exception))
931
932 def testPackX86Rom(self):
933 """Test that a basic x86 ROM can be created"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600934 self._SetupSplElf()
Simon Glass9255f3c2019-08-24 07:23:01 -0600935 data = self._DoReadFile('029_x86_rom.dts')
Simon Glasseb0086f2019-08-24 07:23:04 -0600936 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 3) + U_BOOT_SPL_DATA +
Simon Glasse6d85ff2019-05-14 15:53:47 -0600937 tools.GetBytes(0, 2), data)
Simon Glasse0ff8552016-11-25 20:15:53 -0700938
939 def testPackX86RomMeNoDesc(self):
940 """Test that an invalid Intel descriptor entry is detected"""
Simon Glass0ba4b3d2020-07-09 18:39:41 -0600941 try:
Simon Glass52b10dd2020-07-25 15:11:19 -0600942 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
Simon Glass0ba4b3d2020-07-09 18:39:41 -0600943 with self.assertRaises(ValueError) as e:
Simon Glass52b10dd2020-07-25 15:11:19 -0600944 self._DoTestFile('163_x86_rom_me_empty.dts')
Simon Glass0ba4b3d2020-07-09 18:39:41 -0600945 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
946 str(e.exception))
947 finally:
948 self._SetupDescriptor()
Simon Glasse0ff8552016-11-25 20:15:53 -0700949
950 def testPackX86RomBadDesc(self):
951 """Test that the Intel requires a descriptor entry"""
952 with self.assertRaises(ValueError) as e:
Simon Glass9255f3c2019-08-24 07:23:01 -0600953 self._DoTestFile('030_x86_rom_me_no_desc.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600954 self.assertIn("Node '/binman/intel-me': No offset set with "
955 "offset-unset: should another entry provide this correct "
956 "offset?", str(e.exception))
Simon Glasse0ff8552016-11-25 20:15:53 -0700957
958 def testPackX86RomMe(self):
959 """Test that an x86 ROM with an ME region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -0600960 data = self._DoReadFile('031_x86_rom_me.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -0600961 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
962 if data[:0x1000] != expected_desc:
963 self.fail('Expected descriptor binary at start of image')
Simon Glasse0ff8552016-11-25 20:15:53 -0700964 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
965
966 def testPackVga(self):
967 """Test that an image with a VGA binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -0600968 data = self._DoReadFile('032_intel_vga.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -0700969 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
970
971 def testPackStart16(self):
972 """Test that an image with an x86 start16 region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -0600973 data = self._DoReadFile('033_x86_start16.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -0700974 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
975
Jagdish Gediya9d368f32018-09-03 21:35:08 +0530976 def testPackPowerpcMpc85xxBootpgResetvec(self):
977 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
978 created"""
Simon Glassdfdd2b62019-08-24 07:23:02 -0600979 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
Jagdish Gediya9d368f32018-09-03 21:35:08 +0530980 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
981
Simon Glass736bb0a2018-07-06 10:27:17 -0600982 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glassadc57012018-07-06 10:27:16 -0600983 """Handle running a test for insertion of microcode
984
985 Args:
986 dts_fname: Name of test .dts file
987 nodtb_data: Data that we expect in the first section
Simon Glass736bb0a2018-07-06 10:27:17 -0600988 ucode_second: True if the microsecond entry is second instead of
989 third
Simon Glassadc57012018-07-06 10:27:16 -0600990
991 Returns:
992 Tuple:
993 Contents of first region (U-Boot or SPL)
Simon Glass3ab95982018-08-01 15:22:37 -0600994 Offset and size components of microcode pointer, as inserted
Simon Glassadc57012018-07-06 10:27:16 -0600995 in the above (two 4-byte words)
996 """
Simon Glass6b187df2017-11-12 21:52:27 -0700997 data = self._DoReadFile(dts_fname, True)
Simon Glasse0ff8552016-11-25 20:15:53 -0700998
999 # Now check the device tree has no microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001000 if ucode_second:
1001 ucode_content = data[len(nodtb_data):]
1002 ucode_pos = len(nodtb_data)
1003 dtb_with_ucode = ucode_content[16:]
1004 fdt_len = self.GetFdtLen(dtb_with_ucode)
1005 else:
1006 dtb_with_ucode = data[len(nodtb_data):]
1007 fdt_len = self.GetFdtLen(dtb_with_ucode)
1008 ucode_content = dtb_with_ucode[fdt_len:]
1009 ucode_pos = len(nodtb_data) + fdt_len
Simon Glasse0ff8552016-11-25 20:15:53 -07001010 fname = tools.GetOutputFilename('test.dtb')
1011 with open(fname, 'wb') as fd:
Simon Glassadc57012018-07-06 10:27:16 -06001012 fd.write(dtb_with_ucode)
Simon Glassec3f3782017-05-27 07:38:29 -06001013 dtb = fdt.FdtScan(fname)
1014 ucode = dtb.GetNode('/microcode')
Simon Glasse0ff8552016-11-25 20:15:53 -07001015 self.assertTrue(ucode)
1016 for node in ucode.subnodes:
1017 self.assertFalse(node.props.get('data'))
1018
Simon Glasse0ff8552016-11-25 20:15:53 -07001019 # Check that the microcode appears immediately after the Fdt
1020 # This matches the concatenation of the data properties in
Simon Glass87722132017-11-12 21:52:26 -07001021 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glasse0ff8552016-11-25 20:15:53 -07001022 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1023 0x78235609)
Simon Glassadc57012018-07-06 10:27:16 -06001024 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glasse0ff8552016-11-25 20:15:53 -07001025
1026 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -06001027 # expected offset and size
Simon Glasse0ff8552016-11-25 20:15:53 -07001028 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1029 len(ucode_data))
Simon Glass736bb0a2018-07-06 10:27:17 -06001030 u_boot = data[:len(nodtb_data)]
1031 return u_boot, pos_and_size
Simon Glass6b187df2017-11-12 21:52:27 -07001032
1033 def testPackUbootMicrocode(self):
1034 """Test that x86 microcode can be handled correctly
1035
1036 We expect to see the following in the image, in order:
1037 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1038 place
1039 u-boot.dtb with the microcode removed
1040 the microcode
1041 """
Simon Glass741f2d62018-10-01 12:22:30 -06001042 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass6b187df2017-11-12 21:52:27 -07001043 U_BOOT_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001044 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1045 b' somewhere in here', first)
Simon Glasse0ff8552016-11-25 20:15:53 -07001046
Simon Glass160a7662017-05-27 07:38:26 -06001047 def _RunPackUbootSingleMicrocode(self):
Simon Glasse0ff8552016-11-25 20:15:53 -07001048 """Test that x86 microcode can be handled correctly
1049
1050 We expect to see the following in the image, in order:
1051 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1052 place
1053 u-boot.dtb with the microcode
1054 an empty microcode region
1055 """
1056 # We need the libfdt library to run this test since only that allows
1057 # finding the offset of a property. This is required by
1058 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass741f2d62018-10-01 12:22:30 -06001059 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glasse0ff8552016-11-25 20:15:53 -07001060
1061 second = data[len(U_BOOT_NODTB_DATA):]
1062
1063 fdt_len = self.GetFdtLen(second)
1064 third = second[fdt_len:]
1065 second = second[:fdt_len]
1066
Simon Glass160a7662017-05-27 07:38:26 -06001067 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1068 self.assertIn(ucode_data, second)
1069 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -07001070
Simon Glass160a7662017-05-27 07:38:26 -06001071 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -06001072 # expected offset and size
Simon Glass160a7662017-05-27 07:38:26 -06001073 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1074 len(ucode_data))
1075 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glassc6c10e72019-05-17 22:00:46 -06001076 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1077 b' somewhere in here', first)
Simon Glassc49deb82016-11-25 20:15:54 -07001078
Simon Glass75db0862016-11-25 20:15:55 -07001079 def testPackUbootSingleMicrocode(self):
1080 """Test that x86 microcode can be handled correctly with fdt_normal.
1081 """
Simon Glass160a7662017-05-27 07:38:26 -06001082 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001083
Simon Glassc49deb82016-11-25 20:15:54 -07001084 def testUBootImg(self):
1085 """Test that u-boot.img can be put in a file"""
Simon Glass741f2d62018-10-01 12:22:30 -06001086 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glassc49deb82016-11-25 20:15:54 -07001087 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glass75db0862016-11-25 20:15:55 -07001088
1089 def testNoMicrocode(self):
1090 """Test that a missing microcode region is detected"""
1091 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001092 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001093 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1094 "node found in ", str(e.exception))
1095
1096 def testMicrocodeWithoutNode(self):
1097 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1098 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001099 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001100 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1101 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1102
1103 def testMicrocodeWithoutNode2(self):
1104 """Test that a missing u-boot-ucode node is detected"""
1105 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001106 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001107 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1108 "microcode region u-boot-ucode", str(e.exception))
1109
1110 def testMicrocodeWithoutPtrInElf(self):
1111 """Test that a U-Boot binary without the microcode symbol is detected"""
1112 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glass75db0862016-11-25 20:15:55 -07001113 try:
Simon Glassbccd91d2019-08-24 07:22:55 -06001114 TestFunctional._MakeInputFile('u-boot',
1115 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass75db0862016-11-25 20:15:55 -07001116
1117 with self.assertRaises(ValueError) as e:
Simon Glass160a7662017-05-27 07:38:26 -06001118 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001119 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1120 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1121
1122 finally:
1123 # Put the original file back
Simon Glassf514d8f2019-08-24 07:22:54 -06001124 TestFunctional._MakeInputFile('u-boot',
1125 tools.ReadFile(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glass75db0862016-11-25 20:15:55 -07001126
1127 def testMicrocodeNotInImage(self):
1128 """Test that microcode must be placed within the image"""
1129 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001130 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001131 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1132 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glass25ac0e62018-06-01 09:38:14 -06001133 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glass75db0862016-11-25 20:15:55 -07001134
1135 def testWithoutMicrocode(self):
1136 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glassbccd91d2019-08-24 07:22:55 -06001137 TestFunctional._MakeInputFile('u-boot',
1138 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass741f2d62018-10-01 12:22:30 -06001139 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001140
1141 # Now check the device tree has no microcode
1142 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1143 second = data[len(U_BOOT_NODTB_DATA):]
1144
1145 fdt_len = self.GetFdtLen(second)
1146 self.assertEqual(dtb, second[:fdt_len])
1147
1148 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1149 third = data[used_len:]
Simon Glasse6d85ff2019-05-14 15:53:47 -06001150 self.assertEqual(tools.GetBytes(0, 0x200 - used_len), third)
Simon Glass75db0862016-11-25 20:15:55 -07001151
1152 def testUnknownPosSize(self):
1153 """Test that microcode must be placed within the image"""
1154 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001155 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glass3ab95982018-08-01 15:22:37 -06001156 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glass75db0862016-11-25 20:15:55 -07001157 "entry 'invalid-entry'", str(e.exception))
Simon Glassda229092016-11-25 20:15:56 -07001158
1159 def testPackFsp(self):
1160 """Test that an image with a FSP binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001161 data = self._DoReadFile('042_intel_fsp.dts')
Simon Glassda229092016-11-25 20:15:56 -07001162 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1163
1164 def testPackCmc(self):
Bin Meng59ea8c22017-08-15 22:41:54 -07001165 """Test that an image with a CMC binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001166 data = self._DoReadFile('043_intel_cmc.dts')
Simon Glassda229092016-11-25 20:15:56 -07001167 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Meng59ea8c22017-08-15 22:41:54 -07001168
1169 def testPackVbt(self):
1170 """Test that an image with a VBT binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001171 data = self._DoReadFile('046_intel_vbt.dts')
Bin Meng59ea8c22017-08-15 22:41:54 -07001172 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glass9fc60b42017-11-12 21:52:22 -07001173
Simon Glass56509842017-11-12 21:52:25 -07001174 def testSplBssPad(self):
1175 """Test that we can pad SPL's BSS with zeros"""
Simon Glass6b187df2017-11-12 21:52:27 -07001176 # ELF file with a '__bss_size' symbol
Simon Glass11ae93e2018-10-01 21:12:47 -06001177 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001178 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001179 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
1180 data)
Simon Glass56509842017-11-12 21:52:25 -07001181
Simon Glass86af5112018-10-01 21:12:42 -06001182 def testSplBssPadMissing(self):
1183 """Test that a missing symbol is detected"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001184 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glassb50e5612017-11-13 18:54:54 -07001185 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001186 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassb50e5612017-11-13 18:54:54 -07001187 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1188 str(e.exception))
1189
Simon Glass87722132017-11-12 21:52:26 -07001190 def testPackStart16Spl(self):
Simon Glass35b384c2018-09-14 04:57:10 -06001191 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001192 data = self._DoReadFile('048_x86_start16_spl.dts')
Simon Glass87722132017-11-12 21:52:26 -07001193 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1194
Simon Glass736bb0a2018-07-06 10:27:17 -06001195 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1196 """Helper function for microcode tests
Simon Glass6b187df2017-11-12 21:52:27 -07001197
1198 We expect to see the following in the image, in order:
1199 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1200 correct place
1201 u-boot.dtb with the microcode removed
1202 the microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001203
1204 Args:
1205 dts: Device tree file to use for test
1206 ucode_second: True if the microsecond entry is second instead of
1207 third
Simon Glass6b187df2017-11-12 21:52:27 -07001208 """
Simon Glass11ae93e2018-10-01 21:12:47 -06001209 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass736bb0a2018-07-06 10:27:17 -06001210 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1211 ucode_second=ucode_second)
Simon Glassc6c10e72019-05-17 22:00:46 -06001212 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1213 b'ter somewhere in here', first)
Simon Glass6b187df2017-11-12 21:52:27 -07001214
Simon Glass736bb0a2018-07-06 10:27:17 -06001215 def testPackUbootSplMicrocode(self):
1216 """Test that x86 microcode can be handled correctly in SPL"""
Simon Glass741f2d62018-10-01 12:22:30 -06001217 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass736bb0a2018-07-06 10:27:17 -06001218
1219 def testPackUbootSplMicrocodeReorder(self):
1220 """Test that order doesn't matter for microcode entries
1221
1222 This is the same as testPackUbootSplMicrocode but when we process the
1223 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1224 entry, so we reply on binman to try later.
1225 """
Simon Glass741f2d62018-10-01 12:22:30 -06001226 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass736bb0a2018-07-06 10:27:17 -06001227 ucode_second=True)
1228
Simon Glassca4f4ff2017-11-12 21:52:28 -07001229 def testPackMrc(self):
1230 """Test that an image with an MRC binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001231 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassca4f4ff2017-11-12 21:52:28 -07001232 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1233
Simon Glass47419ea2017-11-13 18:54:55 -07001234 def testSplDtb(self):
1235 """Test that an image with spl/u-boot-spl.dtb can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001236 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass47419ea2017-11-13 18:54:55 -07001237 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1238
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001239 def testSplNoDtb(self):
1240 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001241 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001242 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1243
Simon Glass19790632017-11-13 18:55:01 -07001244 def testSymbols(self):
1245 """Test binman can assign symbols embedded in U-Boot"""
Simon Glass1542c8b2019-08-24 07:22:56 -06001246 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass19790632017-11-13 18:55:01 -07001247 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1248 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Simon Glass3ab95982018-08-01 15:22:37 -06001249 self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr)
Simon Glass19790632017-11-13 18:55:01 -07001250
Simon Glass11ae93e2018-10-01 21:12:47 -06001251 self._SetupSplElf('u_boot_binman_syms')
Simon Glass741f2d62018-10-01 12:22:30 -06001252 data = self._DoReadFile('053_symbols.dts')
Simon Glass7c150132019-11-06 17:22:44 -07001253 sym_values = struct.pack('<LQLL', 0x00, 0x1c, 0x28, 0x04)
Simon Glassb87064c2019-08-24 07:23:05 -06001254 expected = (sym_values + U_BOOT_SPL_DATA[20:] +
Simon Glasse6d85ff2019-05-14 15:53:47 -06001255 tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
Simon Glassb87064c2019-08-24 07:23:05 -06001256 U_BOOT_SPL_DATA[20:])
Simon Glass19790632017-11-13 18:55:01 -07001257 self.assertEqual(expected, data)
1258
Simon Glassdd57c132018-06-01 09:38:11 -06001259 def testPackUnitAddress(self):
1260 """Test that we support multiple binaries with the same name"""
Simon Glass741f2d62018-10-01 12:22:30 -06001261 data = self._DoReadFile('054_unit_address.dts')
Simon Glassdd57c132018-06-01 09:38:11 -06001262 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1263
Simon Glass18546952018-06-01 09:38:16 -06001264 def testSections(self):
1265 """Basic test of sections"""
Simon Glass741f2d62018-10-01 12:22:30 -06001266 data = self._DoReadFile('055_sections.dts')
Simon Glassc6c10e72019-05-17 22:00:46 -06001267 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1268 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
1269 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
Simon Glass18546952018-06-01 09:38:16 -06001270 self.assertEqual(expected, data)
Simon Glass9fc60b42017-11-12 21:52:22 -07001271
Simon Glass3b0c38212018-06-01 09:38:20 -06001272 def testMap(self):
1273 """Tests outputting a map of the images"""
Simon Glass741f2d62018-10-01 12:22:30 -06001274 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001275 self.assertEqual('''ImagePos Offset Size Name
127600000000 00000000 00000028 main-section
127700000000 00000000 00000010 section@0
127800000000 00000000 00000004 u-boot
127900000010 00000010 00000010 section@1
128000000010 00000000 00000004 u-boot
128100000020 00000020 00000004 section@2
128200000020 00000000 00000004 u-boot
Simon Glass3b0c38212018-06-01 09:38:20 -06001283''', map_data)
1284
Simon Glassc8d48ef2018-06-01 09:38:21 -06001285 def testNamePrefix(self):
1286 """Tests that name prefixes are used"""
Simon Glass741f2d62018-10-01 12:22:30 -06001287 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001288 self.assertEqual('''ImagePos Offset Size Name
128900000000 00000000 00000028 main-section
129000000000 00000000 00000010 section@0
129100000000 00000000 00000004 ro-u-boot
129200000010 00000010 00000010 section@1
129300000010 00000000 00000004 rw-u-boot
Simon Glassc8d48ef2018-06-01 09:38:21 -06001294''', map_data)
1295
Simon Glass736bb0a2018-07-06 10:27:17 -06001296 def testUnknownContents(self):
1297 """Test that obtaining the contents works as expected"""
1298 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001299 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass8beb11e2019-07-08 14:25:47 -06001300 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glass16287932020-04-17 18:09:03 -06001301 "processing of contents: remaining ["
1302 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass736bb0a2018-07-06 10:27:17 -06001303
Simon Glass5c890232018-07-06 10:27:19 -06001304 def testBadChangeSize(self):
1305 """Test that trying to change the size of an entry fails"""
Simon Glassc52c9e72019-07-08 14:25:37 -06001306 try:
1307 state.SetAllowEntryExpansion(False)
1308 with self.assertRaises(ValueError) as e:
1309 self._DoReadFile('059_change_size.dts', True)
Simon Glass79d3c582019-07-20 12:23:57 -06001310 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glassc52c9e72019-07-08 14:25:37 -06001311 str(e.exception))
1312 finally:
1313 state.SetAllowEntryExpansion(True)
Simon Glass5c890232018-07-06 10:27:19 -06001314
Simon Glass16b8d6b2018-07-06 10:27:42 -06001315 def testUpdateFdt(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001316 """Test that we can update the device tree with offset/size info"""
Simon Glass741f2d62018-10-01 12:22:30 -06001317 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glass16b8d6b2018-07-06 10:27:42 -06001318 update_dtb=True)
Simon Glasscee02e62018-07-17 13:25:52 -06001319 dtb = fdt.Fdt(out_dtb_fname)
1320 dtb.Scan()
Simon Glass12bb1a92019-07-20 12:23:51 -06001321 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001322 self.assertEqual({
Simon Glassdbf6be92018-08-01 15:22:42 -06001323 'image-pos': 0,
Simon Glass8122f392018-07-17 13:25:28 -06001324 'offset': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001325 '_testing:offset': 32,
Simon Glass79d3c582019-07-20 12:23:57 -06001326 '_testing:size': 2,
Simon Glassdbf6be92018-08-01 15:22:42 -06001327 '_testing:image-pos': 32,
Simon Glass3ab95982018-08-01 15:22:37 -06001328 'section@0/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001329 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001330 'section@0/u-boot:image-pos': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001331 'section@0:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001332 'section@0:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001333 'section@0:image-pos': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001334
Simon Glass3ab95982018-08-01 15:22:37 -06001335 'section@1/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001336 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001337 'section@1/u-boot:image-pos': 16,
Simon Glass3ab95982018-08-01 15:22:37 -06001338 'section@1:offset': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001339 'section@1:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001340 'section@1:image-pos': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001341 'size': 40
1342 }, props)
1343
1344 def testUpdateFdtBad(self):
1345 """Test that we detect when ProcessFdt never completes"""
1346 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001347 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001348 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glass16287932020-04-17 18:09:03 -06001349 '[<binman.etype._testing.Entry__testing',
1350 str(e.exception))
Simon Glass5c890232018-07-06 10:27:19 -06001351
Simon Glass53af22a2018-07-17 13:25:32 -06001352 def testEntryArgs(self):
1353 """Test passing arguments to entries from the command line"""
1354 entry_args = {
1355 'test-str-arg': 'test1',
1356 'test-int-arg': '456',
1357 }
Simon Glass741f2d62018-10-01 12:22:30 -06001358 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001359 self.assertIn('image', control.images)
1360 entry = control.images['image'].GetEntries()['_testing']
1361 self.assertEqual('test0', entry.test_str_fdt)
1362 self.assertEqual('test1', entry.test_str_arg)
1363 self.assertEqual(123, entry.test_int_fdt)
1364 self.assertEqual(456, entry.test_int_arg)
1365
1366 def testEntryArgsMissing(self):
1367 """Test missing arguments and properties"""
1368 entry_args = {
1369 'test-int-arg': '456',
1370 }
Simon Glass741f2d62018-10-01 12:22:30 -06001371 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001372 entry = control.images['image'].GetEntries()['_testing']
1373 self.assertEqual('test0', entry.test_str_fdt)
1374 self.assertEqual(None, entry.test_str_arg)
1375 self.assertEqual(None, entry.test_int_fdt)
1376 self.assertEqual(456, entry.test_int_arg)
1377
1378 def testEntryArgsRequired(self):
1379 """Test missing arguments and properties"""
1380 entry_args = {
1381 'test-int-arg': '456',
1382 }
1383 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001384 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass53af22a2018-07-17 13:25:32 -06001385 self.assertIn("Node '/binman/_testing': Missing required "
1386 'properties/entry args: test-str-arg, test-int-fdt, test-int-arg',
1387 str(e.exception))
1388
1389 def testEntryArgsInvalidFormat(self):
1390 """Test that an invalid entry-argument format is detected"""
Simon Glass53cd5d92019-07-08 14:25:29 -06001391 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1392 '-ano-value']
Simon Glass53af22a2018-07-17 13:25:32 -06001393 with self.assertRaises(ValueError) as e:
1394 self._DoBinman(*args)
1395 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1396
1397 def testEntryArgsInvalidInteger(self):
1398 """Test that an invalid entry-argument integer is detected"""
1399 entry_args = {
1400 'test-int-arg': 'abc',
1401 }
1402 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001403 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001404 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1405 "'test-int-arg' (value 'abc') to integer",
1406 str(e.exception))
1407
1408 def testEntryArgsInvalidDatatype(self):
1409 """Test that an invalid entry-argument datatype is detected
1410
1411 This test could be written in entry_test.py except that it needs
1412 access to control.entry_args, which seems more than that module should
1413 be able to see.
1414 """
1415 entry_args = {
1416 'test-bad-datatype-arg': '12',
1417 }
1418 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001419 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass53af22a2018-07-17 13:25:32 -06001420 entry_args=entry_args)
1421 self.assertIn('GetArg() internal error: Unknown data type ',
1422 str(e.exception))
1423
Simon Glassbb748372018-07-17 13:25:33 -06001424 def testText(self):
1425 """Test for a text entry type"""
1426 entry_args = {
1427 'test-id': TEXT_DATA,
1428 'test-id2': TEXT_DATA2,
1429 'test-id3': TEXT_DATA3,
1430 }
Simon Glass741f2d62018-10-01 12:22:30 -06001431 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glassbb748372018-07-17 13:25:33 -06001432 entry_args=entry_args)
Simon Glassc6c10e72019-05-17 22:00:46 -06001433 expected = (tools.ToBytes(TEXT_DATA) +
1434 tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1435 tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
Simon Glassaa88b502019-07-08 13:18:40 -06001436 b'some text' + b'more text')
Simon Glassbb748372018-07-17 13:25:33 -06001437 self.assertEqual(expected, data)
1438
Simon Glassfd8d1f72018-07-17 13:25:36 -06001439 def testEntryDocs(self):
1440 """Test for creation of entry documentation"""
1441 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass87d43322020-08-05 13:27:46 -06001442 control.WriteEntryDocs(control.GetEntryModules())
Simon Glassfd8d1f72018-07-17 13:25:36 -06001443 self.assertTrue(len(stdout.getvalue()) > 0)
1444
1445 def testEntryDocsMissing(self):
1446 """Test handling of missing entry documentation"""
1447 with self.assertRaises(ValueError) as e:
1448 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass87d43322020-08-05 13:27:46 -06001449 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glassfd8d1f72018-07-17 13:25:36 -06001450 self.assertIn('Documentation is missing for modules: u_boot',
1451 str(e.exception))
1452
Simon Glass11e36cc2018-07-17 13:25:38 -06001453 def testFmap(self):
1454 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001455 data = self._DoReadFile('067_fmap.dts')
Simon Glass11e36cc2018-07-17 13:25:38 -06001456 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc6c10e72019-05-17 22:00:46 -06001457 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1458 U_BOOT_DATA + tools.GetBytes(ord('a'), 12))
Simon Glass11e36cc2018-07-17 13:25:38 -06001459 self.assertEqual(expected, data[:32])
Simon Glassc6c10e72019-05-17 22:00:46 -06001460 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass11e36cc2018-07-17 13:25:38 -06001461 self.assertEqual(1, fhdr.ver_major)
1462 self.assertEqual(0, fhdr.ver_minor)
1463 self.assertEqual(0, fhdr.base)
1464 self.assertEqual(16 + 16 +
1465 fmap_util.FMAP_HEADER_LEN +
1466 fmap_util.FMAP_AREA_LEN * 3, fhdr.image_size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001467 self.assertEqual(b'FMAP', fhdr.name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001468 self.assertEqual(3, fhdr.nareas)
1469 for fentry in fentries:
1470 self.assertEqual(0, fentry.flags)
1471
1472 self.assertEqual(0, fentries[0].offset)
1473 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001474 self.assertEqual(b'RO_U_BOOT', fentries[0].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001475
1476 self.assertEqual(16, fentries[1].offset)
1477 self.assertEqual(4, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001478 self.assertEqual(b'RW_U_BOOT', fentries[1].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001479
1480 self.assertEqual(32, fentries[2].offset)
1481 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1482 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001483 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001484
Simon Glassec127af2018-07-17 13:25:39 -06001485 def testBlobNamedByArg(self):
1486 """Test we can add a blob with the filename coming from an entry arg"""
1487 entry_args = {
1488 'cros-ec-rw-path': 'ecrw.bin',
1489 }
Simon Glass741f2d62018-10-01 12:22:30 -06001490 data, _, _, _ = self._DoReadFileDtb('068_blob_named_by_arg.dts',
Simon Glassec127af2018-07-17 13:25:39 -06001491 entry_args=entry_args)
1492
Simon Glass3af8e492018-07-17 13:25:40 -06001493 def testFill(self):
1494 """Test for an fill entry type"""
Simon Glass741f2d62018-10-01 12:22:30 -06001495 data = self._DoReadFile('069_fill.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001496 expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
Simon Glass3af8e492018-07-17 13:25:40 -06001497 self.assertEqual(expected, data)
1498
1499 def testFillNoSize(self):
1500 """Test for an fill entry type with no size"""
1501 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001502 self._DoReadFile('070_fill_no_size.dts')
Simon Glass3af8e492018-07-17 13:25:40 -06001503 self.assertIn("'fill' entry must have a size property",
1504 str(e.exception))
1505
Simon Glass0ef87aa2018-07-17 13:25:44 -06001506 def _HandleGbbCommand(self, pipe_list):
1507 """Fake calls to the futility utility"""
1508 if pipe_list[0][0] == 'futility':
1509 fname = pipe_list[0][-1]
1510 # Append our GBB data to the file, which will happen every time the
1511 # futility command is called.
Simon Glass1d0ebf72019-05-14 15:53:42 -06001512 with open(fname, 'ab') as fd:
Simon Glass0ef87aa2018-07-17 13:25:44 -06001513 fd.write(GBB_DATA)
1514 return command.CommandResult()
1515
1516 def testGbb(self):
1517 """Test for the Chromium OS Google Binary Block"""
1518 command.test_result = self._HandleGbbCommand
1519 entry_args = {
1520 'keydir': 'devkeys',
1521 'bmpblk': 'bmpblk.bin',
1522 }
Simon Glass741f2d62018-10-01 12:22:30 -06001523 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glass0ef87aa2018-07-17 13:25:44 -06001524
1525 # Since futility
Simon Glasse6d85ff2019-05-14 15:53:47 -06001526 expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1527 tools.GetBytes(0, 0x2180 - 16))
Simon Glass0ef87aa2018-07-17 13:25:44 -06001528 self.assertEqual(expected, data)
1529
1530 def testGbbTooSmall(self):
1531 """Test for the Chromium OS Google Binary Block being large enough"""
1532 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001533 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001534 self.assertIn("Node '/binman/gbb': GBB is too small",
1535 str(e.exception))
1536
1537 def testGbbNoSize(self):
1538 """Test for the Chromium OS Google Binary Block having a size"""
1539 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001540 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001541 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1542 str(e.exception))
1543
Simon Glass24d0d3c2018-07-17 13:25:47 -06001544 def _HandleVblockCommand(self, pipe_list):
1545 """Fake calls to the futility utility"""
1546 if pipe_list[0][0] == 'futility':
1547 fname = pipe_list[0][3]
Simon Glassa326b492018-09-14 04:57:11 -06001548 with open(fname, 'wb') as fd:
Simon Glass24d0d3c2018-07-17 13:25:47 -06001549 fd.write(VBLOCK_DATA)
1550 return command.CommandResult()
1551
1552 def testVblock(self):
1553 """Test for the Chromium OS Verified Boot Block"""
1554 command.test_result = self._HandleVblockCommand
1555 entry_args = {
1556 'keydir': 'devkeys',
1557 }
Simon Glass741f2d62018-10-01 12:22:30 -06001558 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass24d0d3c2018-07-17 13:25:47 -06001559 entry_args=entry_args)
1560 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1561 self.assertEqual(expected, data)
1562
1563 def testVblockNoContent(self):
1564 """Test we detect a vblock which has no content to sign"""
1565 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001566 self._DoReadFile('075_vblock_no_content.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001567 self.assertIn("Node '/binman/vblock': Vblock must have a 'content' "
1568 'property', str(e.exception))
1569
1570 def testVblockBadPhandle(self):
1571 """Test that we detect a vblock with an invalid phandle in contents"""
1572 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001573 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001574 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1575 '1000', str(e.exception))
1576
1577 def testVblockBadEntry(self):
1578 """Test that we detect an entry that points to a non-entry"""
1579 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001580 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001581 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1582 "'other'", str(e.exception))
1583
Simon Glassb8ef5b62018-07-17 13:25:48 -06001584 def testTpl(self):
Simon Glass2090f1e2019-08-24 07:23:00 -06001585 """Test that an image with TPL and its device tree can be created"""
Simon Glassb8ef5b62018-07-17 13:25:48 -06001586 # ELF file with a '__bss_size' symbol
Simon Glass2090f1e2019-08-24 07:23:00 -06001587 self._SetupTplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001588 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glassb8ef5b62018-07-17 13:25:48 -06001589 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1590
Simon Glass15a587c2018-07-17 13:25:51 -06001591 def testUsesPos(self):
1592 """Test that the 'pos' property cannot be used anymore"""
1593 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001594 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass15a587c2018-07-17 13:25:51 -06001595 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1596 "'pos'", str(e.exception))
1597
Simon Glassd178eab2018-09-14 04:57:08 -06001598 def testFillZero(self):
1599 """Test for an fill entry type with a size of 0"""
Simon Glass741f2d62018-10-01 12:22:30 -06001600 data = self._DoReadFile('080_fill_empty.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001601 self.assertEqual(tools.GetBytes(0, 16), data)
Simon Glassd178eab2018-09-14 04:57:08 -06001602
Simon Glass0b489362018-09-14 04:57:09 -06001603 def testTextMissing(self):
1604 """Test for a text entry type where there is no text"""
1605 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001606 self._DoReadFileDtb('066_text.dts',)
Simon Glass0b489362018-09-14 04:57:09 -06001607 self.assertIn("Node '/binman/text': No value provided for text label "
1608 "'test-id'", str(e.exception))
1609
Simon Glass35b384c2018-09-14 04:57:10 -06001610 def testPackStart16Tpl(self):
1611 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001612 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glass35b384c2018-09-14 04:57:10 -06001613 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1614
Simon Glass0bfa7b02018-09-14 04:57:12 -06001615 def testSelectImage(self):
1616 """Test that we can select which images to build"""
Simon Glasseb833d82019-04-25 21:58:34 -06001617 expected = 'Skipping images: image1'
Simon Glass0bfa7b02018-09-14 04:57:12 -06001618
Simon Glasseb833d82019-04-25 21:58:34 -06001619 # We should only get the expected message in verbose mode
Simon Glassee0c9a72019-07-08 13:18:48 -06001620 for verbosity in (0, 2):
Simon Glasseb833d82019-04-25 21:58:34 -06001621 with test_util.capture_sys_output() as (stdout, stderr):
1622 retcode = self._DoTestFile('006_dual_image.dts',
1623 verbosity=verbosity,
1624 images=['image2'])
1625 self.assertEqual(0, retcode)
1626 if verbosity:
1627 self.assertIn(expected, stdout.getvalue())
1628 else:
1629 self.assertNotIn(expected, stdout.getvalue())
1630
1631 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1632 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
Simon Glassf86a7362019-07-20 12:24:10 -06001633 self._CleanupOutputDir()
Simon Glass0bfa7b02018-09-14 04:57:12 -06001634
Simon Glass6ed45ba2018-09-14 04:57:24 -06001635 def testUpdateFdtAll(self):
1636 """Test that all device trees are updated with offset/size info"""
Simon Glass3c081312019-07-08 14:25:26 -06001637 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glass6ed45ba2018-09-14 04:57:24 -06001638
1639 base_expected = {
1640 'section:image-pos': 0,
1641 'u-boot-tpl-dtb:size': 513,
1642 'u-boot-spl-dtb:size': 513,
1643 'u-boot-spl-dtb:offset': 493,
1644 'image-pos': 0,
1645 'section/u-boot-dtb:image-pos': 0,
1646 'u-boot-spl-dtb:image-pos': 493,
1647 'section/u-boot-dtb:size': 493,
1648 'u-boot-tpl-dtb:image-pos': 1006,
1649 'section/u-boot-dtb:offset': 0,
1650 'section:size': 493,
1651 'offset': 0,
1652 'section:offset': 0,
1653 'u-boot-tpl-dtb:offset': 1006,
1654 'size': 1519
1655 }
1656
1657 # We expect three device-tree files in the output, one after the other.
1658 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1659 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1660 # main U-Boot tree. All three should have the same postions and offset.
1661 start = 0
1662 for item in ['', 'spl', 'tpl']:
1663 dtb = fdt.Fdt.FromData(data[start:])
1664 dtb.Scan()
Simon Glass12bb1a92019-07-20 12:23:51 -06001665 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
1666 ['spl', 'tpl'])
Simon Glass6ed45ba2018-09-14 04:57:24 -06001667 expected = dict(base_expected)
1668 if item:
1669 expected[item] = 0
1670 self.assertEqual(expected, props)
1671 start += dtb._fdt_obj.totalsize()
1672
1673 def testUpdateFdtOutput(self):
1674 """Test that output DTB files are updated"""
1675 try:
Simon Glass741f2d62018-10-01 12:22:30 -06001676 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glass6ed45ba2018-09-14 04:57:24 -06001677 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1678
1679 # Unfortunately, compiling a source file always results in a file
1680 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass741f2d62018-10-01 12:22:30 -06001681 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glass6ed45ba2018-09-14 04:57:24 -06001682 # binman as a file called u-boot.dtb. To fix this, copy the file
1683 # over to the expected place.
Simon Glass6ed45ba2018-09-14 04:57:24 -06001684 start = 0
1685 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1686 'tpl/u-boot-tpl.dtb.out']:
1687 dtb = fdt.Fdt.FromData(data[start:])
1688 size = dtb._fdt_obj.totalsize()
1689 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1690 outdata = tools.ReadFile(pathname)
1691 name = os.path.split(fname)[0]
1692
1693 if name:
1694 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1695 else:
1696 orig_indata = dtb_data
1697 self.assertNotEqual(outdata, orig_indata,
1698 "Expected output file '%s' be updated" % pathname)
1699 self.assertEqual(outdata, data[start:start + size],
1700 "Expected output file '%s' to match output image" %
1701 pathname)
1702 start += size
1703 finally:
1704 self._ResetDtbs()
1705
Simon Glass83d73c22018-09-14 04:57:26 -06001706 def _decompress(self, data):
Simon Glassff5c7e32019-07-08 13:18:42 -06001707 return tools.Decompress(data, 'lz4')
Simon Glass83d73c22018-09-14 04:57:26 -06001708
1709 def testCompress(self):
1710 """Test compression of blobs"""
Simon Glassac62fba2019-07-08 13:18:53 -06001711 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06001712 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass83d73c22018-09-14 04:57:26 -06001713 use_real_dtb=True, update_dtb=True)
1714 dtb = fdt.Fdt(out_dtb_fname)
1715 dtb.Scan()
1716 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1717 orig = self._decompress(data)
1718 self.assertEquals(COMPRESS_DATA, orig)
1719 expected = {
1720 'blob:uncomp-size': len(COMPRESS_DATA),
1721 'blob:size': len(data),
1722 'size': len(data),
1723 }
1724 self.assertEqual(expected, props)
1725
Simon Glass0a98b282018-09-14 04:57:28 -06001726 def testFiles(self):
1727 """Test bringing in multiple files"""
Simon Glass741f2d62018-10-01 12:22:30 -06001728 data = self._DoReadFile('084_files.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001729 self.assertEqual(FILES_DATA, data)
1730
1731 def testFilesCompress(self):
1732 """Test bringing in multiple files and compressing them"""
Simon Glassac62fba2019-07-08 13:18:53 -06001733 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06001734 data = self._DoReadFile('085_files_compress.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001735
1736 image = control.images['image']
1737 entries = image.GetEntries()
1738 files = entries['files']
Simon Glass8beb11e2019-07-08 14:25:47 -06001739 entries = files._entries
Simon Glass0a98b282018-09-14 04:57:28 -06001740
Simon Glassc6c10e72019-05-17 22:00:46 -06001741 orig = b''
Simon Glass0a98b282018-09-14 04:57:28 -06001742 for i in range(1, 3):
1743 key = '%d.dat' % i
1744 start = entries[key].image_pos
1745 len = entries[key].size
1746 chunk = data[start:start + len]
1747 orig += self._decompress(chunk)
1748
1749 self.assertEqual(FILES_DATA, orig)
1750
1751 def testFilesMissing(self):
1752 """Test missing files"""
1753 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001754 data = self._DoReadFile('086_files_none.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001755 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1756 'no files', str(e.exception))
1757
1758 def testFilesNoPattern(self):
1759 """Test missing files"""
1760 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001761 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001762 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1763 str(e.exception))
1764
Simon Glassba64a0b2018-09-14 04:57:29 -06001765 def testExpandSize(self):
1766 """Test an expanding entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001767 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
Simon Glassba64a0b2018-09-14 04:57:29 -06001768 map=True)
Simon Glassc6c10e72019-05-17 22:00:46 -06001769 expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA +
1770 MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA +
1771 tools.GetBytes(ord('c'), 8) + U_BOOT_DATA +
1772 tools.GetBytes(ord('d'), 8))
Simon Glassba64a0b2018-09-14 04:57:29 -06001773 self.assertEqual(expect, data)
1774 self.assertEqual('''ImagePos Offset Size Name
177500000000 00000000 00000028 main-section
177600000000 00000000 00000008 fill
177700000008 00000008 00000004 u-boot
17780000000c 0000000c 00000004 section
17790000000c 00000000 00000003 intel-mrc
178000000010 00000010 00000004 u-boot2
178100000014 00000014 0000000c section2
178200000014 00000000 00000008 fill
17830000001c 00000008 00000004 u-boot
178400000020 00000020 00000008 fill2
1785''', map_data)
1786
1787 def testExpandSizeBad(self):
1788 """Test an expanding entry which fails to provide contents"""
Simon Glass163ed6c2018-09-14 04:57:36 -06001789 with test_util.capture_sys_output() as (stdout, stderr):
1790 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001791 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
Simon Glassba64a0b2018-09-14 04:57:29 -06001792 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
1793 'expanding entry', str(e.exception))
1794
Simon Glasse0e5df92018-09-14 04:57:31 -06001795 def testHash(self):
1796 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001797 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06001798 use_real_dtb=True, update_dtb=True)
1799 dtb = fdt.Fdt(out_dtb_fname)
1800 dtb.Scan()
1801 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
1802 m = hashlib.sha256()
1803 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001804 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06001805
1806 def testHashNoAlgo(self):
1807 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001808 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06001809 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
1810 'hash node', str(e.exception))
1811
1812 def testHashBadAlgo(self):
1813 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001814 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06001815 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
1816 str(e.exception))
1817
1818 def testHashSection(self):
1819 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001820 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06001821 use_real_dtb=True, update_dtb=True)
1822 dtb = fdt.Fdt(out_dtb_fname)
1823 dtb.Scan()
1824 hash_node = dtb.GetNode('/binman/section/hash').props['value']
1825 m = hashlib.sha256()
1826 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001827 m.update(tools.GetBytes(ord('a'), 16))
1828 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06001829
Simon Glassf0253632018-09-14 04:57:32 -06001830 def testPackUBootTplMicrocode(self):
1831 """Test that x86 microcode can be handled correctly in TPL
1832
1833 We expect to see the following in the image, in order:
1834 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
1835 place
1836 u-boot-tpl.dtb with the microcode removed
1837 the microcode
1838 """
Simon Glass2090f1e2019-08-24 07:23:00 -06001839 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass741f2d62018-10-01 12:22:30 -06001840 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glassf0253632018-09-14 04:57:32 -06001841 U_BOOT_TPL_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001842 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
1843 b'ter somewhere in here', first)
Simon Glassf0253632018-09-14 04:57:32 -06001844
Simon Glassf8f8df62018-09-14 04:57:34 -06001845 def testFmapX86(self):
1846 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001847 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassf8f8df62018-09-14 04:57:34 -06001848 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc6c10e72019-05-17 22:00:46 -06001849 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06001850 self.assertEqual(expected, data[:32])
1851 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1852
1853 self.assertEqual(0x100, fhdr.image_size)
1854
1855 self.assertEqual(0, fentries[0].offset)
1856 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001857 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001858
1859 self.assertEqual(4, fentries[1].offset)
1860 self.assertEqual(3, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001861 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001862
1863 self.assertEqual(32, fentries[2].offset)
1864 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1865 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001866 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001867
1868 def testFmapX86Section(self):
1869 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001870 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glassc6c10e72019-05-17 22:00:46 -06001871 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06001872 self.assertEqual(expected, data[:32])
1873 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
1874
1875 self.assertEqual(0x100, fhdr.image_size)
1876
1877 self.assertEqual(0, fentries[0].offset)
1878 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001879 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001880
1881 self.assertEqual(4, fentries[1].offset)
1882 self.assertEqual(3, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001883 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001884
1885 self.assertEqual(36, fentries[2].offset)
1886 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1887 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001888 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001889
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001890 def testElf(self):
1891 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001892 self._SetupSplElf()
Simon Glass2090f1e2019-08-24 07:23:00 -06001893 self._SetupTplElf()
Simon Glass53e22bf2019-08-24 07:22:53 -06001894 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001895 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001896 data = self._DoReadFile('096_elf.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001897
Simon Glass093d1682019-07-08 13:18:25 -06001898 def testElfStrip(self):
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001899 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001900 self._SetupSplElf()
Simon Glass53e22bf2019-08-24 07:22:53 -06001901 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001902 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001903 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001904
Simon Glass163ed6c2018-09-14 04:57:36 -06001905 def testPackOverlapMap(self):
1906 """Test that overlapping regions are detected"""
1907 with test_util.capture_sys_output() as (stdout, stderr):
1908 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001909 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glass163ed6c2018-09-14 04:57:36 -06001910 map_fname = tools.GetOutputFilename('image.map')
1911 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
1912 stdout.getvalue())
1913
1914 # We should not get an inmage, but there should be a map file
1915 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
1916 self.assertTrue(os.path.exists(map_fname))
Simon Glasseb546ac2019-05-17 22:00:51 -06001917 map_data = tools.ReadFile(map_fname, binary=False)
Simon Glass163ed6c2018-09-14 04:57:36 -06001918 self.assertEqual('''ImagePos Offset Size Name
1919<none> 00000000 00000007 main-section
1920<none> 00000000 00000004 u-boot
1921<none> 00000003 00000004 u-boot-align
1922''', map_data)
1923
Simon Glass093d1682019-07-08 13:18:25 -06001924 def testPackRefCode(self):
Simon Glass3ae192c2018-10-01 12:22:31 -06001925 """Test that an image with an Intel Reference code binary works"""
1926 data = self._DoReadFile('100_intel_refcode.dts')
1927 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
1928
Simon Glass9481c802019-04-25 21:58:39 -06001929 def testSectionOffset(self):
1930 """Tests use of a section with an offset"""
1931 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
1932 map=True)
1933 self.assertEqual('''ImagePos Offset Size Name
193400000000 00000000 00000038 main-section
193500000004 00000004 00000010 section@0
193600000004 00000000 00000004 u-boot
193700000018 00000018 00000010 section@1
193800000018 00000000 00000004 u-boot
19390000002c 0000002c 00000004 section@2
19400000002c 00000000 00000004 u-boot
1941''', map_data)
1942 self.assertEqual(data,
Simon Glasse6d85ff2019-05-14 15:53:47 -06001943 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1944 tools.GetBytes(0x21, 12) +
1945 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1946 tools.GetBytes(0x61, 12) +
1947 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1948 tools.GetBytes(0x26, 8))
Simon Glass9481c802019-04-25 21:58:39 -06001949
Simon Glassac62fba2019-07-08 13:18:53 -06001950 def testCbfsRaw(self):
1951 """Test base handling of a Coreboot Filesystem (CBFS)
1952
1953 The exact contents of the CBFS is verified by similar tests in
1954 cbfs_util_test.py. The tests here merely check that the files added to
1955 the CBFS can be found in the final image.
1956 """
1957 data = self._DoReadFile('102_cbfs_raw.dts')
1958 size = 0xb0
1959
1960 cbfs = cbfs_util.CbfsReader(data)
1961 self.assertEqual(size, cbfs.rom_size)
1962
1963 self.assertIn('u-boot-dtb', cbfs.files)
1964 cfile = cbfs.files['u-boot-dtb']
1965 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
1966
1967 def testCbfsArch(self):
1968 """Test on non-x86 architecture"""
1969 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
1970 size = 0x100
1971
1972 cbfs = cbfs_util.CbfsReader(data)
1973 self.assertEqual(size, cbfs.rom_size)
1974
1975 self.assertIn('u-boot-dtb', cbfs.files)
1976 cfile = cbfs.files['u-boot-dtb']
1977 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
1978
1979 def testCbfsStage(self):
1980 """Tests handling of a Coreboot Filesystem (CBFS)"""
1981 if not elf.ELF_TOOLS:
1982 self.skipTest('Python elftools not available')
1983 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
1984 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
1985 size = 0xb0
1986
1987 data = self._DoReadFile('104_cbfs_stage.dts')
1988 cbfs = cbfs_util.CbfsReader(data)
1989 self.assertEqual(size, cbfs.rom_size)
1990
1991 self.assertIn('u-boot', cbfs.files)
1992 cfile = cbfs.files['u-boot']
1993 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
1994
1995 def testCbfsRawCompress(self):
1996 """Test handling of compressing raw files"""
1997 self._CheckLz4()
1998 data = self._DoReadFile('105_cbfs_raw_compress.dts')
1999 size = 0x140
2000
2001 cbfs = cbfs_util.CbfsReader(data)
2002 self.assertIn('u-boot', cbfs.files)
2003 cfile = cbfs.files['u-boot']
2004 self.assertEqual(COMPRESS_DATA, cfile.data)
2005
2006 def testCbfsBadArch(self):
2007 """Test handling of a bad architecture"""
2008 with self.assertRaises(ValueError) as e:
2009 self._DoReadFile('106_cbfs_bad_arch.dts')
2010 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2011
2012 def testCbfsNoSize(self):
2013 """Test handling of a missing size property"""
2014 with self.assertRaises(ValueError) as e:
2015 self._DoReadFile('107_cbfs_no_size.dts')
2016 self.assertIn('entry must have a size property', str(e.exception))
2017
2018 def testCbfsNoCOntents(self):
2019 """Test handling of a CBFS entry which does not provide contentsy"""
2020 with self.assertRaises(ValueError) as e:
2021 self._DoReadFile('108_cbfs_no_contents.dts')
2022 self.assertIn('Could not complete processing of contents',
2023 str(e.exception))
2024
2025 def testCbfsBadCompress(self):
2026 """Test handling of a bad architecture"""
2027 with self.assertRaises(ValueError) as e:
2028 self._DoReadFile('109_cbfs_bad_compress.dts')
2029 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2030 str(e.exception))
2031
2032 def testCbfsNamedEntries(self):
2033 """Test handling of named entries"""
2034 data = self._DoReadFile('110_cbfs_name.dts')
2035
2036 cbfs = cbfs_util.CbfsReader(data)
2037 self.assertIn('FRED', cbfs.files)
2038 cfile1 = cbfs.files['FRED']
2039 self.assertEqual(U_BOOT_DATA, cfile1.data)
2040
2041 self.assertIn('hello', cbfs.files)
2042 cfile2 = cbfs.files['hello']
2043 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2044
Simon Glassc5ac1382019-07-08 13:18:54 -06002045 def _SetupIfwi(self, fname):
2046 """Set up to run an IFWI test
2047
2048 Args:
2049 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2050 """
2051 self._SetupSplElf()
Simon Glass2090f1e2019-08-24 07:23:00 -06002052 self._SetupTplElf()
Simon Glassc5ac1382019-07-08 13:18:54 -06002053
2054 # Intel Integrated Firmware Image (IFWI) file
2055 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2056 data = fd.read()
2057 TestFunctional._MakeInputFile(fname,data)
2058
2059 def _CheckIfwi(self, data):
2060 """Check that an image with an IFWI contains the correct output
2061
2062 Args:
2063 data: Conents of output file
2064 """
2065 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
2066 if data[:0x1000] != expected_desc:
2067 self.fail('Expected descriptor binary at start of image')
2068
2069 # We expect to find the TPL wil in subpart IBBP entry IBBL
2070 image_fname = tools.GetOutputFilename('image.bin')
2071 tpl_fname = tools.GetOutputFilename('tpl.out')
2072 tools.RunIfwiTool(image_fname, tools.CMD_EXTRACT, fname=tpl_fname,
2073 subpart='IBBP', entry_name='IBBL')
2074
2075 tpl_data = tools.ReadFile(tpl_fname)
Simon Glasse95be632019-08-24 07:22:51 -06002076 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glassc5ac1382019-07-08 13:18:54 -06002077
2078 def testPackX86RomIfwi(self):
2079 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2080 self._SetupIfwi('fitimage.bin')
Simon Glass9255f3c2019-08-24 07:23:01 -06002081 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002082 self._CheckIfwi(data)
2083
2084 def testPackX86RomIfwiNoDesc(self):
2085 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2086 self._SetupIfwi('ifwi.bin')
Simon Glass9255f3c2019-08-24 07:23:01 -06002087 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002088 self._CheckIfwi(data)
2089
2090 def testPackX86RomIfwiNoData(self):
2091 """Test that an x86 ROM with IFWI handles missing data"""
2092 self._SetupIfwi('ifwi.bin')
2093 with self.assertRaises(ValueError) as e:
Simon Glass9255f3c2019-08-24 07:23:01 -06002094 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002095 self.assertIn('Could not complete processing of contents',
2096 str(e.exception))
Simon Glass53af22a2018-07-17 13:25:32 -06002097
Simon Glasse073d4e2019-07-08 13:18:56 -06002098 def testCbfsOffset(self):
2099 """Test a CBFS with files at particular offsets
2100
2101 Like all CFBS tests, this is just checking the logic that calls
2102 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2103 """
2104 data = self._DoReadFile('114_cbfs_offset.dts')
2105 size = 0x200
2106
2107 cbfs = cbfs_util.CbfsReader(data)
2108 self.assertEqual(size, cbfs.rom_size)
2109
2110 self.assertIn('u-boot', cbfs.files)
2111 cfile = cbfs.files['u-boot']
2112 self.assertEqual(U_BOOT_DATA, cfile.data)
2113 self.assertEqual(0x40, cfile.cbfs_offset)
2114
2115 self.assertIn('u-boot-dtb', cbfs.files)
2116 cfile2 = cbfs.files['u-boot-dtb']
2117 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2118 self.assertEqual(0x140, cfile2.cbfs_offset)
2119
Simon Glass086cec92019-07-08 14:25:27 -06002120 def testFdtmap(self):
2121 """Test an FDT map can be inserted in the image"""
2122 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2123 fdtmap_data = data[len(U_BOOT_DATA):]
2124 magic = fdtmap_data[:8]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002125 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass086cec92019-07-08 14:25:27 -06002126 self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
2127
2128 fdt_data = fdtmap_data[16:]
2129 dtb = fdt.Fdt.FromData(fdt_data)
2130 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002131 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass086cec92019-07-08 14:25:27 -06002132 self.assertEqual({
2133 'image-pos': 0,
2134 'offset': 0,
2135 'u-boot:offset': 0,
2136 'u-boot:size': len(U_BOOT_DATA),
2137 'u-boot:image-pos': 0,
2138 'fdtmap:image-pos': 4,
2139 'fdtmap:offset': 4,
2140 'fdtmap:size': len(fdtmap_data),
2141 'size': len(data),
2142 }, props)
2143
2144 def testFdtmapNoMatch(self):
2145 """Check handling of an FDT map when the section cannot be found"""
2146 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2147
2148 # Mangle the section name, which should cause a mismatch between the
2149 # correct FDT path and the one expected by the section
2150 image = control.images['image']
Simon Glasscf228942019-07-08 14:25:28 -06002151 image._node.path += '-suffix'
Simon Glass086cec92019-07-08 14:25:27 -06002152 entries = image.GetEntries()
2153 fdtmap = entries['fdtmap']
2154 with self.assertRaises(ValueError) as e:
2155 fdtmap._GetFdtmap()
2156 self.assertIn("Cannot locate node for path '/binman-suffix'",
2157 str(e.exception))
2158
Simon Glasscf228942019-07-08 14:25:28 -06002159 def testFdtmapHeader(self):
2160 """Test an FDT map and image header can be inserted in the image"""
2161 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2162 fdtmap_pos = len(U_BOOT_DATA)
2163 fdtmap_data = data[fdtmap_pos:]
2164 fdt_data = fdtmap_data[16:]
2165 dtb = fdt.Fdt.FromData(fdt_data)
2166 fdt_size = dtb.GetFdtObj().totalsize()
2167 hdr_data = data[-8:]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002168 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002169 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2170 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2171
2172 def testFdtmapHeaderStart(self):
2173 """Test an image header can be inserted at the image start"""
2174 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2175 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2176 hdr_data = data[:8]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002177 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002178 offset = struct.unpack('<I', hdr_data[4:])[0]
2179 self.assertEqual(fdtmap_pos, offset)
2180
2181 def testFdtmapHeaderPos(self):
2182 """Test an image header can be inserted at a chosen position"""
2183 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2184 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2185 hdr_data = data[0x80:0x88]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002186 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002187 offset = struct.unpack('<I', hdr_data[4:])[0]
2188 self.assertEqual(fdtmap_pos, offset)
2189
2190 def testHeaderMissingFdtmap(self):
2191 """Test an image header requires an fdtmap"""
2192 with self.assertRaises(ValueError) as e:
2193 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2194 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2195 str(e.exception))
2196
2197 def testHeaderNoLocation(self):
2198 """Test an image header with a no specified location is detected"""
2199 with self.assertRaises(ValueError) as e:
2200 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2201 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2202 str(e.exception))
2203
Simon Glassc52c9e72019-07-08 14:25:37 -06002204 def testEntryExpand(self):
2205 """Test expanding an entry after it is packed"""
2206 data = self._DoReadFile('121_entry_expand.dts')
Simon Glass79d3c582019-07-20 12:23:57 -06002207 self.assertEqual(b'aaa', data[:3])
2208 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2209 self.assertEqual(b'aaa', data[-3:])
Simon Glassc52c9e72019-07-08 14:25:37 -06002210
2211 def testEntryExpandBad(self):
2212 """Test expanding an entry after it is packed, twice"""
2213 with self.assertRaises(ValueError) as e:
2214 self._DoReadFile('122_entry_expand_twice.dts')
Simon Glass61ec04f2019-07-20 12:23:58 -06002215 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glassc52c9e72019-07-08 14:25:37 -06002216 str(e.exception))
2217
2218 def testEntryExpandSection(self):
2219 """Test expanding an entry within a section after it is packed"""
2220 data = self._DoReadFile('123_entry_expand_section.dts')
Simon Glass79d3c582019-07-20 12:23:57 -06002221 self.assertEqual(b'aaa', data[:3])
2222 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2223 self.assertEqual(b'aaa', data[-3:])
Simon Glassc52c9e72019-07-08 14:25:37 -06002224
Simon Glass6c223fd2019-07-08 14:25:38 -06002225 def testCompressDtb(self):
2226 """Test that compress of device-tree files is supported"""
2227 self._CheckLz4()
2228 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2229 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2230 comp_data = data[len(U_BOOT_DATA):]
2231 orig = self._decompress(comp_data)
2232 dtb = fdt.Fdt.FromData(orig)
2233 dtb.Scan()
2234 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2235 expected = {
2236 'u-boot:size': len(U_BOOT_DATA),
2237 'u-boot-dtb:uncomp-size': len(orig),
2238 'u-boot-dtb:size': len(comp_data),
2239 'size': len(data),
2240 }
2241 self.assertEqual(expected, props)
2242
Simon Glass69f7cb32019-07-08 14:25:41 -06002243 def testCbfsUpdateFdt(self):
2244 """Test that we can update the device tree with CBFS offset/size info"""
2245 self._CheckLz4()
2246 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2247 update_dtb=True)
2248 dtb = fdt.Fdt(out_dtb_fname)
2249 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002250 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass69f7cb32019-07-08 14:25:41 -06002251 del props['cbfs/u-boot:size']
2252 self.assertEqual({
2253 'offset': 0,
2254 'size': len(data),
2255 'image-pos': 0,
2256 'cbfs:offset': 0,
2257 'cbfs:size': len(data),
2258 'cbfs:image-pos': 0,
2259 'cbfs/u-boot:offset': 0x38,
2260 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2261 'cbfs/u-boot:image-pos': 0x38,
2262 'cbfs/u-boot-dtb:offset': 0xb8,
2263 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2264 'cbfs/u-boot-dtb:image-pos': 0xb8,
2265 }, props)
2266
Simon Glass8a1ad062019-07-08 14:25:42 -06002267 def testCbfsBadType(self):
2268 """Test an image header with a no specified location is detected"""
2269 with self.assertRaises(ValueError) as e:
2270 self._DoReadFile('126_cbfs_bad_type.dts')
2271 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2272
Simon Glass41b8ba02019-07-08 14:25:43 -06002273 def testList(self):
2274 """Test listing the files in an image"""
2275 self._CheckLz4()
2276 data = self._DoReadFile('127_list.dts')
2277 image = control.images['image']
2278 entries = image.BuildEntryList()
2279 self.assertEqual(7, len(entries))
2280
2281 ent = entries[0]
2282 self.assertEqual(0, ent.indent)
2283 self.assertEqual('main-section', ent.name)
2284 self.assertEqual('section', ent.etype)
2285 self.assertEqual(len(data), ent.size)
2286 self.assertEqual(0, ent.image_pos)
2287 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002288 self.assertEqual(0, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002289
2290 ent = entries[1]
2291 self.assertEqual(1, ent.indent)
2292 self.assertEqual('u-boot', ent.name)
2293 self.assertEqual('u-boot', ent.etype)
2294 self.assertEqual(len(U_BOOT_DATA), ent.size)
2295 self.assertEqual(0, ent.image_pos)
2296 self.assertEqual(None, ent.uncomp_size)
2297 self.assertEqual(0, ent.offset)
2298
2299 ent = entries[2]
2300 self.assertEqual(1, ent.indent)
2301 self.assertEqual('section', ent.name)
2302 self.assertEqual('section', ent.etype)
2303 section_size = ent.size
2304 self.assertEqual(0x100, ent.image_pos)
2305 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002306 self.assertEqual(0x100, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002307
2308 ent = entries[3]
2309 self.assertEqual(2, ent.indent)
2310 self.assertEqual('cbfs', ent.name)
2311 self.assertEqual('cbfs', ent.etype)
2312 self.assertEqual(0x400, ent.size)
2313 self.assertEqual(0x100, ent.image_pos)
2314 self.assertEqual(None, ent.uncomp_size)
2315 self.assertEqual(0, ent.offset)
2316
2317 ent = entries[4]
2318 self.assertEqual(3, ent.indent)
2319 self.assertEqual('u-boot', ent.name)
2320 self.assertEqual('u-boot', ent.etype)
2321 self.assertEqual(len(U_BOOT_DATA), ent.size)
2322 self.assertEqual(0x138, ent.image_pos)
2323 self.assertEqual(None, ent.uncomp_size)
2324 self.assertEqual(0x38, ent.offset)
2325
2326 ent = entries[5]
2327 self.assertEqual(3, ent.indent)
2328 self.assertEqual('u-boot-dtb', ent.name)
2329 self.assertEqual('text', ent.etype)
2330 self.assertGreater(len(COMPRESS_DATA), ent.size)
2331 self.assertEqual(0x178, ent.image_pos)
2332 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2333 self.assertEqual(0x78, ent.offset)
2334
2335 ent = entries[6]
2336 self.assertEqual(2, ent.indent)
2337 self.assertEqual('u-boot-dtb', ent.name)
2338 self.assertEqual('u-boot-dtb', ent.etype)
2339 self.assertEqual(0x500, ent.image_pos)
2340 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2341 dtb_size = ent.size
2342 # Compressing this data expands it since headers are added
2343 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2344 self.assertEqual(0x400, ent.offset)
2345
2346 self.assertEqual(len(data), 0x100 + section_size)
2347 self.assertEqual(section_size, 0x400 + dtb_size)
2348
Simon Glasse1925fa2019-07-08 14:25:44 -06002349 def testFindFdtmap(self):
2350 """Test locating an FDT map in an image"""
2351 self._CheckLz4()
2352 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2353 image = control.images['image']
2354 entries = image.GetEntries()
2355 entry = entries['fdtmap']
2356 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2357
2358 def testFindFdtmapMissing(self):
2359 """Test failing to locate an FDP map"""
2360 data = self._DoReadFile('005_simple.dts')
2361 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2362
Simon Glass2d260032019-07-08 14:25:45 -06002363 def testFindImageHeader(self):
2364 """Test locating a image header"""
2365 self._CheckLz4()
Simon Glassffded752019-07-08 14:25:46 -06002366 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002367 image = control.images['image']
2368 entries = image.GetEntries()
2369 entry = entries['fdtmap']
2370 # The header should point to the FDT map
2371 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2372
2373 def testFindImageHeaderStart(self):
2374 """Test locating a image header located at the start of an image"""
Simon Glassffded752019-07-08 14:25:46 -06002375 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002376 image = control.images['image']
2377 entries = image.GetEntries()
2378 entry = entries['fdtmap']
2379 # The header should point to the FDT map
2380 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2381
2382 def testFindImageHeaderMissing(self):
2383 """Test failing to locate an image header"""
2384 data = self._DoReadFile('005_simple.dts')
2385 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2386
Simon Glassffded752019-07-08 14:25:46 -06002387 def testReadImage(self):
2388 """Test reading an image and accessing its FDT map"""
2389 self._CheckLz4()
2390 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2391 image_fname = tools.GetOutputFilename('image.bin')
2392 orig_image = control.images['image']
2393 image = Image.FromFile(image_fname)
2394 self.assertEqual(orig_image.GetEntries().keys(),
2395 image.GetEntries().keys())
2396
2397 orig_entry = orig_image.GetEntries()['fdtmap']
2398 entry = image.GetEntries()['fdtmap']
2399 self.assertEquals(orig_entry.offset, entry.offset)
2400 self.assertEquals(orig_entry.size, entry.size)
2401 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2402
2403 def testReadImageNoHeader(self):
2404 """Test accessing an image's FDT map without an image header"""
2405 self._CheckLz4()
2406 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
2407 image_fname = tools.GetOutputFilename('image.bin')
2408 image = Image.FromFile(image_fname)
2409 self.assertTrue(isinstance(image, Image))
Simon Glass10f9d002019-07-20 12:23:50 -06002410 self.assertEqual('image', image.image_name[-5:])
Simon Glassffded752019-07-08 14:25:46 -06002411
2412 def testReadImageFail(self):
2413 """Test failing to read an image image's FDT map"""
2414 self._DoReadFile('005_simple.dts')
2415 image_fname = tools.GetOutputFilename('image.bin')
2416 with self.assertRaises(ValueError) as e:
2417 image = Image.FromFile(image_fname)
2418 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glasse073d4e2019-07-08 13:18:56 -06002419
Simon Glass61f564d2019-07-08 14:25:48 -06002420 def testListCmd(self):
2421 """Test listing the files in an image using an Fdtmap"""
2422 self._CheckLz4()
2423 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2424
2425 # lz4 compression size differs depending on the version
2426 image = control.images['image']
2427 entries = image.GetEntries()
2428 section_size = entries['section'].size
2429 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2430 fdtmap_offset = entries['fdtmap'].offset
2431
Simon Glassf86a7362019-07-20 12:24:10 -06002432 try:
2433 tmpdir, updated_fname = self._SetupImageInTmpdir()
2434 with test_util.capture_sys_output() as (stdout, stderr):
2435 self._DoBinman('ls', '-i', updated_fname)
2436 finally:
2437 shutil.rmtree(tmpdir)
Simon Glass61f564d2019-07-08 14:25:48 -06002438 lines = stdout.getvalue().splitlines()
2439 expected = [
2440'Name Image-pos Size Entry-type Offset Uncomp-size',
2441'----------------------------------------------------------------------',
2442'main-section 0 c00 section 0',
2443' u-boot 0 4 u-boot 0',
2444' section 100 %x section 100' % section_size,
2445' cbfs 100 400 cbfs 0',
2446' u-boot 138 4 u-boot 38',
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002447' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glass61f564d2019-07-08 14:25:48 -06002448' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002449' fdtmap %x 3bd fdtmap %x' %
Simon Glass61f564d2019-07-08 14:25:48 -06002450 (fdtmap_offset, fdtmap_offset),
2451' image-header bf8 8 image-header bf8',
2452 ]
2453 self.assertEqual(expected, lines)
2454
2455 def testListCmdFail(self):
2456 """Test failing to list an image"""
2457 self._DoReadFile('005_simple.dts')
Simon Glassf86a7362019-07-20 12:24:10 -06002458 try:
2459 tmpdir, updated_fname = self._SetupImageInTmpdir()
2460 with self.assertRaises(ValueError) as e:
2461 self._DoBinman('ls', '-i', updated_fname)
2462 finally:
2463 shutil.rmtree(tmpdir)
Simon Glass61f564d2019-07-08 14:25:48 -06002464 self.assertIn("Cannot find FDT map in image", str(e.exception))
2465
2466 def _RunListCmd(self, paths, expected):
2467 """List out entries and check the result
2468
2469 Args:
2470 paths: List of paths to pass to the list command
2471 expected: Expected list of filenames to be returned, in order
2472 """
2473 self._CheckLz4()
2474 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2475 image_fname = tools.GetOutputFilename('image.bin')
2476 image = Image.FromFile(image_fname)
2477 lines = image.GetListEntries(paths)[1]
2478 files = [line[0].strip() for line in lines[1:]]
2479 self.assertEqual(expected, files)
2480
2481 def testListCmdSection(self):
2482 """Test listing the files in a section"""
2483 self._RunListCmd(['section'],
2484 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2485
2486 def testListCmdFile(self):
2487 """Test listing a particular file"""
2488 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2489
2490 def testListCmdWildcard(self):
2491 """Test listing a wildcarded file"""
2492 self._RunListCmd(['*boot*'],
2493 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2494
2495 def testListCmdWildcardMulti(self):
2496 """Test listing a wildcarded file"""
2497 self._RunListCmd(['*cb*', '*head*'],
2498 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2499
2500 def testListCmdEmpty(self):
2501 """Test listing a wildcarded file"""
2502 self._RunListCmd(['nothing'], [])
2503
2504 def testListCmdPath(self):
2505 """Test listing the files in a sub-entry of a section"""
2506 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2507
Simon Glassf667e452019-07-08 14:25:50 -06002508 def _RunExtractCmd(self, entry_name, decomp=True):
2509 """Extract an entry from an image
2510
2511 Args:
2512 entry_name: Entry name to extract
2513 decomp: True to decompress the data if compressed, False to leave
2514 it in its raw uncompressed format
2515
2516 Returns:
2517 data from entry
2518 """
2519 self._CheckLz4()
2520 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2521 image_fname = tools.GetOutputFilename('image.bin')
2522 return control.ReadEntry(image_fname, entry_name, decomp)
2523
2524 def testExtractSimple(self):
2525 """Test extracting a single file"""
2526 data = self._RunExtractCmd('u-boot')
2527 self.assertEqual(U_BOOT_DATA, data)
2528
Simon Glass71ce0ba2019-07-08 14:25:52 -06002529 def testExtractSection(self):
2530 """Test extracting the files in a section"""
2531 data = self._RunExtractCmd('section')
2532 cbfs_data = data[:0x400]
2533 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002534 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass71ce0ba2019-07-08 14:25:52 -06002535 dtb_data = data[0x400:]
2536 dtb = self._decompress(dtb_data)
2537 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2538
2539 def testExtractCompressed(self):
2540 """Test extracting compressed data"""
2541 data = self._RunExtractCmd('section/u-boot-dtb')
2542 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2543
2544 def testExtractRaw(self):
2545 """Test extracting compressed data without decompressing it"""
2546 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2547 dtb = self._decompress(data)
2548 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2549
2550 def testExtractCbfs(self):
2551 """Test extracting CBFS data"""
2552 data = self._RunExtractCmd('section/cbfs/u-boot')
2553 self.assertEqual(U_BOOT_DATA, data)
2554
2555 def testExtractCbfsCompressed(self):
2556 """Test extracting CBFS compressed data"""
2557 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2558 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2559
2560 def testExtractCbfsRaw(self):
2561 """Test extracting CBFS compressed data without decompressing it"""
2562 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Simon Glasseb0f4a42019-07-20 12:24:06 -06002563 dtb = tools.Decompress(data, 'lzma', with_header=False)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002564 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2565
Simon Glassf667e452019-07-08 14:25:50 -06002566 def testExtractBadEntry(self):
2567 """Test extracting a bad section path"""
2568 with self.assertRaises(ValueError) as e:
2569 self._RunExtractCmd('section/does-not-exist')
2570 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2571 str(e.exception))
2572
2573 def testExtractMissingFile(self):
2574 """Test extracting file that does not exist"""
2575 with self.assertRaises(IOError) as e:
2576 control.ReadEntry('missing-file', 'name')
2577
2578 def testExtractBadFile(self):
2579 """Test extracting an invalid file"""
2580 fname = os.path.join(self._indir, 'badfile')
2581 tools.WriteFile(fname, b'')
2582 with self.assertRaises(ValueError) as e:
2583 control.ReadEntry(fname, 'name')
2584
Simon Glass71ce0ba2019-07-08 14:25:52 -06002585 def testExtractCmd(self):
2586 """Test extracting a file fron an image on the command line"""
2587 self._CheckLz4()
2588 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass71ce0ba2019-07-08 14:25:52 -06002589 fname = os.path.join(self._indir, 'output.extact')
Simon Glassf86a7362019-07-20 12:24:10 -06002590 try:
2591 tmpdir, updated_fname = self._SetupImageInTmpdir()
2592 with test_util.capture_sys_output() as (stdout, stderr):
2593 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2594 '-f', fname)
2595 finally:
2596 shutil.rmtree(tmpdir)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002597 data = tools.ReadFile(fname)
2598 self.assertEqual(U_BOOT_DATA, data)
2599
2600 def testExtractOneEntry(self):
2601 """Test extracting a single entry fron an image """
2602 self._CheckLz4()
2603 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2604 image_fname = tools.GetOutputFilename('image.bin')
2605 fname = os.path.join(self._indir, 'output.extact')
2606 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
2607 data = tools.ReadFile(fname)
2608 self.assertEqual(U_BOOT_DATA, data)
2609
2610 def _CheckExtractOutput(self, decomp):
2611 """Helper to test file output with and without decompression
2612
2613 Args:
2614 decomp: True to decompress entry data, False to output it raw
2615 """
2616 def _CheckPresent(entry_path, expect_data, expect_size=None):
2617 """Check and remove expected file
2618
2619 This checks the data/size of a file and removes the file both from
2620 the outfiles set and from the output directory. Once all files are
2621 processed, both the set and directory should be empty.
2622
2623 Args:
2624 entry_path: Entry path
2625 expect_data: Data to expect in file, or None to skip check
2626 expect_size: Size of data to expect in file, or None to skip
2627 """
2628 path = os.path.join(outdir, entry_path)
2629 data = tools.ReadFile(path)
2630 os.remove(path)
2631 if expect_data:
2632 self.assertEqual(expect_data, data)
2633 elif expect_size:
2634 self.assertEqual(expect_size, len(data))
2635 outfiles.remove(path)
2636
2637 def _CheckDirPresent(name):
2638 """Remove expected directory
2639
2640 This gives an error if the directory does not exist as expected
2641
2642 Args:
2643 name: Name of directory to remove
2644 """
2645 path = os.path.join(outdir, name)
2646 os.rmdir(path)
2647
2648 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2649 image_fname = tools.GetOutputFilename('image.bin')
2650 outdir = os.path.join(self._indir, 'extract')
2651 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2652
2653 # Create a set of all file that were output (should be 9)
2654 outfiles = set()
2655 for root, dirs, files in os.walk(outdir):
2656 outfiles |= set([os.path.join(root, fname) for fname in files])
2657 self.assertEqual(9, len(outfiles))
2658 self.assertEqual(9, len(einfos))
2659
2660 image = control.images['image']
2661 entries = image.GetEntries()
2662
2663 # Check the 9 files in various ways
2664 section = entries['section']
2665 section_entries = section.GetEntries()
2666 cbfs_entries = section_entries['cbfs'].GetEntries()
2667 _CheckPresent('u-boot', U_BOOT_DATA)
2668 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
2669 dtb_len = EXTRACT_DTB_SIZE
2670 if not decomp:
2671 dtb_len = cbfs_entries['u-boot-dtb'].size
2672 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
2673 if not decomp:
2674 dtb_len = section_entries['u-boot-dtb'].size
2675 _CheckPresent('section/u-boot-dtb', None, dtb_len)
2676
2677 fdtmap = entries['fdtmap']
2678 _CheckPresent('fdtmap', fdtmap.data)
2679 hdr = entries['image-header']
2680 _CheckPresent('image-header', hdr.data)
2681
2682 _CheckPresent('section/root', section.data)
2683 cbfs = section_entries['cbfs']
2684 _CheckPresent('section/cbfs/root', cbfs.data)
2685 data = tools.ReadFile(image_fname)
2686 _CheckPresent('root', data)
2687
2688 # There should be no files left. Remove all the directories to check.
2689 # If there are any files/dirs remaining, one of these checks will fail.
2690 self.assertEqual(0, len(outfiles))
2691 _CheckDirPresent('section/cbfs')
2692 _CheckDirPresent('section')
2693 _CheckDirPresent('')
2694 self.assertFalse(os.path.exists(outdir))
2695
2696 def testExtractAllEntries(self):
2697 """Test extracting all entries"""
2698 self._CheckLz4()
2699 self._CheckExtractOutput(decomp=True)
2700
2701 def testExtractAllEntriesRaw(self):
2702 """Test extracting all entries without decompressing them"""
2703 self._CheckLz4()
2704 self._CheckExtractOutput(decomp=False)
2705
2706 def testExtractSelectedEntries(self):
2707 """Test extracting some entries"""
2708 self._CheckLz4()
2709 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2710 image_fname = tools.GetOutputFilename('image.bin')
2711 outdir = os.path.join(self._indir, 'extract')
2712 einfos = control.ExtractEntries(image_fname, None, outdir,
2713 ['*cb*', '*head*'])
2714
2715 # File output is tested by testExtractAllEntries(), so just check that
2716 # the expected entries are selected
2717 names = [einfo.name for einfo in einfos]
2718 self.assertEqual(names,
2719 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2720
2721 def testExtractNoEntryPaths(self):
2722 """Test extracting some entries"""
2723 self._CheckLz4()
2724 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2725 image_fname = tools.GetOutputFilename('image.bin')
2726 with self.assertRaises(ValueError) as e:
2727 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassbb5edc12019-07-20 12:24:14 -06002728 self.assertIn('Must specify an entry path to write with -f',
Simon Glass71ce0ba2019-07-08 14:25:52 -06002729 str(e.exception))
2730
2731 def testExtractTooManyEntryPaths(self):
2732 """Test extracting some entries"""
2733 self._CheckLz4()
2734 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2735 image_fname = tools.GetOutputFilename('image.bin')
2736 with self.assertRaises(ValueError) as e:
2737 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassbb5edc12019-07-20 12:24:14 -06002738 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass71ce0ba2019-07-08 14:25:52 -06002739 str(e.exception))
2740
Simon Glasse2705fa2019-07-08 14:25:53 -06002741 def testPackAlignSection(self):
2742 """Test that sections can have alignment"""
2743 self._DoReadFile('131_pack_align_section.dts')
2744
2745 self.assertIn('image', control.images)
2746 image = control.images['image']
2747 entries = image.GetEntries()
2748 self.assertEqual(3, len(entries))
2749
2750 # First u-boot
2751 self.assertIn('u-boot', entries)
2752 entry = entries['u-boot']
2753 self.assertEqual(0, entry.offset)
2754 self.assertEqual(0, entry.image_pos)
2755 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2756 self.assertEqual(len(U_BOOT_DATA), entry.size)
2757
2758 # Section0
2759 self.assertIn('section0', entries)
2760 section0 = entries['section0']
2761 self.assertEqual(0x10, section0.offset)
2762 self.assertEqual(0x10, section0.image_pos)
2763 self.assertEqual(len(U_BOOT_DATA), section0.size)
2764
2765 # Second u-boot
2766 section_entries = section0.GetEntries()
2767 self.assertIn('u-boot', section_entries)
2768 entry = section_entries['u-boot']
2769 self.assertEqual(0, entry.offset)
2770 self.assertEqual(0x10, entry.image_pos)
2771 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2772 self.assertEqual(len(U_BOOT_DATA), entry.size)
2773
2774 # Section1
2775 self.assertIn('section1', entries)
2776 section1 = entries['section1']
2777 self.assertEqual(0x14, section1.offset)
2778 self.assertEqual(0x14, section1.image_pos)
2779 self.assertEqual(0x20, section1.size)
2780
2781 # Second u-boot
2782 section_entries = section1.GetEntries()
2783 self.assertIn('u-boot', section_entries)
2784 entry = section_entries['u-boot']
2785 self.assertEqual(0, entry.offset)
2786 self.assertEqual(0x14, entry.image_pos)
2787 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2788 self.assertEqual(len(U_BOOT_DATA), entry.size)
2789
2790 # Section2
2791 self.assertIn('section2', section_entries)
2792 section2 = section_entries['section2']
2793 self.assertEqual(0x4, section2.offset)
2794 self.assertEqual(0x18, section2.image_pos)
2795 self.assertEqual(4, section2.size)
2796
2797 # Third u-boot
2798 section_entries = section2.GetEntries()
2799 self.assertIn('u-boot', section_entries)
2800 entry = section_entries['u-boot']
2801 self.assertEqual(0, entry.offset)
2802 self.assertEqual(0x18, entry.image_pos)
2803 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2804 self.assertEqual(len(U_BOOT_DATA), entry.size)
2805
Simon Glass51014aa2019-07-20 12:23:56 -06002806 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
2807 dts='132_replace.dts'):
Simon Glass10f9d002019-07-20 12:23:50 -06002808 """Replace an entry in an image
2809
2810 This writes the entry data to update it, then opens the updated file and
2811 returns the value that it now finds there.
2812
2813 Args:
2814 entry_name: Entry name to replace
2815 data: Data to replace it with
2816 decomp: True to compress the data if needed, False if data is
2817 already compressed so should be used as is
Simon Glass51014aa2019-07-20 12:23:56 -06002818 allow_resize: True to allow entries to change size, False to raise
2819 an exception
Simon Glass10f9d002019-07-20 12:23:50 -06002820
2821 Returns:
2822 Tuple:
2823 data from entry
2824 data from fdtmap (excluding header)
Simon Glass51014aa2019-07-20 12:23:56 -06002825 Image object that was modified
Simon Glass10f9d002019-07-20 12:23:50 -06002826 """
Simon Glass51014aa2019-07-20 12:23:56 -06002827 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass10f9d002019-07-20 12:23:50 -06002828 update_dtb=True)[1]
2829
2830 self.assertIn('image', control.images)
2831 image = control.images['image']
2832 entries = image.GetEntries()
2833 orig_dtb_data = entries['u-boot-dtb'].data
2834 orig_fdtmap_data = entries['fdtmap'].data
2835
2836 image_fname = tools.GetOutputFilename('image.bin')
2837 updated_fname = tools.GetOutputFilename('image-updated.bin')
2838 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
Simon Glass51014aa2019-07-20 12:23:56 -06002839 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
2840 allow_resize)
Simon Glass10f9d002019-07-20 12:23:50 -06002841 data = control.ReadEntry(updated_fname, entry_name, decomp)
2842
Simon Glass51014aa2019-07-20 12:23:56 -06002843 # The DT data should not change unless resized:
2844 if not allow_resize:
2845 new_dtb_data = entries['u-boot-dtb'].data
2846 self.assertEqual(new_dtb_data, orig_dtb_data)
2847 new_fdtmap_data = entries['fdtmap'].data
2848 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass10f9d002019-07-20 12:23:50 -06002849
Simon Glass51014aa2019-07-20 12:23:56 -06002850 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass10f9d002019-07-20 12:23:50 -06002851
2852 def testReplaceSimple(self):
2853 """Test replacing a single file"""
2854 expected = b'x' * len(U_BOOT_DATA)
Simon Glass51014aa2019-07-20 12:23:56 -06002855 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
2856 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06002857 self.assertEqual(expected, data)
2858
2859 # Test that the state looks right. There should be an FDT for the fdtmap
2860 # that we jsut read back in, and it should match what we find in the
2861 # 'control' tables. Checking for an FDT that does not exist should
2862 # return None.
2863 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glass51014aa2019-07-20 12:23:56 -06002864 self.assertIsNotNone(path)
Simon Glass10f9d002019-07-20 12:23:50 -06002865 self.assertEqual(expected_fdtmap, fdtmap)
2866
2867 dtb = state.GetFdtForEtype('fdtmap')
2868 self.assertEqual(dtb.GetContents(), fdtmap)
2869
2870 missing_path, missing_fdtmap = state.GetFdtContents('missing')
2871 self.assertIsNone(missing_path)
2872 self.assertIsNone(missing_fdtmap)
2873
2874 missing_dtb = state.GetFdtForEtype('missing')
2875 self.assertIsNone(missing_dtb)
2876
2877 self.assertEqual('/binman', state.fdt_path_prefix)
2878
2879 def testReplaceResizeFail(self):
2880 """Test replacing a file by something larger"""
2881 expected = U_BOOT_DATA + b'x'
2882 with self.assertRaises(ValueError) as e:
Simon Glass51014aa2019-07-20 12:23:56 -06002883 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
2884 dts='139_replace_repack.dts')
Simon Glass10f9d002019-07-20 12:23:50 -06002885 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
2886 str(e.exception))
2887
2888 def testReplaceMulti(self):
2889 """Test replacing entry data where multiple images are generated"""
2890 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
2891 update_dtb=True)[0]
2892 expected = b'x' * len(U_BOOT_DATA)
2893 updated_fname = tools.GetOutputFilename('image-updated.bin')
2894 tools.WriteFile(updated_fname, data)
2895 entry_name = 'u-boot'
Simon Glass51014aa2019-07-20 12:23:56 -06002896 control.WriteEntry(updated_fname, entry_name, expected,
2897 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06002898 data = control.ReadEntry(updated_fname, entry_name)
2899 self.assertEqual(expected, data)
2900
2901 # Check the state looks right.
2902 self.assertEqual('/binman/image', state.fdt_path_prefix)
2903
2904 # Now check we can write the first image
2905 image_fname = tools.GetOutputFilename('first-image.bin')
2906 updated_fname = tools.GetOutputFilename('first-updated.bin')
2907 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
2908 entry_name = 'u-boot'
Simon Glass51014aa2019-07-20 12:23:56 -06002909 control.WriteEntry(updated_fname, entry_name, expected,
2910 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06002911 data = control.ReadEntry(updated_fname, entry_name)
2912 self.assertEqual(expected, data)
2913
2914 # Check the state looks right.
2915 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass8beb11e2019-07-08 14:25:47 -06002916
Simon Glass12bb1a92019-07-20 12:23:51 -06002917 def testUpdateFdtAllRepack(self):
2918 """Test that all device trees are updated with offset/size info"""
2919 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
2920 SECTION_SIZE = 0x300
2921 DTB_SIZE = 602
2922 FDTMAP_SIZE = 608
2923 base_expected = {
2924 'offset': 0,
2925 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
2926 'image-pos': 0,
2927 'section:offset': 0,
2928 'section:size': SECTION_SIZE,
2929 'section:image-pos': 0,
2930 'section/u-boot-dtb:offset': 4,
2931 'section/u-boot-dtb:size': 636,
2932 'section/u-boot-dtb:image-pos': 4,
2933 'u-boot-spl-dtb:offset': SECTION_SIZE,
2934 'u-boot-spl-dtb:size': DTB_SIZE,
2935 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
2936 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
2937 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
2938 'u-boot-tpl-dtb:size': DTB_SIZE,
2939 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
2940 'fdtmap:size': FDTMAP_SIZE,
2941 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
2942 }
2943 main_expected = {
2944 'section:orig-size': SECTION_SIZE,
2945 'section/u-boot-dtb:orig-offset': 4,
2946 }
2947
2948 # We expect three device-tree files in the output, with the first one
2949 # within a fixed-size section.
2950 # Read them in sequence. We look for an 'spl' property in the SPL tree,
2951 # and 'tpl' in the TPL tree, to make sure they are distinct from the
2952 # main U-Boot tree. All three should have the same positions and offset
2953 # except that the main tree should include the main_expected properties
2954 start = 4
2955 for item in ['', 'spl', 'tpl', None]:
2956 if item is None:
2957 start += 16 # Move past fdtmap header
2958 dtb = fdt.Fdt.FromData(data[start:])
2959 dtb.Scan()
2960 props = self._GetPropTree(dtb,
2961 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
2962 prefix='/' if item is None else '/binman/')
2963 expected = dict(base_expected)
2964 if item:
2965 expected[item] = 0
2966 else:
2967 # Main DTB and fdtdec should include the 'orig-' properties
2968 expected.update(main_expected)
2969 # Helpful for debugging:
2970 #for prop in sorted(props):
2971 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
2972 self.assertEqual(expected, props)
2973 if item == '':
2974 start = SECTION_SIZE
2975 else:
2976 start += dtb._fdt_obj.totalsize()
2977
Simon Glasseba1f0c2019-07-20 12:23:55 -06002978 def testFdtmapHeaderMiddle(self):
2979 """Test an FDT map in the middle of an image when it should be at end"""
2980 with self.assertRaises(ValueError) as e:
2981 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
2982 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
2983 str(e.exception))
2984
2985 def testFdtmapHeaderStartBad(self):
2986 """Test an FDT map in middle of an image when it should be at start"""
2987 with self.assertRaises(ValueError) as e:
2988 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
2989 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
2990 str(e.exception))
2991
2992 def testFdtmapHeaderEndBad(self):
2993 """Test an FDT map at the start of an image when it should be at end"""
2994 with self.assertRaises(ValueError) as e:
2995 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
2996 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
2997 str(e.exception))
2998
2999 def testFdtmapHeaderNoSize(self):
3000 """Test an image header at the end of an image with undefined size"""
3001 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3002
Simon Glass51014aa2019-07-20 12:23:56 -06003003 def testReplaceResize(self):
3004 """Test replacing a single file in an entry with a larger file"""
3005 expected = U_BOOT_DATA + b'x'
3006 data, _, image = self._RunReplaceCmd('u-boot', expected,
3007 dts='139_replace_repack.dts')
3008 self.assertEqual(expected, data)
3009
3010 entries = image.GetEntries()
3011 dtb_data = entries['u-boot-dtb'].data
3012 dtb = fdt.Fdt.FromData(dtb_data)
3013 dtb.Scan()
3014
3015 # The u-boot section should now be larger in the dtb
3016 node = dtb.GetNode('/binman/u-boot')
3017 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3018
3019 # Same for the fdtmap
3020 fdata = entries['fdtmap'].data
3021 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3022 fdtb.Scan()
3023 fnode = fdtb.GetNode('/u-boot')
3024 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3025
3026 def testReplaceResizeNoRepack(self):
3027 """Test replacing an entry with a larger file when not allowed"""
3028 expected = U_BOOT_DATA + b'x'
3029 with self.assertRaises(ValueError) as e:
3030 self._RunReplaceCmd('u-boot', expected)
3031 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3032 str(e.exception))
3033
Simon Glass61ec04f2019-07-20 12:23:58 -06003034 def testEntryShrink(self):
3035 """Test contracting an entry after it is packed"""
3036 try:
3037 state.SetAllowEntryContraction(True)
3038 data = self._DoReadFileDtb('140_entry_shrink.dts',
3039 update_dtb=True)[0]
3040 finally:
3041 state.SetAllowEntryContraction(False)
3042 self.assertEqual(b'a', data[:1])
3043 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3044 self.assertEqual(b'a', data[-1:])
3045
3046 def testEntryShrinkFail(self):
3047 """Test not being allowed to contract an entry after it is packed"""
3048 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3049
3050 # In this case there is a spare byte at the end of the data. The size of
3051 # the contents is only 1 byte but we still have the size before it
3052 # shrunk.
3053 self.assertEqual(b'a\0', data[:2])
3054 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3055 self.assertEqual(b'a\0', data[-2:])
3056
Simon Glass27145fd2019-07-20 12:24:01 -06003057 def testDescriptorOffset(self):
3058 """Test that the Intel descriptor is always placed at at the start"""
3059 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3060 image = control.images['image']
3061 entries = image.GetEntries()
3062 desc = entries['intel-descriptor']
3063 self.assertEqual(0xff800000, desc.offset);
3064 self.assertEqual(0xff800000, desc.image_pos);
3065
Simon Glasseb0f4a42019-07-20 12:24:06 -06003066 def testReplaceCbfs(self):
3067 """Test replacing a single file in CBFS without changing the size"""
3068 self._CheckLz4()
3069 expected = b'x' * len(U_BOOT_DATA)
3070 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3071 updated_fname = tools.GetOutputFilename('image-updated.bin')
3072 tools.WriteFile(updated_fname, data)
3073 entry_name = 'section/cbfs/u-boot'
3074 control.WriteEntry(updated_fname, entry_name, expected,
3075 allow_resize=True)
3076 data = control.ReadEntry(updated_fname, entry_name)
3077 self.assertEqual(expected, data)
3078
3079 def testReplaceResizeCbfs(self):
3080 """Test replacing a single file in CBFS with one of a different size"""
3081 self._CheckLz4()
3082 expected = U_BOOT_DATA + b'x'
3083 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3084 updated_fname = tools.GetOutputFilename('image-updated.bin')
3085 tools.WriteFile(updated_fname, data)
3086 entry_name = 'section/cbfs/u-boot'
3087 control.WriteEntry(updated_fname, entry_name, expected,
3088 allow_resize=True)
3089 data = control.ReadEntry(updated_fname, entry_name)
3090 self.assertEqual(expected, data)
3091
Simon Glassa6cb9952019-07-20 12:24:15 -06003092 def _SetupForReplace(self):
3093 """Set up some files to use to replace entries
3094
3095 This generates an image, copies it to a new file, extracts all the files
3096 in it and updates some of them
3097
3098 Returns:
3099 List
3100 Image filename
3101 Output directory
3102 Expected values for updated entries, each a string
3103 """
3104 data = self._DoReadFileRealDtb('143_replace_all.dts')
3105
3106 updated_fname = tools.GetOutputFilename('image-updated.bin')
3107 tools.WriteFile(updated_fname, data)
3108
3109 outdir = os.path.join(self._indir, 'extract')
3110 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3111
3112 expected1 = b'x' + U_BOOT_DATA + b'y'
3113 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3114 tools.WriteFile(u_boot_fname1, expected1)
3115
3116 expected2 = b'a' + U_BOOT_DATA + b'b'
3117 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
3118 tools.WriteFile(u_boot_fname2, expected2)
3119
3120 expected_text = b'not the same text'
3121 text_fname = os.path.join(outdir, 'text')
3122 tools.WriteFile(text_fname, expected_text)
3123
3124 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3125 dtb = fdt.FdtScan(dtb_fname)
3126 node = dtb.GetNode('/binman/text')
3127 node.AddString('my-property', 'the value')
3128 dtb.Sync(auto_resize=True)
3129 dtb.Flush()
3130
3131 return updated_fname, outdir, expected1, expected2, expected_text
3132
3133 def _CheckReplaceMultiple(self, entry_paths):
3134 """Handle replacing the contents of multiple entries
3135
3136 Args:
3137 entry_paths: List of entry paths to replace
3138
3139 Returns:
3140 List
3141 Dict of entries in the image:
3142 key: Entry name
3143 Value: Entry object
3144 Expected values for updated entries, each a string
3145 """
3146 updated_fname, outdir, expected1, expected2, expected_text = (
3147 self._SetupForReplace())
3148 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3149
3150 image = Image.FromFile(updated_fname)
3151 image.LoadData()
3152 return image.GetEntries(), expected1, expected2, expected_text
3153
3154 def testReplaceAll(self):
3155 """Test replacing the contents of all entries"""
3156 entries, expected1, expected2, expected_text = (
3157 self._CheckReplaceMultiple([]))
3158 data = entries['u-boot'].data
3159 self.assertEqual(expected1, data)
3160
3161 data = entries['u-boot2'].data
3162 self.assertEqual(expected2, data)
3163
3164 data = entries['text'].data
3165 self.assertEqual(expected_text, data)
3166
3167 # Check that the device tree is updated
3168 data = entries['u-boot-dtb'].data
3169 dtb = fdt.Fdt.FromData(data)
3170 dtb.Scan()
3171 node = dtb.GetNode('/binman/text')
3172 self.assertEqual('the value', node.props['my-property'].value)
3173
3174 def testReplaceSome(self):
3175 """Test replacing the contents of a few entries"""
3176 entries, expected1, expected2, expected_text = (
3177 self._CheckReplaceMultiple(['u-boot2', 'text']))
3178
3179 # This one should not change
3180 data = entries['u-boot'].data
3181 self.assertEqual(U_BOOT_DATA, data)
3182
3183 data = entries['u-boot2'].data
3184 self.assertEqual(expected2, data)
3185
3186 data = entries['text'].data
3187 self.assertEqual(expected_text, data)
3188
3189 def testReplaceCmd(self):
3190 """Test replacing a file fron an image on the command line"""
3191 self._DoReadFileRealDtb('143_replace_all.dts')
3192
3193 try:
3194 tmpdir, updated_fname = self._SetupImageInTmpdir()
3195
3196 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3197 expected = b'x' * len(U_BOOT_DATA)
3198 tools.WriteFile(fname, expected)
3199
3200 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
3201 data = tools.ReadFile(updated_fname)
3202 self.assertEqual(expected, data[:len(expected)])
3203 map_fname = os.path.join(tmpdir, 'image-updated.map')
3204 self.assertFalse(os.path.exists(map_fname))
3205 finally:
3206 shutil.rmtree(tmpdir)
3207
3208 def testReplaceCmdSome(self):
3209 """Test replacing some files fron an image on the command line"""
3210 updated_fname, outdir, expected1, expected2, expected_text = (
3211 self._SetupForReplace())
3212
3213 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3214 'u-boot2', 'text')
3215
3216 tools.PrepareOutputDir(None)
3217 image = Image.FromFile(updated_fname)
3218 image.LoadData()
3219 entries = image.GetEntries()
3220
3221 # This one should not change
3222 data = entries['u-boot'].data
3223 self.assertEqual(U_BOOT_DATA, data)
3224
3225 data = entries['u-boot2'].data
3226 self.assertEqual(expected2, data)
3227
3228 data = entries['text'].data
3229 self.assertEqual(expected_text, data)
3230
3231 def testReplaceMissing(self):
3232 """Test replacing entries where the file is missing"""
3233 updated_fname, outdir, expected1, expected2, expected_text = (
3234 self._SetupForReplace())
3235
3236 # Remove one of the files, to generate a warning
3237 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3238 os.remove(u_boot_fname1)
3239
3240 with test_util.capture_sys_output() as (stdout, stderr):
3241 control.ReplaceEntries(updated_fname, None, outdir, [])
3242 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass38fdb4c2020-07-09 18:39:39 -06003243 stderr.getvalue())
Simon Glassa6cb9952019-07-20 12:24:15 -06003244
3245 def testReplaceCmdMap(self):
3246 """Test replacing a file fron an image on the command line"""
3247 self._DoReadFileRealDtb('143_replace_all.dts')
3248
3249 try:
3250 tmpdir, updated_fname = self._SetupImageInTmpdir()
3251
3252 fname = os.path.join(self._indir, 'update-u-boot.bin')
3253 expected = b'x' * len(U_BOOT_DATA)
3254 tools.WriteFile(fname, expected)
3255
3256 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3257 '-f', fname, '-m')
3258 map_fname = os.path.join(tmpdir, 'image-updated.map')
3259 self.assertTrue(os.path.exists(map_fname))
3260 finally:
3261 shutil.rmtree(tmpdir)
3262
3263 def testReplaceNoEntryPaths(self):
3264 """Test replacing an entry without an entry path"""
3265 self._DoReadFileRealDtb('143_replace_all.dts')
3266 image_fname = tools.GetOutputFilename('image.bin')
3267 with self.assertRaises(ValueError) as e:
3268 control.ReplaceEntries(image_fname, 'fname', None, [])
3269 self.assertIn('Must specify an entry path to read with -f',
3270 str(e.exception))
3271
3272 def testReplaceTooManyEntryPaths(self):
3273 """Test extracting some entries"""
3274 self._DoReadFileRealDtb('143_replace_all.dts')
3275 image_fname = tools.GetOutputFilename('image.bin')
3276 with self.assertRaises(ValueError) as e:
3277 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3278 self.assertIn('Must specify exactly one entry path to write with -f',
3279 str(e.exception))
3280
Simon Glass2250ee62019-08-24 07:22:48 -06003281 def testPackReset16(self):
3282 """Test that an image with an x86 reset16 region can be created"""
3283 data = self._DoReadFile('144_x86_reset16.dts')
3284 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3285
3286 def testPackReset16Spl(self):
3287 """Test that an image with an x86 reset16-spl region can be created"""
3288 data = self._DoReadFile('145_x86_reset16_spl.dts')
3289 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3290
3291 def testPackReset16Tpl(self):
3292 """Test that an image with an x86 reset16-tpl region can be created"""
3293 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3294 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3295
Simon Glass5af12072019-08-24 07:22:50 -06003296 def testPackIntelFit(self):
3297 """Test that an image with an Intel FIT and pointer can be created"""
3298 data = self._DoReadFile('147_intel_fit.dts')
3299 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3300 fit = data[16:32];
3301 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3302 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3303
3304 image = control.images['image']
3305 entries = image.GetEntries()
3306 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3307 self.assertEqual(expected_ptr, ptr)
3308
3309 def testPackIntelFitMissing(self):
3310 """Test detection of a FIT pointer with not FIT region"""
3311 with self.assertRaises(ValueError) as e:
3312 self._DoReadFile('148_intel_fit_missing.dts')
3313 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3314 str(e.exception))
3315
Simon Glass7c150132019-11-06 17:22:44 -07003316 def _CheckSymbolsTplSection(self, dts, expected_vals):
3317 data = self._DoReadFile(dts)
3318 sym_values = struct.pack('<LQLL', *expected_vals)
Simon Glass2090f1e2019-08-24 07:23:00 -06003319 upto1 = 4 + len(U_BOOT_SPL_DATA)
Simon Glassb87064c2019-08-24 07:23:05 -06003320 expected1 = tools.GetBytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[20:]
Simon Glass2090f1e2019-08-24 07:23:00 -06003321 self.assertEqual(expected1, data[:upto1])
3322
3323 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Simon Glassb87064c2019-08-24 07:23:05 -06003324 expected2 = tools.GetBytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[20:]
Simon Glass2090f1e2019-08-24 07:23:00 -06003325 self.assertEqual(expected2, data[upto1:upto2])
3326
Simon Glasseb0086f2019-08-24 07:23:04 -06003327 upto3 = 0x34 + len(U_BOOT_DATA)
3328 expected3 = tools.GetBytes(0xff, 1) + U_BOOT_DATA
Simon Glass2090f1e2019-08-24 07:23:00 -06003329 self.assertEqual(expected3, data[upto2:upto3])
3330
Simon Glassb87064c2019-08-24 07:23:05 -06003331 expected4 = sym_values + U_BOOT_TPL_DATA[20:]
Simon Glass7c150132019-11-06 17:22:44 -07003332 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3333
3334 def testSymbolsTplSection(self):
3335 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3336 self._SetupSplElf('u_boot_binman_syms')
3337 self._SetupTplElf('u_boot_binman_syms')
3338 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
3339 [0x04, 0x1c, 0x10 + 0x34, 0x04])
3340
3341 def testSymbolsTplSectionX86(self):
3342 """Test binman can assign symbols in a section with end-at-4gb"""
3343 self._SetupSplElf('u_boot_binman_syms_x86')
3344 self._SetupTplElf('u_boot_binman_syms_x86')
3345 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
3346 [0xffffff04, 0xffffff1c, 0xffffff34,
3347 0x04])
Simon Glass2090f1e2019-08-24 07:23:00 -06003348
Simon Glassbf4d0e22019-08-24 07:23:03 -06003349 def testPackX86RomIfwiSectiom(self):
3350 """Test that a section can be placed in an IFWI region"""
3351 self._SetupIfwi('fitimage.bin')
3352 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3353 self._CheckIfwi(data)
3354
Simon Glassea0fff92019-08-24 07:23:07 -06003355 def testPackFspM(self):
3356 """Test that an image with a FSP memory-init binary can be created"""
3357 data = self._DoReadFile('152_intel_fsp_m.dts')
3358 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3359
Simon Glassbc6a88f2019-10-20 21:31:35 -06003360 def testPackFspS(self):
3361 """Test that an image with a FSP silicon-init binary can be created"""
3362 data = self._DoReadFile('153_intel_fsp_s.dts')
3363 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassea0fff92019-08-24 07:23:07 -06003364
Simon Glass998d1482019-10-20 21:31:36 -06003365 def testPackFspT(self):
3366 """Test that an image with a FSP temp-ram-init binary can be created"""
3367 data = self._DoReadFile('154_intel_fsp_t.dts')
3368 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3369
Simon Glass0dc706f2020-07-09 18:39:31 -06003370 def testMkimage(self):
3371 """Test using mkimage to build an image"""
3372 data = self._DoReadFile('156_mkimage.dts')
3373
3374 # Just check that the data appears in the file somewhere
3375 self.assertIn(U_BOOT_SPL_DATA, data)
3376
Simon Glassce867ad2020-07-09 18:39:36 -06003377 def testExtblob(self):
3378 """Test an image with an external blob"""
3379 data = self._DoReadFile('157_blob_ext.dts')
3380 self.assertEqual(REFCODE_DATA, data)
3381
3382 def testExtblobMissing(self):
3383 """Test an image with a missing external blob"""
3384 with self.assertRaises(ValueError) as e:
3385 self._DoReadFile('158_blob_ext_missing.dts')
3386 self.assertIn("Filename 'missing-file' not found in input path",
3387 str(e.exception))
3388
Simon Glass4f9f1052020-07-09 18:39:38 -06003389 def testExtblobMissingOk(self):
3390 """Test an image with an missing external blob that is allowed"""
Simon Glassb1cca952020-07-09 18:39:40 -06003391 with test_util.capture_sys_output() as (stdout, stderr):
3392 self._DoTestFile('158_blob_ext_missing.dts', allow_missing=True)
3393 err = stderr.getvalue()
3394 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
3395
3396 def testExtblobMissingOkSect(self):
3397 """Test an image with an missing external blob that is allowed"""
3398 with test_util.capture_sys_output() as (stdout, stderr):
3399 self._DoTestFile('159_blob_ext_missing_sect.dts',
3400 allow_missing=True)
3401 err = stderr.getvalue()
3402 self.assertRegex(err, "Image 'main-section'.*missing.*: "
3403 "blob-ext blob-ext2")
Simon Glass4f9f1052020-07-09 18:39:38 -06003404
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003405 def testPackX86RomMeMissingDesc(self):
3406 """Test that an missing Intel descriptor entry is allowed"""
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003407 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass52b10dd2020-07-25 15:11:19 -06003408 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003409 err = stderr.getvalue()
3410 self.assertRegex(err,
3411 "Image 'main-section'.*missing.*: intel-descriptor")
3412
3413 def testPackX86RomMissingIfwi(self):
3414 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3415 self._SetupIfwi('fitimage.bin')
3416 pathname = os.path.join(self._indir, 'fitimage.bin')
3417 os.remove(pathname)
3418 with test_util.capture_sys_output() as (stdout, stderr):
3419 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3420 err = stderr.getvalue()
3421 self.assertRegex(err, "Image 'main-section'.*missing.*: intel-ifwi")
3422
Simon Glassb3295fd2020-07-09 18:39:42 -06003423 def testPackOverlap(self):
3424 """Test that zero-size overlapping regions are ignored"""
3425 self._DoTestFile('160_pack_overlap_zero.dts')
3426
Simon Glassfdc34362020-07-09 18:39:45 -06003427 def testSimpleFit(self):
3428 """Test an image with a FIT inside"""
3429 data = self._DoReadFile('161_fit.dts')
3430 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3431 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3432 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3433
3434 # The data should be inside the FIT
3435 dtb = fdt.Fdt.FromData(fit_data)
3436 dtb.Scan()
3437 fnode = dtb.GetNode('/images/kernel')
3438 self.assertIn('data', fnode.props)
3439
3440 fname = os.path.join(self._indir, 'fit_data.fit')
3441 tools.WriteFile(fname, fit_data)
3442 out = tools.Run('dumpimage', '-l', fname)
3443
3444 # Check a few features to make sure the plumbing works. We don't need
3445 # to test the operation of mkimage or dumpimage here. First convert the
3446 # output into a dict where the keys are the fields printed by dumpimage
3447 # and the values are a list of values for each field
3448 lines = out.splitlines()
3449
3450 # Converts "Compression: gzip compressed" into two groups:
3451 # 'Compression' and 'gzip compressed'
3452 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3453 vals = collections.defaultdict(list)
3454 for line in lines:
3455 mat = re_line.match(line)
3456 vals[mat.group(1)].append(mat.group(2))
3457
3458 self.assertEquals('FIT description: test-desc', lines[0])
3459 self.assertIn('Created:', lines[1])
3460 self.assertIn('Image 0 (kernel)', vals)
3461 self.assertIn('Hash value', vals)
3462 data_sizes = vals.get('Data Size')
3463 self.assertIsNotNone(data_sizes)
3464 self.assertEqual(2, len(data_sizes))
3465 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
3466 self.assertEqual(len(U_BOOT_DATA), int(data_sizes[0].split()[0]))
3467 self.assertEqual(len(U_BOOT_SPL_DTB_DATA), int(data_sizes[1].split()[0]))
3468
3469 def testFitExternal(self):
3470 """Test an image with an FIT"""
3471 data = self._DoReadFile('162_fit_external.dts')
3472 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3473
3474 # The data should be outside the FIT
3475 dtb = fdt.Fdt.FromData(fit_data)
3476 dtb.Scan()
3477 fnode = dtb.GetNode('/images/kernel')
3478 self.assertNotIn('data', fnode.props)
Simon Glass12bb1a92019-07-20 12:23:51 -06003479
Simon Glass9fc60b42017-11-12 21:52:22 -07003480if __name__ == "__main__":
3481 unittest.main()