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