blob: a51865c5c7ec57955ea609faf89a834e265ac1fa [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 Glassd5164a72019-07-08 13:18:49 -06009from __future__ import print_function
10
Simon Glasse0e5df92018-09-14 04:57:31 -060011import hashlib
Simon Glass4f443042016-11-25 20:15:52 -070012from optparse import OptionParser
13import os
14import shutil
15import struct
16import sys
17import tempfile
18import unittest
19
20import binman
Simon Glassac62fba2019-07-08 13:18:53 -060021import cbfs_util
Simon Glass4f443042016-11-25 20:15:52 -070022import cmdline
23import command
24import control
Simon Glass19790632017-11-13 18:55:01 -070025import elf
Simon Glass99ed4a22017-05-27 07:38:30 -060026import fdt
Simon Glasse1925fa2019-07-08 14:25:44 -060027from etype import fdtmap
Simon Glass2d260032019-07-08 14:25:45 -060028from etype import image_header
Simon Glass4f443042016-11-25 20:15:52 -070029import fdt_util
Simon Glass11e36cc2018-07-17 13:25:38 -060030import fmap_util
Simon Glassfd8d1f72018-07-17 13:25:36 -060031import test_util
Simon Glassc5ac1382019-07-08 13:18:54 -060032import gzip
Simon Glassffded752019-07-08 14:25:46 -060033from image import Image
Simon Glassc55a50f2018-09-14 04:57:19 -060034import state
Simon Glass4f443042016-11-25 20:15:52 -070035import tools
36import tout
37
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'
41U_BOOT_SPL_DATA = b'56780123456789abcde'
42U_BOOT_TPL_DATA = b'tpl'
43BLOB_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'
52PPC_MPC85XX_BR_DATA = b'ppcmpc85xxbr'
53U_BOOT_NODTB_DATA = b'nodtb with microcode pointer somewhere in here'
54U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here'
55U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here'
56FSP_DATA = b'fsp'
57CMC_DATA = b'cmc'
58VBT_DATA = b'vbt'
59MRC_DATA = b'mrc'
Simon Glassbb748372018-07-17 13:25:33 -060060TEXT_DATA = 'text'
61TEXT_DATA2 = 'text2'
62TEXT_DATA3 = 'text3'
Simon Glassc6c10e72019-05-17 22:00:46 -060063CROS_EC_RW_DATA = b'ecrw'
64GBB_DATA = b'gbbd'
65BMPBLK_DATA = b'bmp'
66VBLOCK_DATA = b'vblk'
67FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
68 b"sorry you're alive\n")
Simon Glassff5c7e32019-07-08 13:18:42 -060069COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
Simon Glassc6c10e72019-05-17 22:00:46 -060070REFCODE_DATA = b'refcode'
Simon Glassec127af2018-07-17 13:25:39 -060071
Simon Glass6ccbfcd2019-07-20 12:23:47 -060072# The expected size for the device tree in some tests
Simon Glassf667e452019-07-08 14:25:50 -060073EXTRACT_DTB_SIZE = 0x3c9
74
Simon Glass6ccbfcd2019-07-20 12:23:47 -060075# Properties expected to be in the device tree when update_dtb is used
76BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
77
Simon Glass12bb1a92019-07-20 12:23:51 -060078# Extra properties expected to be in the device tree when allow-repack is used
79REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
80
Simon Glass4f443042016-11-25 20:15:52 -070081
82class TestFunctional(unittest.TestCase):
83 """Functional tests for binman
84
85 Most of these use a sample .dts file to build an image and then check
86 that it looks correct. The sample files are in the test/ subdirectory
87 and are numbered.
88
89 For each entry type a very small test file is created using fixed
90 string contents. This makes it easy to test that things look right, and
91 debug problems.
92
93 In some cases a 'real' file must be used - these are also supplied in
94 the test/ diurectory.
95 """
96 @classmethod
97 def setUpClass(self):
Simon Glass4d5994f2017-11-12 21:52:20 -070098 global entry
99 import entry
100
Simon Glass4f443042016-11-25 20:15:52 -0700101 # Handle the case where argv[0] is 'python'
102 self._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
103 self._binman_pathname = os.path.join(self._binman_dir, 'binman')
104
105 # Create a temporary directory for input files
106 self._indir = tempfile.mkdtemp(prefix='binmant.')
107
108 # Create some test files
109 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
110 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
111 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glassb8ef5b62018-07-17 13:25:48 -0600112 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700113 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -0700114 TestFunctional._MakeInputFile('me.bin', ME_DATA)
115 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glassb8ef5b62018-07-17 13:25:48 -0600116 self._ResetDtbs()
Simon Glasse0ff8552016-11-25 20:15:53 -0700117 TestFunctional._MakeInputFile('u-boot-x86-16bit.bin', X86_START16_DATA)
Jagdish Gediya9d368f32018-09-03 21:35:08 +0530118 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glass87722132017-11-12 21:52:26 -0700119 TestFunctional._MakeInputFile('spl/u-boot-x86-16bit-spl.bin',
120 X86_START16_SPL_DATA)
Simon Glass35b384c2018-09-14 04:57:10 -0600121 TestFunctional._MakeInputFile('tpl/u-boot-x86-16bit-tpl.bin',
122 X86_START16_TPL_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700123 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass6b187df2017-11-12 21:52:27 -0700124 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
125 U_BOOT_SPL_NODTB_DATA)
Simon Glassf0253632018-09-14 04:57:32 -0600126 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
127 U_BOOT_TPL_NODTB_DATA)
Simon Glassda229092016-11-25 20:15:56 -0700128 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
129 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Meng59ea8c22017-08-15 22:41:54 -0700130 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassca4f4ff2017-11-12 21:52:28 -0700131 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassec127af2018-07-17 13:25:39 -0600132 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glass0ef87aa2018-07-17 13:25:44 -0600133 TestFunctional._MakeInputDir('devkeys')
134 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass3ae192c2018-10-01 12:22:31 -0600135 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700136
Simon Glasse0ff8552016-11-25 20:15:53 -0700137 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glass1d0ebf72019-05-14 15:53:42 -0600138 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
Simon Glasse0ff8552016-11-25 20:15:53 -0700139 TestFunctional._MakeInputFile('u-boot', fd.read())
140
141 # Intel flash descriptor file
Simon Glass1d0ebf72019-05-14 15:53:42 -0600142 with open(self.TestFile('descriptor.bin'), 'rb') as fd:
Simon Glasse0ff8552016-11-25 20:15:53 -0700143 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
144
Simon Glass0a98b282018-09-14 04:57:28 -0600145 shutil.copytree(self.TestFile('files'),
146 os.path.join(self._indir, 'files'))
147
Simon Glass83d73c22018-09-14 04:57:26 -0600148 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
149
Simon Glassac62fba2019-07-08 13:18:53 -0600150 # Travis-CI may have an old lz4
151 self.have_lz4 = True
152 try:
153 tools.Run('lz4', '--no-frame-crc', '-c',
154 os.path.join(self._indir, 'u-boot.bin'))
155 except:
156 self.have_lz4 = False
157
Simon Glass4f443042016-11-25 20:15:52 -0700158 @classmethod
159 def tearDownClass(self):
160 """Remove the temporary input directory and its contents"""
Simon Glassd5164a72019-07-08 13:18:49 -0600161 if self.preserve_indir:
162 print('Preserving input dir: %s' % self._indir)
163 else:
164 if self._indir:
165 shutil.rmtree(self._indir)
Simon Glass4f443042016-11-25 20:15:52 -0700166 self._indir = None
167
Simon Glassd5164a72019-07-08 13:18:49 -0600168 @classmethod
Simon Glass8acce602019-07-08 13:18:50 -0600169 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
Simon Glass53cd5d92019-07-08 14:25:29 -0600170 toolpath=None, verbosity=None):
Simon Glassd5164a72019-07-08 13:18:49 -0600171 """Accept arguments controlling test execution
172
173 Args:
174 preserve_indir: Preserve the shared input directory used by all
175 tests in this class.
176 preserve_outdir: Preserve the output directories used by tests. Each
177 test has its own, so this is normally only useful when running a
178 single test.
Simon Glass8acce602019-07-08 13:18:50 -0600179 toolpath: ist of paths to use for tools
Simon Glassd5164a72019-07-08 13:18:49 -0600180 """
181 cls.preserve_indir = preserve_indir
182 cls.preserve_outdirs = preserve_outdirs
Simon Glass8acce602019-07-08 13:18:50 -0600183 cls.toolpath = toolpath
Simon Glass53cd5d92019-07-08 14:25:29 -0600184 cls.verbosity = verbosity
Simon Glassd5164a72019-07-08 13:18:49 -0600185
Simon Glassac62fba2019-07-08 13:18:53 -0600186 def _CheckLz4(self):
187 if not self.have_lz4:
188 self.skipTest('lz4 --no-frame-crc not available')
189
Simon Glassbf574f12019-07-20 12:24:09 -0600190 def _CleanupOutputDir(self):
191 """Remove the temporary output directory"""
192 if self.preserve_outdirs:
193 print('Preserving output dir: %s' % tools.outdir)
194 else:
195 tools._FinaliseForTest()
196
Simon Glass4f443042016-11-25 20:15:52 -0700197 def setUp(self):
198 # Enable this to turn on debugging output
199 # tout.Init(tout.DEBUG)
200 command.test_result = None
201
202 def tearDown(self):
203 """Remove the temporary output directory"""
Simon Glassbf574f12019-07-20 12:24:09 -0600204 self._CleanupOutputDir()
Simon Glass4f443042016-11-25 20:15:52 -0700205
Simon Glassb8ef5b62018-07-17 13:25:48 -0600206 @classmethod
207 def _ResetDtbs(self):
208 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
209 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
210 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
211
Simon Glass4f443042016-11-25 20:15:52 -0700212 def _RunBinman(self, *args, **kwargs):
213 """Run binman using the command line
214
215 Args:
216 Arguments to pass, as a list of strings
217 kwargs: Arguments to pass to Command.RunPipe()
218 """
219 result = command.RunPipe([[self._binman_pathname] + list(args)],
220 capture=True, capture_stderr=True, raise_on_error=False)
221 if result.return_code and kwargs.get('raise_on_error', True):
222 raise Exception("Error running '%s': %s" % (' '.join(args),
223 result.stdout + result.stderr))
224 return result
225
Simon Glass53cd5d92019-07-08 14:25:29 -0600226 def _DoBinman(self, *argv):
Simon Glass4f443042016-11-25 20:15:52 -0700227 """Run binman using directly (in the same process)
228
229 Args:
230 Arguments to pass, as a list of strings
231 Returns:
232 Return value (0 for success)
233 """
Simon Glass53cd5d92019-07-08 14:25:29 -0600234 argv = list(argv)
235 args = cmdline.ParseArgs(argv)
236 args.pager = 'binman-invalid-pager'
237 args.build_dir = self._indir
Simon Glass4f443042016-11-25 20:15:52 -0700238
239 # For testing, you can force an increase in verbosity here
Simon Glass53cd5d92019-07-08 14:25:29 -0600240 # args.verbosity = tout.DEBUG
241 return control.Binman(args)
Simon Glass4f443042016-11-25 20:15:52 -0700242
Simon Glass53af22a2018-07-17 13:25:32 -0600243 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glasseb833d82019-04-25 21:58:34 -0600244 entry_args=None, images=None, use_real_dtb=False,
245 verbosity=None):
Simon Glass4f443042016-11-25 20:15:52 -0700246 """Run binman with a given test file
247
248 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600249 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600250 debug: True to enable debugging output
Simon Glass3b0c3822018-06-01 09:38:20 -0600251 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600252 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600253 tree before packing it into the image
Simon Glass0bfa7b02018-09-14 04:57:12 -0600254 entry_args: Dict of entry args to supply to binman
255 key: arg name
256 value: value of that arg
257 images: List of image names to build
Simon Glass4f443042016-11-25 20:15:52 -0700258 """
Simon Glass53cd5d92019-07-08 14:25:29 -0600259 args = []
Simon Glass7fe91732017-11-13 18:55:00 -0700260 if debug:
261 args.append('-D')
Simon Glass53cd5d92019-07-08 14:25:29 -0600262 if verbosity is not None:
263 args.append('-v%d' % verbosity)
264 elif self.verbosity:
265 args.append('-v%d' % self.verbosity)
266 if self.toolpath:
267 for path in self.toolpath:
268 args += ['--toolpath', path]
269 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass3b0c3822018-06-01 09:38:20 -0600270 if map:
271 args.append('-m')
Simon Glass16b8d6b2018-07-06 10:27:42 -0600272 if update_dtb:
Simon Glass2569e102019-07-08 13:18:47 -0600273 args.append('-u')
Simon Glass93d17412018-09-14 04:57:23 -0600274 if not use_real_dtb:
275 args.append('--fake-dtb')
Simon Glass53af22a2018-07-17 13:25:32 -0600276 if entry_args:
Simon Glass50979152019-05-14 15:53:41 -0600277 for arg, value in entry_args.items():
Simon Glass53af22a2018-07-17 13:25:32 -0600278 args.append('-a%s=%s' % (arg, value))
Simon Glass0bfa7b02018-09-14 04:57:12 -0600279 if images:
280 for image in images:
281 args += ['-i', image]
Simon Glass7fe91732017-11-13 18:55:00 -0700282 return self._DoBinman(*args)
Simon Glass4f443042016-11-25 20:15:52 -0700283
284 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glasse0ff8552016-11-25 20:15:53 -0700285 """Set up a new test device-tree file
286
287 The given file is compiled and set up as the device tree to be used
288 for ths test.
289
290 Args:
291 fname: Filename of .dts file to read
Simon Glass7ae5f312018-06-01 09:38:19 -0600292 outfile: Output filename for compiled device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700293
294 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600295 Contents of device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700296 """
Simon Glassa004f292019-07-20 12:23:49 -0600297 tmpdir = tempfile.mkdtemp(prefix='binmant.')
298 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
Simon Glass1d0ebf72019-05-14 15:53:42 -0600299 with open(dtb, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700300 data = fd.read()
301 TestFunctional._MakeInputFile(outfile, data)
Simon Glassa004f292019-07-20 12:23:49 -0600302 shutil.rmtree(tmpdir)
Simon Glasse0e62752018-10-01 21:12:41 -0600303 return data
Simon Glass4f443042016-11-25 20:15:52 -0700304
Simon Glass6ed45ba2018-09-14 04:57:24 -0600305 def _GetDtbContentsForSplTpl(self, dtb_data, name):
306 """Create a version of the main DTB for SPL or SPL
307
308 For testing we don't actually have different versions of the DTB. With
309 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
310 we don't normally have any unwanted nodes.
311
312 We still want the DTBs for SPL and TPL to be different though, since
313 otherwise it is confusing to know which one we are looking at. So add
314 an 'spl' or 'tpl' property to the top-level node.
315 """
316 dtb = fdt.Fdt.FromData(dtb_data)
317 dtb.Scan()
318 dtb.GetNode('/binman').AddZeroProp(name)
319 dtb.Sync(auto_resize=True)
320 dtb.Pack()
321 return dtb.GetContents()
322
Simon Glass16b8d6b2018-07-06 10:27:42 -0600323 def _DoReadFileDtb(self, fname, use_real_dtb=False, map=False,
Simon Glass6ed45ba2018-09-14 04:57:24 -0600324 update_dtb=False, entry_args=None, reset_dtbs=True):
Simon Glass4f443042016-11-25 20:15:52 -0700325 """Run binman and return the resulting image
326
327 This runs binman with a given test file and then reads the resulting
328 output file. It is a shortcut function since most tests need to do
329 these steps.
330
331 Raises an assertion failure if binman returns a non-zero exit code.
332
333 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600334 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass4f443042016-11-25 20:15:52 -0700335 use_real_dtb: True to use the test file as the contents of
336 the u-boot-dtb entry. Normally this is not needed and the
337 test contents (the U_BOOT_DTB_DATA string) can be used.
338 But in some test we need the real contents.
Simon Glass3b0c3822018-06-01 09:38:20 -0600339 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600340 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600341 tree before packing it into the image
Simon Glasse0ff8552016-11-25 20:15:53 -0700342
343 Returns:
344 Tuple:
345 Resulting image contents
346 Device tree contents
Simon Glass3b0c3822018-06-01 09:38:20 -0600347 Map data showing contents of image (or None if none)
Simon Glassea6922e2018-07-17 13:25:27 -0600348 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass4f443042016-11-25 20:15:52 -0700349 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700350 dtb_data = None
Simon Glass4f443042016-11-25 20:15:52 -0700351 # Use the compiled test file as the u-boot-dtb input
352 if use_real_dtb:
Simon Glasse0ff8552016-11-25 20:15:53 -0700353 dtb_data = self._SetupDtb(fname)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600354
355 # For testing purposes, make a copy of the DT for SPL and TPL. Add
356 # a node indicating which it is, so aid verification.
357 for name in ['spl', 'tpl']:
358 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
359 outfile = os.path.join(self._indir, dtb_fname)
360 TestFunctional._MakeInputFile(dtb_fname,
361 self._GetDtbContentsForSplTpl(dtb_data, name))
Simon Glass4f443042016-11-25 20:15:52 -0700362
363 try:
Simon Glass53af22a2018-07-17 13:25:32 -0600364 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glass6ed45ba2018-09-14 04:57:24 -0600365 entry_args=entry_args, use_real_dtb=use_real_dtb)
Simon Glass4f443042016-11-25 20:15:52 -0700366 self.assertEqual(0, retcode)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600367 out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
Simon Glass4f443042016-11-25 20:15:52 -0700368
369 # Find the (only) image, read it and return its contents
370 image = control.images['image']
Simon Glass16b8d6b2018-07-06 10:27:42 -0600371 image_fname = tools.GetOutputFilename('image.bin')
372 self.assertTrue(os.path.exists(image_fname))
Simon Glass3b0c3822018-06-01 09:38:20 -0600373 if map:
374 map_fname = tools.GetOutputFilename('image.map')
375 with open(map_fname) as fd:
376 map_data = fd.read()
377 else:
378 map_data = None
Simon Glass1d0ebf72019-05-14 15:53:42 -0600379 with open(image_fname, 'rb') as fd:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600380 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass4f443042016-11-25 20:15:52 -0700381 finally:
382 # Put the test file back
Simon Glass6ed45ba2018-09-14 04:57:24 -0600383 if reset_dtbs and use_real_dtb:
Simon Glassb8ef5b62018-07-17 13:25:48 -0600384 self._ResetDtbs()
Simon Glass4f443042016-11-25 20:15:52 -0700385
Simon Glass3c081312019-07-08 14:25:26 -0600386 def _DoReadFileRealDtb(self, fname):
387 """Run binman with a real .dtb file and return the resulting data
388
389 Args:
390 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
391
392 Returns:
393 Resulting image contents
394 """
395 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
396
Simon Glasse0ff8552016-11-25 20:15:53 -0700397 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass7ae5f312018-06-01 09:38:19 -0600398 """Helper function which discards the device-tree binary
399
400 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600401 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600402 use_real_dtb: True to use the test file as the contents of
403 the u-boot-dtb entry. Normally this is not needed and the
404 test contents (the U_BOOT_DTB_DATA string) can be used.
405 But in some test we need the real contents.
Simon Glassea6922e2018-07-17 13:25:27 -0600406
407 Returns:
408 Resulting image contents
Simon Glass7ae5f312018-06-01 09:38:19 -0600409 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700410 return self._DoReadFileDtb(fname, use_real_dtb)[0]
411
Simon Glass4f443042016-11-25 20:15:52 -0700412 @classmethod
413 def _MakeInputFile(self, fname, contents):
414 """Create a new test input file, creating directories as needed
415
416 Args:
Simon Glass3ab95982018-08-01 15:22:37 -0600417 fname: Filename to create
Simon Glass4f443042016-11-25 20:15:52 -0700418 contents: File contents to write in to the file
419 Returns:
420 Full pathname of file created
421 """
422 pathname = os.path.join(self._indir, fname)
423 dirname = os.path.dirname(pathname)
424 if dirname and not os.path.exists(dirname):
425 os.makedirs(dirname)
426 with open(pathname, 'wb') as fd:
427 fd.write(contents)
428 return pathname
429
430 @classmethod
Simon Glass0ef87aa2018-07-17 13:25:44 -0600431 def _MakeInputDir(self, dirname):
432 """Create a new test input directory, creating directories as needed
433
434 Args:
435 dirname: Directory name to create
436
437 Returns:
438 Full pathname of directory created
439 """
440 pathname = os.path.join(self._indir, dirname)
441 if not os.path.exists(pathname):
442 os.makedirs(pathname)
443 return pathname
444
445 @classmethod
Simon Glass11ae93e2018-10-01 21:12:47 -0600446 def _SetupSplElf(self, src_fname='bss_data'):
447 """Set up an ELF file with a '_dt_ucode_base_size' symbol
448
449 Args:
450 Filename of ELF file to use as SPL
451 """
Simon Glass1d0ebf72019-05-14 15:53:42 -0600452 with open(self.TestFile(src_fname), 'rb') as fd:
Simon Glass11ae93e2018-10-01 21:12:47 -0600453 TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
454
455 @classmethod
Simon Glass4f443042016-11-25 20:15:52 -0700456 def TestFile(self, fname):
457 return os.path.join(self._binman_dir, 'test', fname)
458
459 def AssertInList(self, grep_list, target):
460 """Assert that at least one of a list of things is in a target
461
462 Args:
463 grep_list: List of strings to check
464 target: Target string
465 """
466 for grep in grep_list:
467 if grep in target:
468 return
Simon Glass1fc62de2019-05-17 22:00:50 -0600469 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass4f443042016-11-25 20:15:52 -0700470
471 def CheckNoGaps(self, entries):
472 """Check that all entries fit together without gaps
473
474 Args:
475 entries: List of entries to check
476 """
Simon Glass3ab95982018-08-01 15:22:37 -0600477 offset = 0
Simon Glass4f443042016-11-25 20:15:52 -0700478 for entry in entries.values():
Simon Glass3ab95982018-08-01 15:22:37 -0600479 self.assertEqual(offset, entry.offset)
480 offset += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700481
Simon Glasse0ff8552016-11-25 20:15:53 -0700482 def GetFdtLen(self, dtb):
Simon Glass7ae5f312018-06-01 09:38:19 -0600483 """Get the totalsize field from a device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700484
485 Args:
Simon Glass7ae5f312018-06-01 09:38:19 -0600486 dtb: Device-tree binary contents
Simon Glasse0ff8552016-11-25 20:15:53 -0700487
488 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600489 Total size of device-tree binary, from the header
Simon Glasse0ff8552016-11-25 20:15:53 -0700490 """
491 return struct.unpack('>L', dtb[4:8])[0]
492
Simon Glass086cec92019-07-08 14:25:27 -0600493 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glass16b8d6b2018-07-06 10:27:42 -0600494 def AddNode(node, path):
495 if node.name != '/':
496 path += '/' + node.name
Simon Glass086cec92019-07-08 14:25:27 -0600497 for prop in node.props.values():
498 if prop.name in prop_names:
499 prop_path = path + ':' + prop.name
500 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
501 prop.value)
Simon Glass16b8d6b2018-07-06 10:27:42 -0600502 for subnode in node.subnodes:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600503 AddNode(subnode, path)
504
505 tree = {}
Simon Glass16b8d6b2018-07-06 10:27:42 -0600506 AddNode(dtb.GetRoot(), '')
507 return tree
508
Simon Glass4f443042016-11-25 20:15:52 -0700509 def testRun(self):
510 """Test a basic run with valid args"""
511 result = self._RunBinman('-h')
512
513 def testFullHelp(self):
514 """Test that the full help is displayed with -H"""
515 result = self._RunBinman('-H')
516 help_file = os.path.join(self._binman_dir, 'README')
Tom Rini3759df02018-01-16 15:29:50 -0500517 # Remove possible extraneous strings
518 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
519 gothelp = result.stdout.replace(extra, '')
520 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass4f443042016-11-25 20:15:52 -0700521 self.assertEqual(0, len(result.stderr))
522 self.assertEqual(0, result.return_code)
523
524 def testFullHelpInternal(self):
525 """Test that the full help is displayed with -H"""
526 try:
527 command.test_result = command.CommandResult()
528 result = self._DoBinman('-H')
529 help_file = os.path.join(self._binman_dir, 'README')
530 finally:
531 command.test_result = None
532
533 def testHelp(self):
534 """Test that the basic help is displayed with -h"""
535 result = self._RunBinman('-h')
536 self.assertTrue(len(result.stdout) > 200)
537 self.assertEqual(0, len(result.stderr))
538 self.assertEqual(0, result.return_code)
539
Simon Glass4f443042016-11-25 20:15:52 -0700540 def testBoard(self):
541 """Test that we can run it with a specific board"""
Simon Glass741f2d62018-10-01 12:22:30 -0600542 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass4f443042016-11-25 20:15:52 -0700543 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glass53cd5d92019-07-08 14:25:29 -0600544 result = self._DoBinman('build', '-b', 'sandbox')
Simon Glass4f443042016-11-25 20:15:52 -0700545 self.assertEqual(0, result)
546
547 def testNeedBoard(self):
548 """Test that we get an error when no board ius supplied"""
549 with self.assertRaises(ValueError) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600550 result = self._DoBinman('build')
Simon Glass4f443042016-11-25 20:15:52 -0700551 self.assertIn("Must provide a board to process (use -b <board>)",
552 str(e.exception))
553
554 def testMissingDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600555 """Test that an invalid device-tree file generates an error"""
Simon Glass4f443042016-11-25 20:15:52 -0700556 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600557 self._RunBinman('build', '-d', 'missing_file')
Simon Glass4f443042016-11-25 20:15:52 -0700558 # We get one error from libfdt, and a different one from fdtget.
559 self.AssertInList(["Couldn't open blob from 'missing_file'",
560 'No such file or directory'], str(e.exception))
561
562 def testBrokenDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600563 """Test that an invalid device-tree source file generates an error
Simon Glass4f443042016-11-25 20:15:52 -0700564
565 Since this is a source file it should be compiled and the error
566 will come from the device-tree compiler (dtc).
567 """
568 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600569 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700570 self.assertIn("FATAL ERROR: Unable to parse input tree",
571 str(e.exception))
572
573 def testMissingNode(self):
574 """Test that a device tree without a 'binman' node generates an error"""
575 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600576 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700577 self.assertIn("does not have a 'binman' node", str(e.exception))
578
579 def testEmpty(self):
580 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glass53cd5d92019-07-08 14:25:29 -0600581 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700582 self.assertEqual(0, len(result.stderr))
583 self.assertEqual(0, result.return_code)
584
585 def testInvalidEntry(self):
586 """Test that an invalid entry is flagged"""
587 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600588 result = self._RunBinman('build', '-d',
Simon Glass741f2d62018-10-01 12:22:30 -0600589 self.TestFile('004_invalid_entry.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700590 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
591 "'/binman/not-a-valid-type'", str(e.exception))
592
593 def testSimple(self):
594 """Test a simple binman with a single file"""
Simon Glass741f2d62018-10-01 12:22:30 -0600595 data = self._DoReadFile('005_simple.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700596 self.assertEqual(U_BOOT_DATA, data)
597
Simon Glass7fe91732017-11-13 18:55:00 -0700598 def testSimpleDebug(self):
599 """Test a simple binman run with debugging enabled"""
Simon Glasse2705fa2019-07-08 14:25:53 -0600600 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass7fe91732017-11-13 18:55:00 -0700601
Simon Glass4f443042016-11-25 20:15:52 -0700602 def testDual(self):
603 """Test that we can handle creating two images
604
605 This also tests image padding.
606 """
Simon Glass741f2d62018-10-01 12:22:30 -0600607 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700608 self.assertEqual(0, retcode)
609
610 image = control.images['image1']
Simon Glass8beb11e2019-07-08 14:25:47 -0600611 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700612 fname = tools.GetOutputFilename('image1.bin')
613 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600614 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700615 data = fd.read()
616 self.assertEqual(U_BOOT_DATA, data)
617
618 image = control.images['image2']
Simon Glass8beb11e2019-07-08 14:25:47 -0600619 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700620 fname = tools.GetOutputFilename('image2.bin')
621 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600622 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700623 data = fd.read()
624 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glasse6d85ff2019-05-14 15:53:47 -0600625 self.assertEqual(tools.GetBytes(0, 3), data[:3])
626 self.assertEqual(tools.GetBytes(0, 5), data[7:])
Simon Glass4f443042016-11-25 20:15:52 -0700627
628 def testBadAlign(self):
629 """Test that an invalid alignment value is detected"""
630 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600631 self._DoTestFile('007_bad_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700632 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
633 "of two", str(e.exception))
634
635 def testPackSimple(self):
636 """Test that packing works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600637 retcode = self._DoTestFile('008_pack.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700638 self.assertEqual(0, retcode)
639 self.assertIn('image', control.images)
640 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600641 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700642 self.assertEqual(5, len(entries))
643
644 # First u-boot
645 self.assertIn('u-boot', entries)
646 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600647 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700648 self.assertEqual(len(U_BOOT_DATA), entry.size)
649
650 # Second u-boot, aligned to 16-byte boundary
651 self.assertIn('u-boot-align', entries)
652 entry = entries['u-boot-align']
Simon Glass3ab95982018-08-01 15:22:37 -0600653 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700654 self.assertEqual(len(U_BOOT_DATA), entry.size)
655
656 # Third u-boot, size 23 bytes
657 self.assertIn('u-boot-size', entries)
658 entry = entries['u-boot-size']
Simon Glass3ab95982018-08-01 15:22:37 -0600659 self.assertEqual(20, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700660 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
661 self.assertEqual(23, entry.size)
662
663 # Fourth u-boot, placed immediate after the above
664 self.assertIn('u-boot-next', entries)
665 entry = entries['u-boot-next']
Simon Glass3ab95982018-08-01 15:22:37 -0600666 self.assertEqual(43, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700667 self.assertEqual(len(U_BOOT_DATA), entry.size)
668
Simon Glass3ab95982018-08-01 15:22:37 -0600669 # Fifth u-boot, placed at a fixed offset
Simon Glass4f443042016-11-25 20:15:52 -0700670 self.assertIn('u-boot-fixed', entries)
671 entry = entries['u-boot-fixed']
Simon Glass3ab95982018-08-01 15:22:37 -0600672 self.assertEqual(61, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700673 self.assertEqual(len(U_BOOT_DATA), entry.size)
674
Simon Glass8beb11e2019-07-08 14:25:47 -0600675 self.assertEqual(65, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700676
677 def testPackExtra(self):
678 """Test that extra packing feature works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600679 retcode = self._DoTestFile('009_pack_extra.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700680
681 self.assertEqual(0, retcode)
682 self.assertIn('image', control.images)
683 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600684 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700685 self.assertEqual(5, len(entries))
686
687 # First u-boot with padding before and after
688 self.assertIn('u-boot', entries)
689 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600690 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700691 self.assertEqual(3, entry.pad_before)
692 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
693
694 # Second u-boot has an aligned size, but it has no effect
695 self.assertIn('u-boot-align-size-nop', entries)
696 entry = entries['u-boot-align-size-nop']
Simon Glass3ab95982018-08-01 15:22:37 -0600697 self.assertEqual(12, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700698 self.assertEqual(4, entry.size)
699
700 # Third u-boot has an aligned size too
701 self.assertIn('u-boot-align-size', entries)
702 entry = entries['u-boot-align-size']
Simon Glass3ab95982018-08-01 15:22:37 -0600703 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700704 self.assertEqual(32, entry.size)
705
706 # Fourth u-boot has an aligned end
707 self.assertIn('u-boot-align-end', entries)
708 entry = entries['u-boot-align-end']
Simon Glass3ab95982018-08-01 15:22:37 -0600709 self.assertEqual(48, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700710 self.assertEqual(16, entry.size)
711
712 # Fifth u-boot immediately afterwards
713 self.assertIn('u-boot-align-both', entries)
714 entry = entries['u-boot-align-both']
Simon Glass3ab95982018-08-01 15:22:37 -0600715 self.assertEqual(64, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700716 self.assertEqual(64, entry.size)
717
718 self.CheckNoGaps(entries)
Simon Glass8beb11e2019-07-08 14:25:47 -0600719 self.assertEqual(128, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700720
721 def testPackAlignPowerOf2(self):
722 """Test that invalid entry alignment is detected"""
723 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600724 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700725 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
726 "of two", str(e.exception))
727
728 def testPackAlignSizePowerOf2(self):
729 """Test that invalid entry size alignment is detected"""
730 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600731 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700732 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
733 "power of two", str(e.exception))
734
735 def testPackInvalidAlign(self):
Simon Glass3ab95982018-08-01 15:22:37 -0600736 """Test detection of an offset that does not match its alignment"""
Simon Glass4f443042016-11-25 20:15:52 -0700737 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600738 self._DoTestFile('012_pack_inv_align.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600739 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700740 "align 0x4 (4)", str(e.exception))
741
742 def testPackInvalidSizeAlign(self):
743 """Test that invalid entry size alignment is detected"""
744 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600745 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700746 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
747 "align-size 0x4 (4)", str(e.exception))
748
749 def testPackOverlap(self):
750 """Test that overlapping regions are detected"""
751 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600752 self._DoTestFile('014_pack_overlap.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600753 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -0700754 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
755 str(e.exception))
756
757 def testPackEntryOverflow(self):
758 """Test that entries that overflow their size are detected"""
759 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600760 self._DoTestFile('015_pack_overflow.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700761 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
762 "but entry size is 0x3 (3)", str(e.exception))
763
764 def testPackImageOverflow(self):
765 """Test that entries which overflow the image size are detected"""
766 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600767 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600768 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass4f443042016-11-25 20:15:52 -0700769 "size 0x3 (3)", str(e.exception))
770
771 def testPackImageSize(self):
772 """Test that the image size can be set"""
Simon Glass741f2d62018-10-01 12:22:30 -0600773 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700774 self.assertEqual(0, retcode)
775 self.assertIn('image', control.images)
776 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -0600777 self.assertEqual(7, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700778
779 def testPackImageSizeAlign(self):
780 """Test that image size alignemnt works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600781 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700782 self.assertEqual(0, retcode)
783 self.assertIn('image', control.images)
784 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -0600785 self.assertEqual(16, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700786
787 def testPackInvalidImageAlign(self):
788 """Test that invalid image alignment is detected"""
789 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600790 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600791 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700792 "align-size 0x8 (8)", str(e.exception))
793
794 def testPackAlignPowerOf2(self):
795 """Test that invalid image alignment is detected"""
796 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600797 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -0600798 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass4f443042016-11-25 20:15:52 -0700799 "two", str(e.exception))
800
801 def testImagePadByte(self):
802 """Test that the image pad byte can be specified"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600803 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600804 data = self._DoReadFile('021_image_pad.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -0600805 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0xff, 1) +
806 U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -0700807
808 def testImageName(self):
809 """Test that image files can be named"""
Simon Glass741f2d62018-10-01 12:22:30 -0600810 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700811 self.assertEqual(0, retcode)
812 image = control.images['image1']
813 fname = tools.GetOutputFilename('test-name')
814 self.assertTrue(os.path.exists(fname))
815
816 image = control.images['image2']
817 fname = tools.GetOutputFilename('test-name.xx')
818 self.assertTrue(os.path.exists(fname))
819
820 def testBlobFilename(self):
821 """Test that generic blobs can be provided by filename"""
Simon Glass741f2d62018-10-01 12:22:30 -0600822 data = self._DoReadFile('023_blob.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700823 self.assertEqual(BLOB_DATA, data)
824
825 def testPackSorted(self):
826 """Test that entries can be sorted"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600827 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600828 data = self._DoReadFile('024_sorted.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -0600829 self.assertEqual(tools.GetBytes(0, 1) + U_BOOT_SPL_DATA +
830 tools.GetBytes(0, 2) + U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -0700831
Simon Glass3ab95982018-08-01 15:22:37 -0600832 def testPackZeroOffset(self):
833 """Test that an entry at offset 0 is not given a new offset"""
Simon Glass4f443042016-11-25 20:15:52 -0700834 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600835 self._DoTestFile('025_pack_zero_size.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600836 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -0700837 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
838 str(e.exception))
839
840 def testPackUbootDtb(self):
841 """Test that a device tree can be added to U-Boot"""
Simon Glass741f2d62018-10-01 12:22:30 -0600842 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700843 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glasse0ff8552016-11-25 20:15:53 -0700844
845 def testPackX86RomNoSize(self):
846 """Test that the end-at-4gb property requires a size property"""
847 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600848 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -0600849 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glasse0ff8552016-11-25 20:15:53 -0700850 "using end-at-4gb", str(e.exception))
851
Jagdish Gediya94b57db2018-09-03 21:35:07 +0530852 def test4gbAndSkipAtStartTogether(self):
853 """Test that the end-at-4gb and skip-at-size property can't be used
854 together"""
855 with self.assertRaises(ValueError) as e:
856 self._DoTestFile('80_4gb_and_skip_at_start_together.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -0600857 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya94b57db2018-09-03 21:35:07 +0530858 "'skip-at-start'", str(e.exception))
859
Simon Glasse0ff8552016-11-25 20:15:53 -0700860 def testPackX86RomOutside(self):
Simon Glass3ab95982018-08-01 15:22:37 -0600861 """Test that the end-at-4gb property checks for offset boundaries"""
Simon Glasse0ff8552016-11-25 20:15:53 -0700862 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600863 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600864 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) is outside "
Simon Glass8f1da502018-06-01 09:38:12 -0600865 "the section starting at 0xffffffe0 (4294967264)",
Simon Glasse0ff8552016-11-25 20:15:53 -0700866 str(e.exception))
867
868 def testPackX86Rom(self):
869 """Test that a basic x86 ROM can be created"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600870 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600871 data = self._DoReadFile('029_x86-rom.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -0600872 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 7) + U_BOOT_SPL_DATA +
873 tools.GetBytes(0, 2), data)
Simon Glasse0ff8552016-11-25 20:15:53 -0700874
875 def testPackX86RomMeNoDesc(self):
876 """Test that an invalid Intel descriptor entry is detected"""
Simon Glassc6c10e72019-05-17 22:00:46 -0600877 TestFunctional._MakeInputFile('descriptor.bin', b'')
Simon Glasse0ff8552016-11-25 20:15:53 -0700878 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600879 self._DoTestFile('031_x86-rom-me.dts')
Simon Glass458be452019-07-08 13:18:32 -0600880 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
881 str(e.exception))
Simon Glasse0ff8552016-11-25 20:15:53 -0700882
883 def testPackX86RomBadDesc(self):
884 """Test that the Intel requires a descriptor entry"""
885 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600886 self._DoTestFile('030_x86-rom-me-no-desc.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600887 self.assertIn("Node '/binman/intel-me': No offset set with "
888 "offset-unset: should another entry provide this correct "
889 "offset?", str(e.exception))
Simon Glasse0ff8552016-11-25 20:15:53 -0700890
891 def testPackX86RomMe(self):
892 """Test that an x86 ROM with an ME region can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -0600893 data = self._DoReadFile('031_x86-rom-me.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -0600894 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
895 if data[:0x1000] != expected_desc:
896 self.fail('Expected descriptor binary at start of image')
Simon Glasse0ff8552016-11-25 20:15:53 -0700897 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
898
899 def testPackVga(self):
900 """Test that an image with a VGA binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -0600901 data = self._DoReadFile('032_intel-vga.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -0700902 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
903
904 def testPackStart16(self):
905 """Test that an image with an x86 start16 region can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -0600906 data = self._DoReadFile('033_x86-start16.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -0700907 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
908
Jagdish Gediya9d368f32018-09-03 21:35:08 +0530909 def testPackPowerpcMpc85xxBootpgResetvec(self):
910 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
911 created"""
912 data = self._DoReadFile('81_powerpc_mpc85xx_bootpg_resetvec.dts')
913 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
914
Simon Glass736bb0a2018-07-06 10:27:17 -0600915 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glassadc57012018-07-06 10:27:16 -0600916 """Handle running a test for insertion of microcode
917
918 Args:
919 dts_fname: Name of test .dts file
920 nodtb_data: Data that we expect in the first section
Simon Glass736bb0a2018-07-06 10:27:17 -0600921 ucode_second: True if the microsecond entry is second instead of
922 third
Simon Glassadc57012018-07-06 10:27:16 -0600923
924 Returns:
925 Tuple:
926 Contents of first region (U-Boot or SPL)
Simon Glass3ab95982018-08-01 15:22:37 -0600927 Offset and size components of microcode pointer, as inserted
Simon Glassadc57012018-07-06 10:27:16 -0600928 in the above (two 4-byte words)
929 """
Simon Glass6b187df2017-11-12 21:52:27 -0700930 data = self._DoReadFile(dts_fname, True)
Simon Glasse0ff8552016-11-25 20:15:53 -0700931
932 # Now check the device tree has no microcode
Simon Glass736bb0a2018-07-06 10:27:17 -0600933 if ucode_second:
934 ucode_content = data[len(nodtb_data):]
935 ucode_pos = len(nodtb_data)
936 dtb_with_ucode = ucode_content[16:]
937 fdt_len = self.GetFdtLen(dtb_with_ucode)
938 else:
939 dtb_with_ucode = data[len(nodtb_data):]
940 fdt_len = self.GetFdtLen(dtb_with_ucode)
941 ucode_content = dtb_with_ucode[fdt_len:]
942 ucode_pos = len(nodtb_data) + fdt_len
Simon Glasse0ff8552016-11-25 20:15:53 -0700943 fname = tools.GetOutputFilename('test.dtb')
944 with open(fname, 'wb') as fd:
Simon Glassadc57012018-07-06 10:27:16 -0600945 fd.write(dtb_with_ucode)
Simon Glassec3f3782017-05-27 07:38:29 -0600946 dtb = fdt.FdtScan(fname)
947 ucode = dtb.GetNode('/microcode')
Simon Glasse0ff8552016-11-25 20:15:53 -0700948 self.assertTrue(ucode)
949 for node in ucode.subnodes:
950 self.assertFalse(node.props.get('data'))
951
Simon Glasse0ff8552016-11-25 20:15:53 -0700952 # Check that the microcode appears immediately after the Fdt
953 # This matches the concatenation of the data properties in
Simon Glass87722132017-11-12 21:52:26 -0700954 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glasse0ff8552016-11-25 20:15:53 -0700955 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
956 0x78235609)
Simon Glassadc57012018-07-06 10:27:16 -0600957 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glasse0ff8552016-11-25 20:15:53 -0700958
959 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -0600960 # expected offset and size
Simon Glasse0ff8552016-11-25 20:15:53 -0700961 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
962 len(ucode_data))
Simon Glass736bb0a2018-07-06 10:27:17 -0600963 u_boot = data[:len(nodtb_data)]
964 return u_boot, pos_and_size
Simon Glass6b187df2017-11-12 21:52:27 -0700965
966 def testPackUbootMicrocode(self):
967 """Test that x86 microcode can be handled correctly
968
969 We expect to see the following in the image, in order:
970 u-boot-nodtb.bin with a microcode pointer inserted at the correct
971 place
972 u-boot.dtb with the microcode removed
973 the microcode
974 """
Simon Glass741f2d62018-10-01 12:22:30 -0600975 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass6b187df2017-11-12 21:52:27 -0700976 U_BOOT_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -0600977 self.assertEqual(b'nodtb with microcode' + pos_and_size +
978 b' somewhere in here', first)
Simon Glasse0ff8552016-11-25 20:15:53 -0700979
Simon Glass160a7662017-05-27 07:38:26 -0600980 def _RunPackUbootSingleMicrocode(self):
Simon Glasse0ff8552016-11-25 20:15:53 -0700981 """Test that x86 microcode can be handled correctly
982
983 We expect to see the following in the image, in order:
984 u-boot-nodtb.bin with a microcode pointer inserted at the correct
985 place
986 u-boot.dtb with the microcode
987 an empty microcode region
988 """
989 # We need the libfdt library to run this test since only that allows
990 # finding the offset of a property. This is required by
991 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass741f2d62018-10-01 12:22:30 -0600992 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glasse0ff8552016-11-25 20:15:53 -0700993
994 second = data[len(U_BOOT_NODTB_DATA):]
995
996 fdt_len = self.GetFdtLen(second)
997 third = second[fdt_len:]
998 second = second[:fdt_len]
999
Simon Glass160a7662017-05-27 07:38:26 -06001000 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1001 self.assertIn(ucode_data, second)
1002 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -07001003
Simon Glass160a7662017-05-27 07:38:26 -06001004 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -06001005 # expected offset and size
Simon Glass160a7662017-05-27 07:38:26 -06001006 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1007 len(ucode_data))
1008 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glassc6c10e72019-05-17 22:00:46 -06001009 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1010 b' somewhere in here', first)
Simon Glassc49deb82016-11-25 20:15:54 -07001011
Simon Glass75db0862016-11-25 20:15:55 -07001012 def testPackUbootSingleMicrocode(self):
1013 """Test that x86 microcode can be handled correctly with fdt_normal.
1014 """
Simon Glass160a7662017-05-27 07:38:26 -06001015 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001016
Simon Glassc49deb82016-11-25 20:15:54 -07001017 def testUBootImg(self):
1018 """Test that u-boot.img can be put in a file"""
Simon Glass741f2d62018-10-01 12:22:30 -06001019 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glassc49deb82016-11-25 20:15:54 -07001020 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glass75db0862016-11-25 20:15:55 -07001021
1022 def testNoMicrocode(self):
1023 """Test that a missing microcode region is detected"""
1024 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001025 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001026 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1027 "node found in ", str(e.exception))
1028
1029 def testMicrocodeWithoutNode(self):
1030 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1031 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001032 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001033 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1034 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1035
1036 def testMicrocodeWithoutNode2(self):
1037 """Test that a missing u-boot-ucode node is detected"""
1038 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001039 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001040 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1041 "microcode region u-boot-ucode", str(e.exception))
1042
1043 def testMicrocodeWithoutPtrInElf(self):
1044 """Test that a U-Boot binary without the microcode symbol is detected"""
1045 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glass75db0862016-11-25 20:15:55 -07001046 try:
Simon Glass1d0ebf72019-05-14 15:53:42 -06001047 with open(self.TestFile('u_boot_no_ucode_ptr'), 'rb') as fd:
Simon Glass75db0862016-11-25 20:15:55 -07001048 TestFunctional._MakeInputFile('u-boot', fd.read())
1049
1050 with self.assertRaises(ValueError) as e:
Simon Glass160a7662017-05-27 07:38:26 -06001051 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001052 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1053 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1054
1055 finally:
1056 # Put the original file back
Simon Glass1d0ebf72019-05-14 15:53:42 -06001057 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
Simon Glass75db0862016-11-25 20:15:55 -07001058 TestFunctional._MakeInputFile('u-boot', fd.read())
1059
1060 def testMicrocodeNotInImage(self):
1061 """Test that microcode must be placed within the image"""
1062 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001063 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001064 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1065 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glass25ac0e62018-06-01 09:38:14 -06001066 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glass75db0862016-11-25 20:15:55 -07001067
1068 def testWithoutMicrocode(self):
1069 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glass1d0ebf72019-05-14 15:53:42 -06001070 with open(self.TestFile('u_boot_no_ucode_ptr'), 'rb') as fd:
Simon Glass75db0862016-11-25 20:15:55 -07001071 TestFunctional._MakeInputFile('u-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001072 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001073
1074 # Now check the device tree has no microcode
1075 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1076 second = data[len(U_BOOT_NODTB_DATA):]
1077
1078 fdt_len = self.GetFdtLen(second)
1079 self.assertEqual(dtb, second[:fdt_len])
1080
1081 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1082 third = data[used_len:]
Simon Glasse6d85ff2019-05-14 15:53:47 -06001083 self.assertEqual(tools.GetBytes(0, 0x200 - used_len), third)
Simon Glass75db0862016-11-25 20:15:55 -07001084
1085 def testUnknownPosSize(self):
1086 """Test that microcode must be placed within the image"""
1087 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001088 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glass3ab95982018-08-01 15:22:37 -06001089 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glass75db0862016-11-25 20:15:55 -07001090 "entry 'invalid-entry'", str(e.exception))
Simon Glassda229092016-11-25 20:15:56 -07001091
1092 def testPackFsp(self):
1093 """Test that an image with a FSP binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001094 data = self._DoReadFile('042_intel-fsp.dts')
Simon Glassda229092016-11-25 20:15:56 -07001095 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1096
1097 def testPackCmc(self):
Bin Meng59ea8c22017-08-15 22:41:54 -07001098 """Test that an image with a CMC binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001099 data = self._DoReadFile('043_intel-cmc.dts')
Simon Glassda229092016-11-25 20:15:56 -07001100 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Meng59ea8c22017-08-15 22:41:54 -07001101
1102 def testPackVbt(self):
1103 """Test that an image with a VBT binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001104 data = self._DoReadFile('046_intel-vbt.dts')
Bin Meng59ea8c22017-08-15 22:41:54 -07001105 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glass9fc60b42017-11-12 21:52:22 -07001106
Simon Glass56509842017-11-12 21:52:25 -07001107 def testSplBssPad(self):
1108 """Test that we can pad SPL's BSS with zeros"""
Simon Glass6b187df2017-11-12 21:52:27 -07001109 # ELF file with a '__bss_size' symbol
Simon Glass11ae93e2018-10-01 21:12:47 -06001110 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001111 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001112 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
1113 data)
Simon Glass56509842017-11-12 21:52:25 -07001114
Simon Glass86af5112018-10-01 21:12:42 -06001115 def testSplBssPadMissing(self):
1116 """Test that a missing symbol is detected"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001117 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glassb50e5612017-11-13 18:54:54 -07001118 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001119 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassb50e5612017-11-13 18:54:54 -07001120 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1121 str(e.exception))
1122
Simon Glass87722132017-11-12 21:52:26 -07001123 def testPackStart16Spl(self):
Simon Glass35b384c2018-09-14 04:57:10 -06001124 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001125 data = self._DoReadFile('048_x86-start16-spl.dts')
Simon Glass87722132017-11-12 21:52:26 -07001126 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1127
Simon Glass736bb0a2018-07-06 10:27:17 -06001128 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1129 """Helper function for microcode tests
Simon Glass6b187df2017-11-12 21:52:27 -07001130
1131 We expect to see the following in the image, in order:
1132 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1133 correct place
1134 u-boot.dtb with the microcode removed
1135 the microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001136
1137 Args:
1138 dts: Device tree file to use for test
1139 ucode_second: True if the microsecond entry is second instead of
1140 third
Simon Glass6b187df2017-11-12 21:52:27 -07001141 """
Simon Glass11ae93e2018-10-01 21:12:47 -06001142 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass736bb0a2018-07-06 10:27:17 -06001143 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1144 ucode_second=ucode_second)
Simon Glassc6c10e72019-05-17 22:00:46 -06001145 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1146 b'ter somewhere in here', first)
Simon Glass6b187df2017-11-12 21:52:27 -07001147
Simon Glass736bb0a2018-07-06 10:27:17 -06001148 def testPackUbootSplMicrocode(self):
1149 """Test that x86 microcode can be handled correctly in SPL"""
Simon Glass741f2d62018-10-01 12:22:30 -06001150 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass736bb0a2018-07-06 10:27:17 -06001151
1152 def testPackUbootSplMicrocodeReorder(self):
1153 """Test that order doesn't matter for microcode entries
1154
1155 This is the same as testPackUbootSplMicrocode but when we process the
1156 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1157 entry, so we reply on binman to try later.
1158 """
Simon Glass741f2d62018-10-01 12:22:30 -06001159 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass736bb0a2018-07-06 10:27:17 -06001160 ucode_second=True)
1161
Simon Glassca4f4ff2017-11-12 21:52:28 -07001162 def testPackMrc(self):
1163 """Test that an image with an MRC binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001164 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassca4f4ff2017-11-12 21:52:28 -07001165 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1166
Simon Glass47419ea2017-11-13 18:54:55 -07001167 def testSplDtb(self):
1168 """Test that an image with spl/u-boot-spl.dtb can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001169 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass47419ea2017-11-13 18:54:55 -07001170 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1171
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001172 def testSplNoDtb(self):
1173 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001174 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001175 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1176
Simon Glass19790632017-11-13 18:55:01 -07001177 def testSymbols(self):
1178 """Test binman can assign symbols embedded in U-Boot"""
1179 elf_fname = self.TestFile('u_boot_binman_syms')
1180 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1181 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Simon Glass3ab95982018-08-01 15:22:37 -06001182 self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr)
Simon Glass19790632017-11-13 18:55:01 -07001183
Simon Glass11ae93e2018-10-01 21:12:47 -06001184 self._SetupSplElf('u_boot_binman_syms')
Simon Glass741f2d62018-10-01 12:22:30 -06001185 data = self._DoReadFile('053_symbols.dts')
Simon Glass19790632017-11-13 18:55:01 -07001186 sym_values = struct.pack('<LQL', 0x24 + 0, 0x24 + 24, 0x24 + 20)
Simon Glasse6d85ff2019-05-14 15:53:47 -06001187 expected = (sym_values + U_BOOT_SPL_DATA[16:] +
1188 tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
1189 U_BOOT_SPL_DATA[16:])
Simon Glass19790632017-11-13 18:55:01 -07001190 self.assertEqual(expected, data)
1191
Simon Glassdd57c132018-06-01 09:38:11 -06001192 def testPackUnitAddress(self):
1193 """Test that we support multiple binaries with the same name"""
Simon Glass741f2d62018-10-01 12:22:30 -06001194 data = self._DoReadFile('054_unit_address.dts')
Simon Glassdd57c132018-06-01 09:38:11 -06001195 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1196
Simon Glass18546952018-06-01 09:38:16 -06001197 def testSections(self):
1198 """Basic test of sections"""
Simon Glass741f2d62018-10-01 12:22:30 -06001199 data = self._DoReadFile('055_sections.dts')
Simon Glassc6c10e72019-05-17 22:00:46 -06001200 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1201 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
1202 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
Simon Glass18546952018-06-01 09:38:16 -06001203 self.assertEqual(expected, data)
Simon Glass9fc60b42017-11-12 21:52:22 -07001204
Simon Glass3b0c3822018-06-01 09:38:20 -06001205 def testMap(self):
1206 """Tests outputting a map of the images"""
Simon Glass741f2d62018-10-01 12:22:30 -06001207 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001208 self.assertEqual('''ImagePos Offset Size Name
120900000000 00000000 00000028 main-section
121000000000 00000000 00000010 section@0
121100000000 00000000 00000004 u-boot
121200000010 00000010 00000010 section@1
121300000010 00000000 00000004 u-boot
121400000020 00000020 00000004 section@2
121500000020 00000000 00000004 u-boot
Simon Glass3b0c3822018-06-01 09:38:20 -06001216''', map_data)
1217
Simon Glassc8d48ef2018-06-01 09:38:21 -06001218 def testNamePrefix(self):
1219 """Tests that name prefixes are used"""
Simon Glass741f2d62018-10-01 12:22:30 -06001220 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001221 self.assertEqual('''ImagePos Offset Size Name
122200000000 00000000 00000028 main-section
122300000000 00000000 00000010 section@0
122400000000 00000000 00000004 ro-u-boot
122500000010 00000010 00000010 section@1
122600000010 00000000 00000004 rw-u-boot
Simon Glassc8d48ef2018-06-01 09:38:21 -06001227''', map_data)
1228
Simon Glass736bb0a2018-07-06 10:27:17 -06001229 def testUnknownContents(self):
1230 """Test that obtaining the contents works as expected"""
1231 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001232 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass8beb11e2019-07-08 14:25:47 -06001233 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glass736bb0a2018-07-06 10:27:17 -06001234 "processing of contents: remaining [<_testing.Entry__testing ",
1235 str(e.exception))
1236
Simon Glass5c890232018-07-06 10:27:19 -06001237 def testBadChangeSize(self):
1238 """Test that trying to change the size of an entry fails"""
Simon Glassc52c9e72019-07-08 14:25:37 -06001239 try:
1240 state.SetAllowEntryExpansion(False)
1241 with self.assertRaises(ValueError) as e:
1242 self._DoReadFile('059_change_size.dts', True)
Simon Glass79d3c582019-07-20 12:23:57 -06001243 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glassc52c9e72019-07-08 14:25:37 -06001244 str(e.exception))
1245 finally:
1246 state.SetAllowEntryExpansion(True)
Simon Glass5c890232018-07-06 10:27:19 -06001247
Simon Glass16b8d6b2018-07-06 10:27:42 -06001248 def testUpdateFdt(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001249 """Test that we can update the device tree with offset/size info"""
Simon Glass741f2d62018-10-01 12:22:30 -06001250 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glass16b8d6b2018-07-06 10:27:42 -06001251 update_dtb=True)
Simon Glasscee02e62018-07-17 13:25:52 -06001252 dtb = fdt.Fdt(out_dtb_fname)
1253 dtb.Scan()
Simon Glass12bb1a92019-07-20 12:23:51 -06001254 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001255 self.assertEqual({
Simon Glassdbf6be92018-08-01 15:22:42 -06001256 'image-pos': 0,
Simon Glass8122f392018-07-17 13:25:28 -06001257 'offset': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001258 '_testing:offset': 32,
Simon Glass79d3c582019-07-20 12:23:57 -06001259 '_testing:size': 2,
Simon Glassdbf6be92018-08-01 15:22:42 -06001260 '_testing:image-pos': 32,
Simon Glass3ab95982018-08-01 15:22:37 -06001261 'section@0/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001262 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001263 'section@0/u-boot:image-pos': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001264 'section@0:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001265 'section@0:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001266 'section@0:image-pos': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001267
Simon Glass3ab95982018-08-01 15:22:37 -06001268 'section@1/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001269 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001270 'section@1/u-boot:image-pos': 16,
Simon Glass3ab95982018-08-01 15:22:37 -06001271 'section@1:offset': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001272 'section@1:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001273 'section@1:image-pos': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001274 'size': 40
1275 }, props)
1276
1277 def testUpdateFdtBad(self):
1278 """Test that we detect when ProcessFdt never completes"""
1279 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001280 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001281 self.assertIn('Could not complete processing of Fdt: remaining '
1282 '[<_testing.Entry__testing', str(e.exception))
Simon Glass5c890232018-07-06 10:27:19 -06001283
Simon Glass53af22a2018-07-17 13:25:32 -06001284 def testEntryArgs(self):
1285 """Test passing arguments to entries from the command line"""
1286 entry_args = {
1287 'test-str-arg': 'test1',
1288 'test-int-arg': '456',
1289 }
Simon Glass741f2d62018-10-01 12:22:30 -06001290 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001291 self.assertIn('image', control.images)
1292 entry = control.images['image'].GetEntries()['_testing']
1293 self.assertEqual('test0', entry.test_str_fdt)
1294 self.assertEqual('test1', entry.test_str_arg)
1295 self.assertEqual(123, entry.test_int_fdt)
1296 self.assertEqual(456, entry.test_int_arg)
1297
1298 def testEntryArgsMissing(self):
1299 """Test missing arguments and properties"""
1300 entry_args = {
1301 'test-int-arg': '456',
1302 }
Simon Glass741f2d62018-10-01 12:22:30 -06001303 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001304 entry = control.images['image'].GetEntries()['_testing']
1305 self.assertEqual('test0', entry.test_str_fdt)
1306 self.assertEqual(None, entry.test_str_arg)
1307 self.assertEqual(None, entry.test_int_fdt)
1308 self.assertEqual(456, entry.test_int_arg)
1309
1310 def testEntryArgsRequired(self):
1311 """Test missing arguments and properties"""
1312 entry_args = {
1313 'test-int-arg': '456',
1314 }
1315 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001316 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass53af22a2018-07-17 13:25:32 -06001317 self.assertIn("Node '/binman/_testing': Missing required "
1318 'properties/entry args: test-str-arg, test-int-fdt, test-int-arg',
1319 str(e.exception))
1320
1321 def testEntryArgsInvalidFormat(self):
1322 """Test that an invalid entry-argument format is detected"""
Simon Glass53cd5d92019-07-08 14:25:29 -06001323 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1324 '-ano-value']
Simon Glass53af22a2018-07-17 13:25:32 -06001325 with self.assertRaises(ValueError) as e:
1326 self._DoBinman(*args)
1327 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1328
1329 def testEntryArgsInvalidInteger(self):
1330 """Test that an invalid entry-argument integer is detected"""
1331 entry_args = {
1332 'test-int-arg': 'abc',
1333 }
1334 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001335 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001336 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1337 "'test-int-arg' (value 'abc') to integer",
1338 str(e.exception))
1339
1340 def testEntryArgsInvalidDatatype(self):
1341 """Test that an invalid entry-argument datatype is detected
1342
1343 This test could be written in entry_test.py except that it needs
1344 access to control.entry_args, which seems more than that module should
1345 be able to see.
1346 """
1347 entry_args = {
1348 'test-bad-datatype-arg': '12',
1349 }
1350 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001351 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass53af22a2018-07-17 13:25:32 -06001352 entry_args=entry_args)
1353 self.assertIn('GetArg() internal error: Unknown data type ',
1354 str(e.exception))
1355
Simon Glassbb748372018-07-17 13:25:33 -06001356 def testText(self):
1357 """Test for a text entry type"""
1358 entry_args = {
1359 'test-id': TEXT_DATA,
1360 'test-id2': TEXT_DATA2,
1361 'test-id3': TEXT_DATA3,
1362 }
Simon Glass741f2d62018-10-01 12:22:30 -06001363 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glassbb748372018-07-17 13:25:33 -06001364 entry_args=entry_args)
Simon Glassc6c10e72019-05-17 22:00:46 -06001365 expected = (tools.ToBytes(TEXT_DATA) +
1366 tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1367 tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
Simon Glassaa88b502019-07-08 13:18:40 -06001368 b'some text' + b'more text')
Simon Glassbb748372018-07-17 13:25:33 -06001369 self.assertEqual(expected, data)
1370
Simon Glassfd8d1f72018-07-17 13:25:36 -06001371 def testEntryDocs(self):
1372 """Test for creation of entry documentation"""
1373 with test_util.capture_sys_output() as (stdout, stderr):
1374 control.WriteEntryDocs(binman.GetEntryModules())
1375 self.assertTrue(len(stdout.getvalue()) > 0)
1376
1377 def testEntryDocsMissing(self):
1378 """Test handling of missing entry documentation"""
1379 with self.assertRaises(ValueError) as e:
1380 with test_util.capture_sys_output() as (stdout, stderr):
1381 control.WriteEntryDocs(binman.GetEntryModules(), 'u_boot')
1382 self.assertIn('Documentation is missing for modules: u_boot',
1383 str(e.exception))
1384
Simon Glass11e36cc2018-07-17 13:25:38 -06001385 def testFmap(self):
1386 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001387 data = self._DoReadFile('067_fmap.dts')
Simon Glass11e36cc2018-07-17 13:25:38 -06001388 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc6c10e72019-05-17 22:00:46 -06001389 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1390 U_BOOT_DATA + tools.GetBytes(ord('a'), 12))
Simon Glass11e36cc2018-07-17 13:25:38 -06001391 self.assertEqual(expected, data[:32])
Simon Glassc6c10e72019-05-17 22:00:46 -06001392 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass11e36cc2018-07-17 13:25:38 -06001393 self.assertEqual(1, fhdr.ver_major)
1394 self.assertEqual(0, fhdr.ver_minor)
1395 self.assertEqual(0, fhdr.base)
1396 self.assertEqual(16 + 16 +
1397 fmap_util.FMAP_HEADER_LEN +
1398 fmap_util.FMAP_AREA_LEN * 3, fhdr.image_size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001399 self.assertEqual(b'FMAP', fhdr.name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001400 self.assertEqual(3, fhdr.nareas)
1401 for fentry in fentries:
1402 self.assertEqual(0, fentry.flags)
1403
1404 self.assertEqual(0, fentries[0].offset)
1405 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001406 self.assertEqual(b'RO_U_BOOT', fentries[0].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001407
1408 self.assertEqual(16, fentries[1].offset)
1409 self.assertEqual(4, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001410 self.assertEqual(b'RW_U_BOOT', fentries[1].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001411
1412 self.assertEqual(32, fentries[2].offset)
1413 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1414 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001415 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001416
Simon Glassec127af2018-07-17 13:25:39 -06001417 def testBlobNamedByArg(self):
1418 """Test we can add a blob with the filename coming from an entry arg"""
1419 entry_args = {
1420 'cros-ec-rw-path': 'ecrw.bin',
1421 }
Simon Glass741f2d62018-10-01 12:22:30 -06001422 data, _, _, _ = self._DoReadFileDtb('068_blob_named_by_arg.dts',
Simon Glassec127af2018-07-17 13:25:39 -06001423 entry_args=entry_args)
1424
Simon Glass3af8e492018-07-17 13:25:40 -06001425 def testFill(self):
1426 """Test for an fill entry type"""
Simon Glass741f2d62018-10-01 12:22:30 -06001427 data = self._DoReadFile('069_fill.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001428 expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
Simon Glass3af8e492018-07-17 13:25:40 -06001429 self.assertEqual(expected, data)
1430
1431 def testFillNoSize(self):
1432 """Test for an fill entry type with no size"""
1433 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001434 self._DoReadFile('070_fill_no_size.dts')
Simon Glass3af8e492018-07-17 13:25:40 -06001435 self.assertIn("'fill' entry must have a size property",
1436 str(e.exception))
1437
Simon Glass0ef87aa2018-07-17 13:25:44 -06001438 def _HandleGbbCommand(self, pipe_list):
1439 """Fake calls to the futility utility"""
1440 if pipe_list[0][0] == 'futility':
1441 fname = pipe_list[0][-1]
1442 # Append our GBB data to the file, which will happen every time the
1443 # futility command is called.
Simon Glass1d0ebf72019-05-14 15:53:42 -06001444 with open(fname, 'ab') as fd:
Simon Glass0ef87aa2018-07-17 13:25:44 -06001445 fd.write(GBB_DATA)
1446 return command.CommandResult()
1447
1448 def testGbb(self):
1449 """Test for the Chromium OS Google Binary Block"""
1450 command.test_result = self._HandleGbbCommand
1451 entry_args = {
1452 'keydir': 'devkeys',
1453 'bmpblk': 'bmpblk.bin',
1454 }
Simon Glass741f2d62018-10-01 12:22:30 -06001455 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glass0ef87aa2018-07-17 13:25:44 -06001456
1457 # Since futility
Simon Glasse6d85ff2019-05-14 15:53:47 -06001458 expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1459 tools.GetBytes(0, 0x2180 - 16))
Simon Glass0ef87aa2018-07-17 13:25:44 -06001460 self.assertEqual(expected, data)
1461
1462 def testGbbTooSmall(self):
1463 """Test for the Chromium OS Google Binary Block being large enough"""
1464 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001465 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001466 self.assertIn("Node '/binman/gbb': GBB is too small",
1467 str(e.exception))
1468
1469 def testGbbNoSize(self):
1470 """Test for the Chromium OS Google Binary Block having a size"""
1471 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001472 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001473 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1474 str(e.exception))
1475
Simon Glass24d0d3c2018-07-17 13:25:47 -06001476 def _HandleVblockCommand(self, pipe_list):
1477 """Fake calls to the futility utility"""
1478 if pipe_list[0][0] == 'futility':
1479 fname = pipe_list[0][3]
Simon Glassa326b492018-09-14 04:57:11 -06001480 with open(fname, 'wb') as fd:
Simon Glass24d0d3c2018-07-17 13:25:47 -06001481 fd.write(VBLOCK_DATA)
1482 return command.CommandResult()
1483
1484 def testVblock(self):
1485 """Test for the Chromium OS Verified Boot Block"""
1486 command.test_result = self._HandleVblockCommand
1487 entry_args = {
1488 'keydir': 'devkeys',
1489 }
Simon Glass741f2d62018-10-01 12:22:30 -06001490 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass24d0d3c2018-07-17 13:25:47 -06001491 entry_args=entry_args)
1492 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1493 self.assertEqual(expected, data)
1494
1495 def testVblockNoContent(self):
1496 """Test we detect a vblock which has no content to sign"""
1497 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001498 self._DoReadFile('075_vblock_no_content.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001499 self.assertIn("Node '/binman/vblock': Vblock must have a 'content' "
1500 'property', str(e.exception))
1501
1502 def testVblockBadPhandle(self):
1503 """Test that we detect a vblock with an invalid phandle in contents"""
1504 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001505 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001506 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1507 '1000', str(e.exception))
1508
1509 def testVblockBadEntry(self):
1510 """Test that we detect an entry that points to a non-entry"""
1511 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001512 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001513 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1514 "'other'", str(e.exception))
1515
Simon Glassb8ef5b62018-07-17 13:25:48 -06001516 def testTpl(self):
1517 """Test that an image with TPL and ots device tree can be created"""
1518 # ELF file with a '__bss_size' symbol
Simon Glass1d0ebf72019-05-14 15:53:42 -06001519 with open(self.TestFile('bss_data'), 'rb') as fd:
Simon Glassb8ef5b62018-07-17 13:25:48 -06001520 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001521 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glassb8ef5b62018-07-17 13:25:48 -06001522 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1523
Simon Glass15a587c2018-07-17 13:25:51 -06001524 def testUsesPos(self):
1525 """Test that the 'pos' property cannot be used anymore"""
1526 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001527 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass15a587c2018-07-17 13:25:51 -06001528 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1529 "'pos'", str(e.exception))
1530
Simon Glassd178eab2018-09-14 04:57:08 -06001531 def testFillZero(self):
1532 """Test for an fill entry type with a size of 0"""
Simon Glass741f2d62018-10-01 12:22:30 -06001533 data = self._DoReadFile('080_fill_empty.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001534 self.assertEqual(tools.GetBytes(0, 16), data)
Simon Glassd178eab2018-09-14 04:57:08 -06001535
Simon Glass0b489362018-09-14 04:57:09 -06001536 def testTextMissing(self):
1537 """Test for a text entry type where there is no text"""
1538 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001539 self._DoReadFileDtb('066_text.dts',)
Simon Glass0b489362018-09-14 04:57:09 -06001540 self.assertIn("Node '/binman/text': No value provided for text label "
1541 "'test-id'", str(e.exception))
1542
Simon Glass35b384c2018-09-14 04:57:10 -06001543 def testPackStart16Tpl(self):
1544 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001545 data = self._DoReadFile('081_x86-start16-tpl.dts')
Simon Glass35b384c2018-09-14 04:57:10 -06001546 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1547
Simon Glass0bfa7b02018-09-14 04:57:12 -06001548 def testSelectImage(self):
1549 """Test that we can select which images to build"""
Simon Glasseb833d82019-04-25 21:58:34 -06001550 expected = 'Skipping images: image1'
Simon Glass0bfa7b02018-09-14 04:57:12 -06001551
Simon Glasseb833d82019-04-25 21:58:34 -06001552 # We should only get the expected message in verbose mode
Simon Glassee0c9a72019-07-08 13:18:48 -06001553 for verbosity in (0, 2):
Simon Glasseb833d82019-04-25 21:58:34 -06001554 with test_util.capture_sys_output() as (stdout, stderr):
1555 retcode = self._DoTestFile('006_dual_image.dts',
1556 verbosity=verbosity,
1557 images=['image2'])
1558 self.assertEqual(0, retcode)
1559 if verbosity:
1560 self.assertIn(expected, stdout.getvalue())
1561 else:
1562 self.assertNotIn(expected, stdout.getvalue())
1563
1564 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1565 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
Simon Glass0bfa7b02018-09-14 04:57:12 -06001566
Simon Glass6ed45ba2018-09-14 04:57:24 -06001567 def testUpdateFdtAll(self):
1568 """Test that all device trees are updated with offset/size info"""
Simon Glass3c081312019-07-08 14:25:26 -06001569 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glass6ed45ba2018-09-14 04:57:24 -06001570
1571 base_expected = {
1572 'section:image-pos': 0,
1573 'u-boot-tpl-dtb:size': 513,
1574 'u-boot-spl-dtb:size': 513,
1575 'u-boot-spl-dtb:offset': 493,
1576 'image-pos': 0,
1577 'section/u-boot-dtb:image-pos': 0,
1578 'u-boot-spl-dtb:image-pos': 493,
1579 'section/u-boot-dtb:size': 493,
1580 'u-boot-tpl-dtb:image-pos': 1006,
1581 'section/u-boot-dtb:offset': 0,
1582 'section:size': 493,
1583 'offset': 0,
1584 'section:offset': 0,
1585 'u-boot-tpl-dtb:offset': 1006,
1586 'size': 1519
1587 }
1588
1589 # We expect three device-tree files in the output, one after the other.
1590 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1591 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1592 # main U-Boot tree. All three should have the same postions and offset.
1593 start = 0
1594 for item in ['', 'spl', 'tpl']:
1595 dtb = fdt.Fdt.FromData(data[start:])
1596 dtb.Scan()
Simon Glass12bb1a92019-07-20 12:23:51 -06001597 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
1598 ['spl', 'tpl'])
Simon Glass6ed45ba2018-09-14 04:57:24 -06001599 expected = dict(base_expected)
1600 if item:
1601 expected[item] = 0
1602 self.assertEqual(expected, props)
1603 start += dtb._fdt_obj.totalsize()
1604
1605 def testUpdateFdtOutput(self):
1606 """Test that output DTB files are updated"""
1607 try:
Simon Glass741f2d62018-10-01 12:22:30 -06001608 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glass6ed45ba2018-09-14 04:57:24 -06001609 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1610
1611 # Unfortunately, compiling a source file always results in a file
1612 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass741f2d62018-10-01 12:22:30 -06001613 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glass6ed45ba2018-09-14 04:57:24 -06001614 # binman as a file called u-boot.dtb. To fix this, copy the file
1615 # over to the expected place.
1616 #tools.WriteFile(os.path.join(self._indir, 'u-boot.dtb'),
1617 #tools.ReadFile(tools.GetOutputFilename('source.dtb')))
1618 start = 0
1619 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1620 'tpl/u-boot-tpl.dtb.out']:
1621 dtb = fdt.Fdt.FromData(data[start:])
1622 size = dtb._fdt_obj.totalsize()
1623 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1624 outdata = tools.ReadFile(pathname)
1625 name = os.path.split(fname)[0]
1626
1627 if name:
1628 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1629 else:
1630 orig_indata = dtb_data
1631 self.assertNotEqual(outdata, orig_indata,
1632 "Expected output file '%s' be updated" % pathname)
1633 self.assertEqual(outdata, data[start:start + size],
1634 "Expected output file '%s' to match output image" %
1635 pathname)
1636 start += size
1637 finally:
1638 self._ResetDtbs()
1639
Simon Glass83d73c22018-09-14 04:57:26 -06001640 def _decompress(self, data):
Simon Glassff5c7e32019-07-08 13:18:42 -06001641 return tools.Decompress(data, 'lz4')
Simon Glass83d73c22018-09-14 04:57:26 -06001642
1643 def testCompress(self):
1644 """Test compression of blobs"""
Simon Glassac62fba2019-07-08 13:18:53 -06001645 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06001646 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass83d73c22018-09-14 04:57:26 -06001647 use_real_dtb=True, update_dtb=True)
1648 dtb = fdt.Fdt(out_dtb_fname)
1649 dtb.Scan()
1650 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1651 orig = self._decompress(data)
1652 self.assertEquals(COMPRESS_DATA, orig)
1653 expected = {
1654 'blob:uncomp-size': len(COMPRESS_DATA),
1655 'blob:size': len(data),
1656 'size': len(data),
1657 }
1658 self.assertEqual(expected, props)
1659
Simon Glass0a98b282018-09-14 04:57:28 -06001660 def testFiles(self):
1661 """Test bringing in multiple files"""
Simon Glass741f2d62018-10-01 12:22:30 -06001662 data = self._DoReadFile('084_files.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001663 self.assertEqual(FILES_DATA, data)
1664
1665 def testFilesCompress(self):
1666 """Test bringing in multiple files and compressing them"""
Simon Glassac62fba2019-07-08 13:18:53 -06001667 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06001668 data = self._DoReadFile('085_files_compress.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001669
1670 image = control.images['image']
1671 entries = image.GetEntries()
1672 files = entries['files']
Simon Glass8beb11e2019-07-08 14:25:47 -06001673 entries = files._entries
Simon Glass0a98b282018-09-14 04:57:28 -06001674
Simon Glassc6c10e72019-05-17 22:00:46 -06001675 orig = b''
Simon Glass0a98b282018-09-14 04:57:28 -06001676 for i in range(1, 3):
1677 key = '%d.dat' % i
1678 start = entries[key].image_pos
1679 len = entries[key].size
1680 chunk = data[start:start + len]
1681 orig += self._decompress(chunk)
1682
1683 self.assertEqual(FILES_DATA, orig)
1684
1685 def testFilesMissing(self):
1686 """Test missing files"""
1687 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001688 data = self._DoReadFile('086_files_none.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001689 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1690 'no files', str(e.exception))
1691
1692 def testFilesNoPattern(self):
1693 """Test missing files"""
1694 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001695 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001696 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1697 str(e.exception))
1698
Simon Glassba64a0b2018-09-14 04:57:29 -06001699 def testExpandSize(self):
1700 """Test an expanding entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001701 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
Simon Glassba64a0b2018-09-14 04:57:29 -06001702 map=True)
Simon Glassc6c10e72019-05-17 22:00:46 -06001703 expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA +
1704 MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA +
1705 tools.GetBytes(ord('c'), 8) + U_BOOT_DATA +
1706 tools.GetBytes(ord('d'), 8))
Simon Glassba64a0b2018-09-14 04:57:29 -06001707 self.assertEqual(expect, data)
1708 self.assertEqual('''ImagePos Offset Size Name
170900000000 00000000 00000028 main-section
171000000000 00000000 00000008 fill
171100000008 00000008 00000004 u-boot
17120000000c 0000000c 00000004 section
17130000000c 00000000 00000003 intel-mrc
171400000010 00000010 00000004 u-boot2
171500000014 00000014 0000000c section2
171600000014 00000000 00000008 fill
17170000001c 00000008 00000004 u-boot
171800000020 00000020 00000008 fill2
1719''', map_data)
1720
1721 def testExpandSizeBad(self):
1722 """Test an expanding entry which fails to provide contents"""
Simon Glass163ed6c2018-09-14 04:57:36 -06001723 with test_util.capture_sys_output() as (stdout, stderr):
1724 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001725 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
Simon Glassba64a0b2018-09-14 04:57:29 -06001726 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
1727 'expanding entry', str(e.exception))
1728
Simon Glasse0e5df92018-09-14 04:57:31 -06001729 def testHash(self):
1730 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001731 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06001732 use_real_dtb=True, update_dtb=True)
1733 dtb = fdt.Fdt(out_dtb_fname)
1734 dtb.Scan()
1735 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
1736 m = hashlib.sha256()
1737 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001738 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06001739
1740 def testHashNoAlgo(self):
1741 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001742 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06001743 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
1744 'hash node', str(e.exception))
1745
1746 def testHashBadAlgo(self):
1747 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001748 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06001749 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
1750 str(e.exception))
1751
1752 def testHashSection(self):
1753 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001754 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06001755 use_real_dtb=True, update_dtb=True)
1756 dtb = fdt.Fdt(out_dtb_fname)
1757 dtb.Scan()
1758 hash_node = dtb.GetNode('/binman/section/hash').props['value']
1759 m = hashlib.sha256()
1760 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001761 m.update(tools.GetBytes(ord('a'), 16))
1762 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06001763
Simon Glassf0253632018-09-14 04:57:32 -06001764 def testPackUBootTplMicrocode(self):
1765 """Test that x86 microcode can be handled correctly in TPL
1766
1767 We expect to see the following in the image, in order:
1768 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
1769 place
1770 u-boot-tpl.dtb with the microcode removed
1771 the microcode
1772 """
Simon Glass1d0ebf72019-05-14 15:53:42 -06001773 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
Simon Glassf0253632018-09-14 04:57:32 -06001774 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001775 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glassf0253632018-09-14 04:57:32 -06001776 U_BOOT_TPL_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001777 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
1778 b'ter somewhere in here', first)
Simon Glassf0253632018-09-14 04:57:32 -06001779
Simon Glassf8f8df62018-09-14 04:57:34 -06001780 def testFmapX86(self):
1781 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001782 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassf8f8df62018-09-14 04:57:34 -06001783 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc6c10e72019-05-17 22:00:46 -06001784 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06001785 self.assertEqual(expected, data[:32])
1786 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1787
1788 self.assertEqual(0x100, fhdr.image_size)
1789
1790 self.assertEqual(0, fentries[0].offset)
1791 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001792 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001793
1794 self.assertEqual(4, fentries[1].offset)
1795 self.assertEqual(3, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001796 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001797
1798 self.assertEqual(32, fentries[2].offset)
1799 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1800 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001801 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001802
1803 def testFmapX86Section(self):
1804 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001805 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glassc6c10e72019-05-17 22:00:46 -06001806 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06001807 self.assertEqual(expected, data[:32])
1808 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
1809
1810 self.assertEqual(0x100, fhdr.image_size)
1811
1812 self.assertEqual(0, fentries[0].offset)
1813 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001814 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001815
1816 self.assertEqual(4, fentries[1].offset)
1817 self.assertEqual(3, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001818 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001819
1820 self.assertEqual(36, fentries[2].offset)
1821 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1822 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001823 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001824
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001825 def testElf(self):
1826 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001827 self._SetupSplElf()
Simon Glass1d0ebf72019-05-14 15:53:42 -06001828 with open(self.TestFile('bss_data'), 'rb') as fd:
Simon Glass4c650252019-07-08 13:18:46 -06001829 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
1830 with open(self.TestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001831 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001832 data = self._DoReadFile('096_elf.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001833
Simon Glass093d1682019-07-08 13:18:25 -06001834 def testElfStrip(self):
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001835 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001836 self._SetupSplElf()
Simon Glass1d0ebf72019-05-14 15:53:42 -06001837 with open(self.TestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001838 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001839 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001840
Simon Glass163ed6c2018-09-14 04:57:36 -06001841 def testPackOverlapMap(self):
1842 """Test that overlapping regions are detected"""
1843 with test_util.capture_sys_output() as (stdout, stderr):
1844 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001845 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glass163ed6c2018-09-14 04:57:36 -06001846 map_fname = tools.GetOutputFilename('image.map')
1847 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
1848 stdout.getvalue())
1849
1850 # We should not get an inmage, but there should be a map file
1851 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
1852 self.assertTrue(os.path.exists(map_fname))
Simon Glasseb546ac2019-05-17 22:00:51 -06001853 map_data = tools.ReadFile(map_fname, binary=False)
Simon Glass163ed6c2018-09-14 04:57:36 -06001854 self.assertEqual('''ImagePos Offset Size Name
1855<none> 00000000 00000007 main-section
1856<none> 00000000 00000004 u-boot
1857<none> 00000003 00000004 u-boot-align
1858''', map_data)
1859
Simon Glass093d1682019-07-08 13:18:25 -06001860 def testPackRefCode(self):
Simon Glass3ae192c2018-10-01 12:22:31 -06001861 """Test that an image with an Intel Reference code binary works"""
1862 data = self._DoReadFile('100_intel_refcode.dts')
1863 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
1864
Simon Glass9481c802019-04-25 21:58:39 -06001865 def testSectionOffset(self):
1866 """Tests use of a section with an offset"""
1867 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
1868 map=True)
1869 self.assertEqual('''ImagePos Offset Size Name
187000000000 00000000 00000038 main-section
187100000004 00000004 00000010 section@0
187200000004 00000000 00000004 u-boot
187300000018 00000018 00000010 section@1
187400000018 00000000 00000004 u-boot
18750000002c 0000002c 00000004 section@2
18760000002c 00000000 00000004 u-boot
1877''', map_data)
1878 self.assertEqual(data,
Simon Glasse6d85ff2019-05-14 15:53:47 -06001879 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1880 tools.GetBytes(0x21, 12) +
1881 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1882 tools.GetBytes(0x61, 12) +
1883 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1884 tools.GetBytes(0x26, 8))
Simon Glass9481c802019-04-25 21:58:39 -06001885
Simon Glassac62fba2019-07-08 13:18:53 -06001886 def testCbfsRaw(self):
1887 """Test base handling of a Coreboot Filesystem (CBFS)
1888
1889 The exact contents of the CBFS is verified by similar tests in
1890 cbfs_util_test.py. The tests here merely check that the files added to
1891 the CBFS can be found in the final image.
1892 """
1893 data = self._DoReadFile('102_cbfs_raw.dts')
1894 size = 0xb0
1895
1896 cbfs = cbfs_util.CbfsReader(data)
1897 self.assertEqual(size, cbfs.rom_size)
1898
1899 self.assertIn('u-boot-dtb', cbfs.files)
1900 cfile = cbfs.files['u-boot-dtb']
1901 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
1902
1903 def testCbfsArch(self):
1904 """Test on non-x86 architecture"""
1905 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
1906 size = 0x100
1907
1908 cbfs = cbfs_util.CbfsReader(data)
1909 self.assertEqual(size, cbfs.rom_size)
1910
1911 self.assertIn('u-boot-dtb', cbfs.files)
1912 cfile = cbfs.files['u-boot-dtb']
1913 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
1914
1915 def testCbfsStage(self):
1916 """Tests handling of a Coreboot Filesystem (CBFS)"""
1917 if not elf.ELF_TOOLS:
1918 self.skipTest('Python elftools not available')
1919 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
1920 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
1921 size = 0xb0
1922
1923 data = self._DoReadFile('104_cbfs_stage.dts')
1924 cbfs = cbfs_util.CbfsReader(data)
1925 self.assertEqual(size, cbfs.rom_size)
1926
1927 self.assertIn('u-boot', cbfs.files)
1928 cfile = cbfs.files['u-boot']
1929 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
1930
1931 def testCbfsRawCompress(self):
1932 """Test handling of compressing raw files"""
1933 self._CheckLz4()
1934 data = self._DoReadFile('105_cbfs_raw_compress.dts')
1935 size = 0x140
1936
1937 cbfs = cbfs_util.CbfsReader(data)
1938 self.assertIn('u-boot', cbfs.files)
1939 cfile = cbfs.files['u-boot']
1940 self.assertEqual(COMPRESS_DATA, cfile.data)
1941
1942 def testCbfsBadArch(self):
1943 """Test handling of a bad architecture"""
1944 with self.assertRaises(ValueError) as e:
1945 self._DoReadFile('106_cbfs_bad_arch.dts')
1946 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
1947
1948 def testCbfsNoSize(self):
1949 """Test handling of a missing size property"""
1950 with self.assertRaises(ValueError) as e:
1951 self._DoReadFile('107_cbfs_no_size.dts')
1952 self.assertIn('entry must have a size property', str(e.exception))
1953
1954 def testCbfsNoCOntents(self):
1955 """Test handling of a CBFS entry which does not provide contentsy"""
1956 with self.assertRaises(ValueError) as e:
1957 self._DoReadFile('108_cbfs_no_contents.dts')
1958 self.assertIn('Could not complete processing of contents',
1959 str(e.exception))
1960
1961 def testCbfsBadCompress(self):
1962 """Test handling of a bad architecture"""
1963 with self.assertRaises(ValueError) as e:
1964 self._DoReadFile('109_cbfs_bad_compress.dts')
1965 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
1966 str(e.exception))
1967
1968 def testCbfsNamedEntries(self):
1969 """Test handling of named entries"""
1970 data = self._DoReadFile('110_cbfs_name.dts')
1971
1972 cbfs = cbfs_util.CbfsReader(data)
1973 self.assertIn('FRED', cbfs.files)
1974 cfile1 = cbfs.files['FRED']
1975 self.assertEqual(U_BOOT_DATA, cfile1.data)
1976
1977 self.assertIn('hello', cbfs.files)
1978 cfile2 = cbfs.files['hello']
1979 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
1980
Simon Glassc5ac1382019-07-08 13:18:54 -06001981 def _SetupIfwi(self, fname):
1982 """Set up to run an IFWI test
1983
1984 Args:
1985 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
1986 """
1987 self._SetupSplElf()
1988
1989 # Intel Integrated Firmware Image (IFWI) file
1990 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
1991 data = fd.read()
1992 TestFunctional._MakeInputFile(fname,data)
1993
1994 def _CheckIfwi(self, data):
1995 """Check that an image with an IFWI contains the correct output
1996
1997 Args:
1998 data: Conents of output file
1999 """
2000 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
2001 if data[:0x1000] != expected_desc:
2002 self.fail('Expected descriptor binary at start of image')
2003
2004 # We expect to find the TPL wil in subpart IBBP entry IBBL
2005 image_fname = tools.GetOutputFilename('image.bin')
2006 tpl_fname = tools.GetOutputFilename('tpl.out')
2007 tools.RunIfwiTool(image_fname, tools.CMD_EXTRACT, fname=tpl_fname,
2008 subpart='IBBP', entry_name='IBBL')
2009
2010 tpl_data = tools.ReadFile(tpl_fname)
2011 self.assertEqual(tpl_data[:len(U_BOOT_TPL_DATA)], U_BOOT_TPL_DATA)
2012
2013 def testPackX86RomIfwi(self):
2014 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2015 self._SetupIfwi('fitimage.bin')
2016 data = self._DoReadFile('111_x86-rom-ifwi.dts')
2017 self._CheckIfwi(data)
2018
2019 def testPackX86RomIfwiNoDesc(self):
2020 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2021 self._SetupIfwi('ifwi.bin')
2022 data = self._DoReadFile('112_x86-rom-ifwi-nodesc.dts')
2023 self._CheckIfwi(data)
2024
2025 def testPackX86RomIfwiNoData(self):
2026 """Test that an x86 ROM with IFWI handles missing data"""
2027 self._SetupIfwi('ifwi.bin')
2028 with self.assertRaises(ValueError) as e:
2029 data = self._DoReadFile('113_x86-rom-ifwi-nodata.dts')
2030 self.assertIn('Could not complete processing of contents',
2031 str(e.exception))
Simon Glass53af22a2018-07-17 13:25:32 -06002032
Simon Glasse073d4e2019-07-08 13:18:56 -06002033 def testCbfsOffset(self):
2034 """Test a CBFS with files at particular offsets
2035
2036 Like all CFBS tests, this is just checking the logic that calls
2037 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2038 """
2039 data = self._DoReadFile('114_cbfs_offset.dts')
2040 size = 0x200
2041
2042 cbfs = cbfs_util.CbfsReader(data)
2043 self.assertEqual(size, cbfs.rom_size)
2044
2045 self.assertIn('u-boot', cbfs.files)
2046 cfile = cbfs.files['u-boot']
2047 self.assertEqual(U_BOOT_DATA, cfile.data)
2048 self.assertEqual(0x40, cfile.cbfs_offset)
2049
2050 self.assertIn('u-boot-dtb', cbfs.files)
2051 cfile2 = cbfs.files['u-boot-dtb']
2052 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2053 self.assertEqual(0x140, cfile2.cbfs_offset)
2054
Simon Glass086cec92019-07-08 14:25:27 -06002055 def testFdtmap(self):
2056 """Test an FDT map can be inserted in the image"""
2057 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2058 fdtmap_data = data[len(U_BOOT_DATA):]
2059 magic = fdtmap_data[:8]
2060 self.assertEqual('_FDTMAP_', magic)
2061 self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
2062
2063 fdt_data = fdtmap_data[16:]
2064 dtb = fdt.Fdt.FromData(fdt_data)
2065 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002066 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass086cec92019-07-08 14:25:27 -06002067 self.assertEqual({
2068 'image-pos': 0,
2069 'offset': 0,
2070 'u-boot:offset': 0,
2071 'u-boot:size': len(U_BOOT_DATA),
2072 'u-boot:image-pos': 0,
2073 'fdtmap:image-pos': 4,
2074 'fdtmap:offset': 4,
2075 'fdtmap:size': len(fdtmap_data),
2076 'size': len(data),
2077 }, props)
2078
2079 def testFdtmapNoMatch(self):
2080 """Check handling of an FDT map when the section cannot be found"""
2081 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2082
2083 # Mangle the section name, which should cause a mismatch between the
2084 # correct FDT path and the one expected by the section
2085 image = control.images['image']
Simon Glasscf228942019-07-08 14:25:28 -06002086 image._node.path += '-suffix'
Simon Glass086cec92019-07-08 14:25:27 -06002087 entries = image.GetEntries()
2088 fdtmap = entries['fdtmap']
2089 with self.assertRaises(ValueError) as e:
2090 fdtmap._GetFdtmap()
2091 self.assertIn("Cannot locate node for path '/binman-suffix'",
2092 str(e.exception))
2093
Simon Glasscf228942019-07-08 14:25:28 -06002094 def testFdtmapHeader(self):
2095 """Test an FDT map and image header can be inserted in the image"""
2096 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2097 fdtmap_pos = len(U_BOOT_DATA)
2098 fdtmap_data = data[fdtmap_pos:]
2099 fdt_data = fdtmap_data[16:]
2100 dtb = fdt.Fdt.FromData(fdt_data)
2101 fdt_size = dtb.GetFdtObj().totalsize()
2102 hdr_data = data[-8:]
2103 self.assertEqual('BinM', hdr_data[:4])
2104 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2105 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2106
2107 def testFdtmapHeaderStart(self):
2108 """Test an image header can be inserted at the image start"""
2109 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2110 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2111 hdr_data = data[:8]
2112 self.assertEqual('BinM', hdr_data[:4])
2113 offset = struct.unpack('<I', hdr_data[4:])[0]
2114 self.assertEqual(fdtmap_pos, offset)
2115
2116 def testFdtmapHeaderPos(self):
2117 """Test an image header can be inserted at a chosen position"""
2118 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2119 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2120 hdr_data = data[0x80:0x88]
2121 self.assertEqual('BinM', hdr_data[:4])
2122 offset = struct.unpack('<I', hdr_data[4:])[0]
2123 self.assertEqual(fdtmap_pos, offset)
2124
2125 def testHeaderMissingFdtmap(self):
2126 """Test an image header requires an fdtmap"""
2127 with self.assertRaises(ValueError) as e:
2128 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2129 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2130 str(e.exception))
2131
2132 def testHeaderNoLocation(self):
2133 """Test an image header with a no specified location is detected"""
2134 with self.assertRaises(ValueError) as e:
2135 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2136 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2137 str(e.exception))
2138
Simon Glassc52c9e72019-07-08 14:25:37 -06002139 def testEntryExpand(self):
2140 """Test expanding an entry after it is packed"""
2141 data = self._DoReadFile('121_entry_expand.dts')
Simon Glass79d3c582019-07-20 12:23:57 -06002142 self.assertEqual(b'aaa', data[:3])
2143 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2144 self.assertEqual(b'aaa', data[-3:])
Simon Glassc52c9e72019-07-08 14:25:37 -06002145
2146 def testEntryExpandBad(self):
2147 """Test expanding an entry after it is packed, twice"""
2148 with self.assertRaises(ValueError) as e:
2149 self._DoReadFile('122_entry_expand_twice.dts')
Simon Glass61ec04f2019-07-20 12:23:58 -06002150 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glassc52c9e72019-07-08 14:25:37 -06002151 str(e.exception))
2152
2153 def testEntryExpandSection(self):
2154 """Test expanding an entry within a section after it is packed"""
2155 data = self._DoReadFile('123_entry_expand_section.dts')
Simon Glass79d3c582019-07-20 12:23:57 -06002156 self.assertEqual(b'aaa', data[:3])
2157 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2158 self.assertEqual(b'aaa', data[-3:])
Simon Glassc52c9e72019-07-08 14:25:37 -06002159
Simon Glass6c223fd2019-07-08 14:25:38 -06002160 def testCompressDtb(self):
2161 """Test that compress of device-tree files is supported"""
2162 self._CheckLz4()
2163 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2164 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2165 comp_data = data[len(U_BOOT_DATA):]
2166 orig = self._decompress(comp_data)
2167 dtb = fdt.Fdt.FromData(orig)
2168 dtb.Scan()
2169 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2170 expected = {
2171 'u-boot:size': len(U_BOOT_DATA),
2172 'u-boot-dtb:uncomp-size': len(orig),
2173 'u-boot-dtb:size': len(comp_data),
2174 'size': len(data),
2175 }
2176 self.assertEqual(expected, props)
2177
Simon Glass69f7cb32019-07-08 14:25:41 -06002178 def testCbfsUpdateFdt(self):
2179 """Test that we can update the device tree with CBFS offset/size info"""
2180 self._CheckLz4()
2181 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2182 update_dtb=True)
2183 dtb = fdt.Fdt(out_dtb_fname)
2184 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002185 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass69f7cb32019-07-08 14:25:41 -06002186 del props['cbfs/u-boot:size']
2187 self.assertEqual({
2188 'offset': 0,
2189 'size': len(data),
2190 'image-pos': 0,
2191 'cbfs:offset': 0,
2192 'cbfs:size': len(data),
2193 'cbfs:image-pos': 0,
2194 'cbfs/u-boot:offset': 0x38,
2195 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2196 'cbfs/u-boot:image-pos': 0x38,
2197 'cbfs/u-boot-dtb:offset': 0xb8,
2198 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2199 'cbfs/u-boot-dtb:image-pos': 0xb8,
2200 }, props)
2201
Simon Glass8a1ad062019-07-08 14:25:42 -06002202 def testCbfsBadType(self):
2203 """Test an image header with a no specified location is detected"""
2204 with self.assertRaises(ValueError) as e:
2205 self._DoReadFile('126_cbfs_bad_type.dts')
2206 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2207
Simon Glass41b8ba02019-07-08 14:25:43 -06002208 def testList(self):
2209 """Test listing the files in an image"""
2210 self._CheckLz4()
2211 data = self._DoReadFile('127_list.dts')
2212 image = control.images['image']
2213 entries = image.BuildEntryList()
2214 self.assertEqual(7, len(entries))
2215
2216 ent = entries[0]
2217 self.assertEqual(0, ent.indent)
2218 self.assertEqual('main-section', ent.name)
2219 self.assertEqual('section', ent.etype)
2220 self.assertEqual(len(data), ent.size)
2221 self.assertEqual(0, ent.image_pos)
2222 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002223 self.assertEqual(0, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002224
2225 ent = entries[1]
2226 self.assertEqual(1, ent.indent)
2227 self.assertEqual('u-boot', ent.name)
2228 self.assertEqual('u-boot', ent.etype)
2229 self.assertEqual(len(U_BOOT_DATA), ent.size)
2230 self.assertEqual(0, ent.image_pos)
2231 self.assertEqual(None, ent.uncomp_size)
2232 self.assertEqual(0, ent.offset)
2233
2234 ent = entries[2]
2235 self.assertEqual(1, ent.indent)
2236 self.assertEqual('section', ent.name)
2237 self.assertEqual('section', ent.etype)
2238 section_size = ent.size
2239 self.assertEqual(0x100, ent.image_pos)
2240 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002241 self.assertEqual(0x100, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002242
2243 ent = entries[3]
2244 self.assertEqual(2, ent.indent)
2245 self.assertEqual('cbfs', ent.name)
2246 self.assertEqual('cbfs', ent.etype)
2247 self.assertEqual(0x400, ent.size)
2248 self.assertEqual(0x100, ent.image_pos)
2249 self.assertEqual(None, ent.uncomp_size)
2250 self.assertEqual(0, ent.offset)
2251
2252 ent = entries[4]
2253 self.assertEqual(3, ent.indent)
2254 self.assertEqual('u-boot', ent.name)
2255 self.assertEqual('u-boot', ent.etype)
2256 self.assertEqual(len(U_BOOT_DATA), ent.size)
2257 self.assertEqual(0x138, ent.image_pos)
2258 self.assertEqual(None, ent.uncomp_size)
2259 self.assertEqual(0x38, ent.offset)
2260
2261 ent = entries[5]
2262 self.assertEqual(3, ent.indent)
2263 self.assertEqual('u-boot-dtb', ent.name)
2264 self.assertEqual('text', ent.etype)
2265 self.assertGreater(len(COMPRESS_DATA), ent.size)
2266 self.assertEqual(0x178, ent.image_pos)
2267 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2268 self.assertEqual(0x78, ent.offset)
2269
2270 ent = entries[6]
2271 self.assertEqual(2, ent.indent)
2272 self.assertEqual('u-boot-dtb', ent.name)
2273 self.assertEqual('u-boot-dtb', ent.etype)
2274 self.assertEqual(0x500, ent.image_pos)
2275 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2276 dtb_size = ent.size
2277 # Compressing this data expands it since headers are added
2278 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2279 self.assertEqual(0x400, ent.offset)
2280
2281 self.assertEqual(len(data), 0x100 + section_size)
2282 self.assertEqual(section_size, 0x400 + dtb_size)
2283
Simon Glasse1925fa2019-07-08 14:25:44 -06002284 def testFindFdtmap(self):
2285 """Test locating an FDT map in an image"""
2286 self._CheckLz4()
2287 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2288 image = control.images['image']
2289 entries = image.GetEntries()
2290 entry = entries['fdtmap']
2291 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2292
2293 def testFindFdtmapMissing(self):
2294 """Test failing to locate an FDP map"""
2295 data = self._DoReadFile('005_simple.dts')
2296 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2297
Simon Glass2d260032019-07-08 14:25:45 -06002298 def testFindImageHeader(self):
2299 """Test locating a image header"""
2300 self._CheckLz4()
Simon Glassffded752019-07-08 14:25:46 -06002301 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002302 image = control.images['image']
2303 entries = image.GetEntries()
2304 entry = entries['fdtmap']
2305 # The header should point to the FDT map
2306 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2307
2308 def testFindImageHeaderStart(self):
2309 """Test locating a image header located at the start of an image"""
Simon Glassffded752019-07-08 14:25:46 -06002310 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002311 image = control.images['image']
2312 entries = image.GetEntries()
2313 entry = entries['fdtmap']
2314 # The header should point to the FDT map
2315 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2316
2317 def testFindImageHeaderMissing(self):
2318 """Test failing to locate an image header"""
2319 data = self._DoReadFile('005_simple.dts')
2320 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2321
Simon Glassffded752019-07-08 14:25:46 -06002322 def testReadImage(self):
2323 """Test reading an image and accessing its FDT map"""
2324 self._CheckLz4()
2325 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2326 image_fname = tools.GetOutputFilename('image.bin')
2327 orig_image = control.images['image']
2328 image = Image.FromFile(image_fname)
2329 self.assertEqual(orig_image.GetEntries().keys(),
2330 image.GetEntries().keys())
2331
2332 orig_entry = orig_image.GetEntries()['fdtmap']
2333 entry = image.GetEntries()['fdtmap']
2334 self.assertEquals(orig_entry.offset, entry.offset)
2335 self.assertEquals(orig_entry.size, entry.size)
2336 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2337
2338 def testReadImageNoHeader(self):
2339 """Test accessing an image's FDT map without an image header"""
2340 self._CheckLz4()
2341 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
2342 image_fname = tools.GetOutputFilename('image.bin')
2343 image = Image.FromFile(image_fname)
2344 self.assertTrue(isinstance(image, Image))
Simon Glass10f9d002019-07-20 12:23:50 -06002345 self.assertEqual('image', image.image_name[-5:])
Simon Glassffded752019-07-08 14:25:46 -06002346
2347 def testReadImageFail(self):
2348 """Test failing to read an image image's FDT map"""
2349 self._DoReadFile('005_simple.dts')
2350 image_fname = tools.GetOutputFilename('image.bin')
2351 with self.assertRaises(ValueError) as e:
2352 image = Image.FromFile(image_fname)
2353 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glasse073d4e2019-07-08 13:18:56 -06002354
Simon Glass61f564d2019-07-08 14:25:48 -06002355 def testListCmd(self):
2356 """Test listing the files in an image using an Fdtmap"""
2357 self._CheckLz4()
2358 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2359
2360 # lz4 compression size differs depending on the version
2361 image = control.images['image']
2362 entries = image.GetEntries()
2363 section_size = entries['section'].size
2364 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2365 fdtmap_offset = entries['fdtmap'].offset
2366
2367 image_fname = tools.GetOutputFilename('image.bin')
2368 with test_util.capture_sys_output() as (stdout, stderr):
2369 self._DoBinman('ls', '-i', image_fname)
2370 lines = stdout.getvalue().splitlines()
2371 expected = [
2372'Name Image-pos Size Entry-type Offset Uncomp-size',
2373'----------------------------------------------------------------------',
2374'main-section 0 c00 section 0',
2375' u-boot 0 4 u-boot 0',
2376' section 100 %x section 100' % section_size,
2377' cbfs 100 400 cbfs 0',
2378' u-boot 138 4 u-boot 38',
2379' u-boot-dtb 180 10f u-boot-dtb 80 3c9',
2380' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glass1411ac82019-07-20 12:23:44 -06002381' fdtmap %x 3b4 fdtmap %x' %
Simon Glass61f564d2019-07-08 14:25:48 -06002382 (fdtmap_offset, fdtmap_offset),
2383' image-header bf8 8 image-header bf8',
2384 ]
2385 self.assertEqual(expected, lines)
2386
2387 def testListCmdFail(self):
2388 """Test failing to list an image"""
2389 self._DoReadFile('005_simple.dts')
2390 image_fname = tools.GetOutputFilename('image.bin')
2391 with self.assertRaises(ValueError) as e:
2392 self._DoBinman('ls', '-i', image_fname)
2393 self.assertIn("Cannot find FDT map in image", str(e.exception))
2394
2395 def _RunListCmd(self, paths, expected):
2396 """List out entries and check the result
2397
2398 Args:
2399 paths: List of paths to pass to the list command
2400 expected: Expected list of filenames to be returned, in order
2401 """
2402 self._CheckLz4()
2403 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2404 image_fname = tools.GetOutputFilename('image.bin')
2405 image = Image.FromFile(image_fname)
2406 lines = image.GetListEntries(paths)[1]
2407 files = [line[0].strip() for line in lines[1:]]
2408 self.assertEqual(expected, files)
2409
2410 def testListCmdSection(self):
2411 """Test listing the files in a section"""
2412 self._RunListCmd(['section'],
2413 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2414
2415 def testListCmdFile(self):
2416 """Test listing a particular file"""
2417 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2418
2419 def testListCmdWildcard(self):
2420 """Test listing a wildcarded file"""
2421 self._RunListCmd(['*boot*'],
2422 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2423
2424 def testListCmdWildcardMulti(self):
2425 """Test listing a wildcarded file"""
2426 self._RunListCmd(['*cb*', '*head*'],
2427 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2428
2429 def testListCmdEmpty(self):
2430 """Test listing a wildcarded file"""
2431 self._RunListCmd(['nothing'], [])
2432
2433 def testListCmdPath(self):
2434 """Test listing the files in a sub-entry of a section"""
2435 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2436
Simon Glassf667e452019-07-08 14:25:50 -06002437 def _RunExtractCmd(self, entry_name, decomp=True):
2438 """Extract an entry from an image
2439
2440 Args:
2441 entry_name: Entry name to extract
2442 decomp: True to decompress the data if compressed, False to leave
2443 it in its raw uncompressed format
2444
2445 Returns:
2446 data from entry
2447 """
2448 self._CheckLz4()
2449 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2450 image_fname = tools.GetOutputFilename('image.bin')
2451 return control.ReadEntry(image_fname, entry_name, decomp)
2452
2453 def testExtractSimple(self):
2454 """Test extracting a single file"""
2455 data = self._RunExtractCmd('u-boot')
2456 self.assertEqual(U_BOOT_DATA, data)
2457
Simon Glass71ce0ba2019-07-08 14:25:52 -06002458 def testExtractSection(self):
2459 """Test extracting the files in a section"""
2460 data = self._RunExtractCmd('section')
2461 cbfs_data = data[:0x400]
2462 cbfs = cbfs_util.CbfsReader(cbfs_data)
2463 self.assertEqual(['u-boot', 'u-boot-dtb', ''], cbfs.files.keys())
2464 dtb_data = data[0x400:]
2465 dtb = self._decompress(dtb_data)
2466 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2467
2468 def testExtractCompressed(self):
2469 """Test extracting compressed data"""
2470 data = self._RunExtractCmd('section/u-boot-dtb')
2471 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2472
2473 def testExtractRaw(self):
2474 """Test extracting compressed data without decompressing it"""
2475 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2476 dtb = self._decompress(data)
2477 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2478
2479 def testExtractCbfs(self):
2480 """Test extracting CBFS data"""
2481 data = self._RunExtractCmd('section/cbfs/u-boot')
2482 self.assertEqual(U_BOOT_DATA, data)
2483
2484 def testExtractCbfsCompressed(self):
2485 """Test extracting CBFS compressed data"""
2486 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2487 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2488
2489 def testExtractCbfsRaw(self):
2490 """Test extracting CBFS compressed data without decompressing it"""
2491 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Simon Glasseb0f4a42019-07-20 12:24:06 -06002492 dtb = tools.Decompress(data, 'lzma', with_header=False)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002493 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2494
Simon Glassf667e452019-07-08 14:25:50 -06002495 def testExtractBadEntry(self):
2496 """Test extracting a bad section path"""
2497 with self.assertRaises(ValueError) as e:
2498 self._RunExtractCmd('section/does-not-exist')
2499 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2500 str(e.exception))
2501
2502 def testExtractMissingFile(self):
2503 """Test extracting file that does not exist"""
2504 with self.assertRaises(IOError) as e:
2505 control.ReadEntry('missing-file', 'name')
2506
2507 def testExtractBadFile(self):
2508 """Test extracting an invalid file"""
2509 fname = os.path.join(self._indir, 'badfile')
2510 tools.WriteFile(fname, b'')
2511 with self.assertRaises(ValueError) as e:
2512 control.ReadEntry(fname, 'name')
2513
Simon Glass71ce0ba2019-07-08 14:25:52 -06002514 def testExtractCmd(self):
2515 """Test extracting a file fron an image on the command line"""
2516 self._CheckLz4()
2517 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2518 image_fname = tools.GetOutputFilename('image.bin')
2519 fname = os.path.join(self._indir, 'output.extact')
2520 with test_util.capture_sys_output() as (stdout, stderr):
2521 self._DoBinman('extract', '-i', image_fname, 'u-boot', '-f', fname)
2522 data = tools.ReadFile(fname)
2523 self.assertEqual(U_BOOT_DATA, data)
2524
2525 def testExtractOneEntry(self):
2526 """Test extracting a single entry fron an image """
2527 self._CheckLz4()
2528 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2529 image_fname = tools.GetOutputFilename('image.bin')
2530 fname = os.path.join(self._indir, 'output.extact')
2531 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
2532 data = tools.ReadFile(fname)
2533 self.assertEqual(U_BOOT_DATA, data)
2534
2535 def _CheckExtractOutput(self, decomp):
2536 """Helper to test file output with and without decompression
2537
2538 Args:
2539 decomp: True to decompress entry data, False to output it raw
2540 """
2541 def _CheckPresent(entry_path, expect_data, expect_size=None):
2542 """Check and remove expected file
2543
2544 This checks the data/size of a file and removes the file both from
2545 the outfiles set and from the output directory. Once all files are
2546 processed, both the set and directory should be empty.
2547
2548 Args:
2549 entry_path: Entry path
2550 expect_data: Data to expect in file, or None to skip check
2551 expect_size: Size of data to expect in file, or None to skip
2552 """
2553 path = os.path.join(outdir, entry_path)
2554 data = tools.ReadFile(path)
2555 os.remove(path)
2556 if expect_data:
2557 self.assertEqual(expect_data, data)
2558 elif expect_size:
2559 self.assertEqual(expect_size, len(data))
2560 outfiles.remove(path)
2561
2562 def _CheckDirPresent(name):
2563 """Remove expected directory
2564
2565 This gives an error if the directory does not exist as expected
2566
2567 Args:
2568 name: Name of directory to remove
2569 """
2570 path = os.path.join(outdir, name)
2571 os.rmdir(path)
2572
2573 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2574 image_fname = tools.GetOutputFilename('image.bin')
2575 outdir = os.path.join(self._indir, 'extract')
2576 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2577
2578 # Create a set of all file that were output (should be 9)
2579 outfiles = set()
2580 for root, dirs, files in os.walk(outdir):
2581 outfiles |= set([os.path.join(root, fname) for fname in files])
2582 self.assertEqual(9, len(outfiles))
2583 self.assertEqual(9, len(einfos))
2584
2585 image = control.images['image']
2586 entries = image.GetEntries()
2587
2588 # Check the 9 files in various ways
2589 section = entries['section']
2590 section_entries = section.GetEntries()
2591 cbfs_entries = section_entries['cbfs'].GetEntries()
2592 _CheckPresent('u-boot', U_BOOT_DATA)
2593 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
2594 dtb_len = EXTRACT_DTB_SIZE
2595 if not decomp:
2596 dtb_len = cbfs_entries['u-boot-dtb'].size
2597 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
2598 if not decomp:
2599 dtb_len = section_entries['u-boot-dtb'].size
2600 _CheckPresent('section/u-boot-dtb', None, dtb_len)
2601
2602 fdtmap = entries['fdtmap']
2603 _CheckPresent('fdtmap', fdtmap.data)
2604 hdr = entries['image-header']
2605 _CheckPresent('image-header', hdr.data)
2606
2607 _CheckPresent('section/root', section.data)
2608 cbfs = section_entries['cbfs']
2609 _CheckPresent('section/cbfs/root', cbfs.data)
2610 data = tools.ReadFile(image_fname)
2611 _CheckPresent('root', data)
2612
2613 # There should be no files left. Remove all the directories to check.
2614 # If there are any files/dirs remaining, one of these checks will fail.
2615 self.assertEqual(0, len(outfiles))
2616 _CheckDirPresent('section/cbfs')
2617 _CheckDirPresent('section')
2618 _CheckDirPresent('')
2619 self.assertFalse(os.path.exists(outdir))
2620
2621 def testExtractAllEntries(self):
2622 """Test extracting all entries"""
2623 self._CheckLz4()
2624 self._CheckExtractOutput(decomp=True)
2625
2626 def testExtractAllEntriesRaw(self):
2627 """Test extracting all entries without decompressing them"""
2628 self._CheckLz4()
2629 self._CheckExtractOutput(decomp=False)
2630
2631 def testExtractSelectedEntries(self):
2632 """Test extracting some entries"""
2633 self._CheckLz4()
2634 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2635 image_fname = tools.GetOutputFilename('image.bin')
2636 outdir = os.path.join(self._indir, 'extract')
2637 einfos = control.ExtractEntries(image_fname, None, outdir,
2638 ['*cb*', '*head*'])
2639
2640 # File output is tested by testExtractAllEntries(), so just check that
2641 # the expected entries are selected
2642 names = [einfo.name for einfo in einfos]
2643 self.assertEqual(names,
2644 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2645
2646 def testExtractNoEntryPaths(self):
2647 """Test extracting some entries"""
2648 self._CheckLz4()
2649 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2650 image_fname = tools.GetOutputFilename('image.bin')
2651 with self.assertRaises(ValueError) as e:
2652 control.ExtractEntries(image_fname, 'fname', None, [])
2653 self.assertIn('Must specify an entry path to write with -o',
2654 str(e.exception))
2655
2656 def testExtractTooManyEntryPaths(self):
2657 """Test extracting some entries"""
2658 self._CheckLz4()
2659 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2660 image_fname = tools.GetOutputFilename('image.bin')
2661 with self.assertRaises(ValueError) as e:
2662 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
2663 self.assertIn('Must specify exactly one entry path to write with -o',
2664 str(e.exception))
2665
Simon Glasse2705fa2019-07-08 14:25:53 -06002666 def testPackAlignSection(self):
2667 """Test that sections can have alignment"""
2668 self._DoReadFile('131_pack_align_section.dts')
2669
2670 self.assertIn('image', control.images)
2671 image = control.images['image']
2672 entries = image.GetEntries()
2673 self.assertEqual(3, len(entries))
2674
2675 # First u-boot
2676 self.assertIn('u-boot', entries)
2677 entry = entries['u-boot']
2678 self.assertEqual(0, entry.offset)
2679 self.assertEqual(0, entry.image_pos)
2680 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2681 self.assertEqual(len(U_BOOT_DATA), entry.size)
2682
2683 # Section0
2684 self.assertIn('section0', entries)
2685 section0 = entries['section0']
2686 self.assertEqual(0x10, section0.offset)
2687 self.assertEqual(0x10, section0.image_pos)
2688 self.assertEqual(len(U_BOOT_DATA), section0.size)
2689
2690 # Second u-boot
2691 section_entries = section0.GetEntries()
2692 self.assertIn('u-boot', section_entries)
2693 entry = section_entries['u-boot']
2694 self.assertEqual(0, entry.offset)
2695 self.assertEqual(0x10, entry.image_pos)
2696 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2697 self.assertEqual(len(U_BOOT_DATA), entry.size)
2698
2699 # Section1
2700 self.assertIn('section1', entries)
2701 section1 = entries['section1']
2702 self.assertEqual(0x14, section1.offset)
2703 self.assertEqual(0x14, section1.image_pos)
2704 self.assertEqual(0x20, section1.size)
2705
2706 # Second u-boot
2707 section_entries = section1.GetEntries()
2708 self.assertIn('u-boot', section_entries)
2709 entry = section_entries['u-boot']
2710 self.assertEqual(0, entry.offset)
2711 self.assertEqual(0x14, entry.image_pos)
2712 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2713 self.assertEqual(len(U_BOOT_DATA), entry.size)
2714
2715 # Section2
2716 self.assertIn('section2', section_entries)
2717 section2 = section_entries['section2']
2718 self.assertEqual(0x4, section2.offset)
2719 self.assertEqual(0x18, section2.image_pos)
2720 self.assertEqual(4, section2.size)
2721
2722 # Third u-boot
2723 section_entries = section2.GetEntries()
2724 self.assertIn('u-boot', section_entries)
2725 entry = section_entries['u-boot']
2726 self.assertEqual(0, entry.offset)
2727 self.assertEqual(0x18, entry.image_pos)
2728 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2729 self.assertEqual(len(U_BOOT_DATA), entry.size)
2730
Simon Glass51014aa2019-07-20 12:23:56 -06002731 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
2732 dts='132_replace.dts'):
Simon Glass10f9d002019-07-20 12:23:50 -06002733 """Replace an entry in an image
2734
2735 This writes the entry data to update it, then opens the updated file and
2736 returns the value that it now finds there.
2737
2738 Args:
2739 entry_name: Entry name to replace
2740 data: Data to replace it with
2741 decomp: True to compress the data if needed, False if data is
2742 already compressed so should be used as is
Simon Glass51014aa2019-07-20 12:23:56 -06002743 allow_resize: True to allow entries to change size, False to raise
2744 an exception
Simon Glass10f9d002019-07-20 12:23:50 -06002745
2746 Returns:
2747 Tuple:
2748 data from entry
2749 data from fdtmap (excluding header)
Simon Glass51014aa2019-07-20 12:23:56 -06002750 Image object that was modified
Simon Glass10f9d002019-07-20 12:23:50 -06002751 """
Simon Glass51014aa2019-07-20 12:23:56 -06002752 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass10f9d002019-07-20 12:23:50 -06002753 update_dtb=True)[1]
2754
2755 self.assertIn('image', control.images)
2756 image = control.images['image']
2757 entries = image.GetEntries()
2758 orig_dtb_data = entries['u-boot-dtb'].data
2759 orig_fdtmap_data = entries['fdtmap'].data
2760
2761 image_fname = tools.GetOutputFilename('image.bin')
2762 updated_fname = tools.GetOutputFilename('image-updated.bin')
2763 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
Simon Glass51014aa2019-07-20 12:23:56 -06002764 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
2765 allow_resize)
Simon Glass10f9d002019-07-20 12:23:50 -06002766 data = control.ReadEntry(updated_fname, entry_name, decomp)
2767
Simon Glass51014aa2019-07-20 12:23:56 -06002768 # The DT data should not change unless resized:
2769 if not allow_resize:
2770 new_dtb_data = entries['u-boot-dtb'].data
2771 self.assertEqual(new_dtb_data, orig_dtb_data)
2772 new_fdtmap_data = entries['fdtmap'].data
2773 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass10f9d002019-07-20 12:23:50 -06002774
Simon Glass51014aa2019-07-20 12:23:56 -06002775 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass10f9d002019-07-20 12:23:50 -06002776
2777 def testReplaceSimple(self):
2778 """Test replacing a single file"""
2779 expected = b'x' * len(U_BOOT_DATA)
Simon Glass51014aa2019-07-20 12:23:56 -06002780 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
2781 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06002782 self.assertEqual(expected, data)
2783
2784 # Test that the state looks right. There should be an FDT for the fdtmap
2785 # that we jsut read back in, and it should match what we find in the
2786 # 'control' tables. Checking for an FDT that does not exist should
2787 # return None.
2788 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glass51014aa2019-07-20 12:23:56 -06002789 self.assertIsNotNone(path)
Simon Glass10f9d002019-07-20 12:23:50 -06002790 self.assertEqual(expected_fdtmap, fdtmap)
2791
2792 dtb = state.GetFdtForEtype('fdtmap')
2793 self.assertEqual(dtb.GetContents(), fdtmap)
2794
2795 missing_path, missing_fdtmap = state.GetFdtContents('missing')
2796 self.assertIsNone(missing_path)
2797 self.assertIsNone(missing_fdtmap)
2798
2799 missing_dtb = state.GetFdtForEtype('missing')
2800 self.assertIsNone(missing_dtb)
2801
2802 self.assertEqual('/binman', state.fdt_path_prefix)
2803
2804 def testReplaceResizeFail(self):
2805 """Test replacing a file by something larger"""
2806 expected = U_BOOT_DATA + b'x'
2807 with self.assertRaises(ValueError) as e:
Simon Glass51014aa2019-07-20 12:23:56 -06002808 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
2809 dts='139_replace_repack.dts')
Simon Glass10f9d002019-07-20 12:23:50 -06002810 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
2811 str(e.exception))
2812
2813 def testReplaceMulti(self):
2814 """Test replacing entry data where multiple images are generated"""
2815 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
2816 update_dtb=True)[0]
2817 expected = b'x' * len(U_BOOT_DATA)
2818 updated_fname = tools.GetOutputFilename('image-updated.bin')
2819 tools.WriteFile(updated_fname, data)
2820 entry_name = 'u-boot'
Simon Glass51014aa2019-07-20 12:23:56 -06002821 control.WriteEntry(updated_fname, entry_name, expected,
2822 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06002823 data = control.ReadEntry(updated_fname, entry_name)
2824 self.assertEqual(expected, data)
2825
2826 # Check the state looks right.
2827 self.assertEqual('/binman/image', state.fdt_path_prefix)
2828
2829 # Now check we can write the first image
2830 image_fname = tools.GetOutputFilename('first-image.bin')
2831 updated_fname = tools.GetOutputFilename('first-updated.bin')
2832 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
2833 entry_name = 'u-boot'
Simon Glass51014aa2019-07-20 12:23:56 -06002834 control.WriteEntry(updated_fname, entry_name, expected,
2835 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06002836 data = control.ReadEntry(updated_fname, entry_name)
2837 self.assertEqual(expected, data)
2838
2839 # Check the state looks right.
2840 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass8beb11e2019-07-08 14:25:47 -06002841
Simon Glass12bb1a92019-07-20 12:23:51 -06002842 def testUpdateFdtAllRepack(self):
2843 """Test that all device trees are updated with offset/size info"""
2844 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
2845 SECTION_SIZE = 0x300
2846 DTB_SIZE = 602
2847 FDTMAP_SIZE = 608
2848 base_expected = {
2849 'offset': 0,
2850 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
2851 'image-pos': 0,
2852 'section:offset': 0,
2853 'section:size': SECTION_SIZE,
2854 'section:image-pos': 0,
2855 'section/u-boot-dtb:offset': 4,
2856 'section/u-boot-dtb:size': 636,
2857 'section/u-boot-dtb:image-pos': 4,
2858 'u-boot-spl-dtb:offset': SECTION_SIZE,
2859 'u-boot-spl-dtb:size': DTB_SIZE,
2860 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
2861 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
2862 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
2863 'u-boot-tpl-dtb:size': DTB_SIZE,
2864 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
2865 'fdtmap:size': FDTMAP_SIZE,
2866 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
2867 }
2868 main_expected = {
2869 'section:orig-size': SECTION_SIZE,
2870 'section/u-boot-dtb:orig-offset': 4,
2871 }
2872
2873 # We expect three device-tree files in the output, with the first one
2874 # within a fixed-size section.
2875 # Read them in sequence. We look for an 'spl' property in the SPL tree,
2876 # and 'tpl' in the TPL tree, to make sure they are distinct from the
2877 # main U-Boot tree. All three should have the same positions and offset
2878 # except that the main tree should include the main_expected properties
2879 start = 4
2880 for item in ['', 'spl', 'tpl', None]:
2881 if item is None:
2882 start += 16 # Move past fdtmap header
2883 dtb = fdt.Fdt.FromData(data[start:])
2884 dtb.Scan()
2885 props = self._GetPropTree(dtb,
2886 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
2887 prefix='/' if item is None else '/binman/')
2888 expected = dict(base_expected)
2889 if item:
2890 expected[item] = 0
2891 else:
2892 # Main DTB and fdtdec should include the 'orig-' properties
2893 expected.update(main_expected)
2894 # Helpful for debugging:
2895 #for prop in sorted(props):
2896 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
2897 self.assertEqual(expected, props)
2898 if item == '':
2899 start = SECTION_SIZE
2900 else:
2901 start += dtb._fdt_obj.totalsize()
2902
Simon Glasseba1f0c2019-07-20 12:23:55 -06002903 def testFdtmapHeaderMiddle(self):
2904 """Test an FDT map in the middle of an image when it should be at end"""
2905 with self.assertRaises(ValueError) as e:
2906 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
2907 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
2908 str(e.exception))
2909
2910 def testFdtmapHeaderStartBad(self):
2911 """Test an FDT map in middle of an image when it should be at start"""
2912 with self.assertRaises(ValueError) as e:
2913 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
2914 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
2915 str(e.exception))
2916
2917 def testFdtmapHeaderEndBad(self):
2918 """Test an FDT map at the start of an image when it should be at end"""
2919 with self.assertRaises(ValueError) as e:
2920 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
2921 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
2922 str(e.exception))
2923
2924 def testFdtmapHeaderNoSize(self):
2925 """Test an image header at the end of an image with undefined size"""
2926 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
2927
Simon Glass51014aa2019-07-20 12:23:56 -06002928 def testReplaceResize(self):
2929 """Test replacing a single file in an entry with a larger file"""
2930 expected = U_BOOT_DATA + b'x'
2931 data, _, image = self._RunReplaceCmd('u-boot', expected,
2932 dts='139_replace_repack.dts')
2933 self.assertEqual(expected, data)
2934
2935 entries = image.GetEntries()
2936 dtb_data = entries['u-boot-dtb'].data
2937 dtb = fdt.Fdt.FromData(dtb_data)
2938 dtb.Scan()
2939
2940 # The u-boot section should now be larger in the dtb
2941 node = dtb.GetNode('/binman/u-boot')
2942 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
2943
2944 # Same for the fdtmap
2945 fdata = entries['fdtmap'].data
2946 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
2947 fdtb.Scan()
2948 fnode = fdtb.GetNode('/u-boot')
2949 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
2950
2951 def testReplaceResizeNoRepack(self):
2952 """Test replacing an entry with a larger file when not allowed"""
2953 expected = U_BOOT_DATA + b'x'
2954 with self.assertRaises(ValueError) as e:
2955 self._RunReplaceCmd('u-boot', expected)
2956 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
2957 str(e.exception))
2958
Simon Glass61ec04f2019-07-20 12:23:58 -06002959 def testEntryShrink(self):
2960 """Test contracting an entry after it is packed"""
2961 try:
2962 state.SetAllowEntryContraction(True)
2963 data = self._DoReadFileDtb('140_entry_shrink.dts',
2964 update_dtb=True)[0]
2965 finally:
2966 state.SetAllowEntryContraction(False)
2967 self.assertEqual(b'a', data[:1])
2968 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
2969 self.assertEqual(b'a', data[-1:])
2970
2971 def testEntryShrinkFail(self):
2972 """Test not being allowed to contract an entry after it is packed"""
2973 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
2974
2975 # In this case there is a spare byte at the end of the data. The size of
2976 # the contents is only 1 byte but we still have the size before it
2977 # shrunk.
2978 self.assertEqual(b'a\0', data[:2])
2979 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
2980 self.assertEqual(b'a\0', data[-2:])
2981
Simon Glass27145fd2019-07-20 12:24:01 -06002982 def testDescriptorOffset(self):
2983 """Test that the Intel descriptor is always placed at at the start"""
2984 data = self._DoReadFileDtb('141_descriptor_offset.dts')
2985 image = control.images['image']
2986 entries = image.GetEntries()
2987 desc = entries['intel-descriptor']
2988 self.assertEqual(0xff800000, desc.offset);
2989 self.assertEqual(0xff800000, desc.image_pos);
2990
Simon Glasseb0f4a42019-07-20 12:24:06 -06002991 def testReplaceCbfs(self):
2992 """Test replacing a single file in CBFS without changing the size"""
2993 self._CheckLz4()
2994 expected = b'x' * len(U_BOOT_DATA)
2995 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
2996 updated_fname = tools.GetOutputFilename('image-updated.bin')
2997 tools.WriteFile(updated_fname, data)
2998 entry_name = 'section/cbfs/u-boot'
2999 control.WriteEntry(updated_fname, entry_name, expected,
3000 allow_resize=True)
3001 data = control.ReadEntry(updated_fname, entry_name)
3002 self.assertEqual(expected, data)
3003
3004 def testReplaceResizeCbfs(self):
3005 """Test replacing a single file in CBFS with one of a different size"""
3006 self._CheckLz4()
3007 expected = U_BOOT_DATA + b'x'
3008 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3009 updated_fname = tools.GetOutputFilename('image-updated.bin')
3010 tools.WriteFile(updated_fname, data)
3011 entry_name = 'section/cbfs/u-boot'
3012 control.WriteEntry(updated_fname, entry_name, expected,
3013 allow_resize=True)
3014 data = control.ReadEntry(updated_fname, entry_name)
3015 self.assertEqual(expected, data)
3016
Simon Glass12bb1a92019-07-20 12:23:51 -06003017
Simon Glass9fc60b42017-11-12 21:52:22 -07003018if __name__ == "__main__":
3019 unittest.main()