blob: 91225459162aa19a645dc8a7a609782b7e132782 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001# SPDX-License-Identifier: GPL-2.0+
Simon Glass4f443042016-11-25 20:15:52 -07002# Copyright (c) 2016 Google, Inc
3# Written by Simon Glass <sjg@chromium.org>
4#
Simon Glass4f443042016-11-25 20:15:52 -07005# To run a single test, change to this directory, and:
6#
7# python -m unittest func_test.TestFunctional.testHelp
8
Simon Glassfdc34362020-07-09 18:39:45 -06009import collections
Simon Glass16287932020-04-17 18:09:03 -060010import gzip
Simon Glasse0e5df92018-09-14 04:57:31 -060011import hashlib
Simon Glass4f443042016-11-25 20:15:52 -070012from optparse import OptionParser
13import os
Simon Glassfdc34362020-07-09 18:39:45 -060014import re
Simon Glass4f443042016-11-25 20:15:52 -070015import shutil
16import struct
17import sys
18import tempfile
19import unittest
20
Simon Glass16287932020-04-17 18:09:03 -060021from binman import cbfs_util
22from binman import cmdline
23from binman import control
24from binman import elf
25from binman import elf_test
26from binman import fmap_util
Simon Glass16287932020-04-17 18:09:03 -060027from binman import state
28from dtoc import fdt
29from dtoc import fdt_util
30from binman.etype import fdtmap
31from binman.etype import image_header
Simon Glass07237982020-08-05 13:27:47 -060032from binman.image import Image
Simon Glassbf776672020-04-17 18:09:04 -060033from patman import command
34from patman import test_util
35from patman import tools
36from patman import tout
Simon Glass4f443042016-11-25 20:15:52 -070037
38# Contents of test files, corresponding to different entry types
Simon Glassc6c10e72019-05-17 22:00:46 -060039U_BOOT_DATA = b'1234'
40U_BOOT_IMG_DATA = b'img'
Simon Glasseb0086f2019-08-24 07:23:04 -060041U_BOOT_SPL_DATA = b'56780123456789abcdefghi'
42U_BOOT_TPL_DATA = b'tpl9876543210fedcbazyw'
Simon Glassc6c10e72019-05-17 22:00:46 -060043BLOB_DATA = b'89'
44ME_DATA = b'0abcd'
45VGA_DATA = b'vga'
46U_BOOT_DTB_DATA = b'udtb'
47U_BOOT_SPL_DTB_DATA = b'spldtb'
48U_BOOT_TPL_DTB_DATA = b'tpldtb'
49X86_START16_DATA = b'start16'
50X86_START16_SPL_DATA = b'start16spl'
51X86_START16_TPL_DATA = b'start16tpl'
Simon Glass2250ee62019-08-24 07:22:48 -060052X86_RESET16_DATA = b'reset16'
53X86_RESET16_SPL_DATA = b'reset16spl'
54X86_RESET16_TPL_DATA = b'reset16tpl'
Simon Glassc6c10e72019-05-17 22:00:46 -060055PPC_MPC85XX_BR_DATA = b'ppcmpc85xxbr'
56U_BOOT_NODTB_DATA = b'nodtb with microcode pointer somewhere in here'
57U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here'
58U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here'
59FSP_DATA = b'fsp'
60CMC_DATA = b'cmc'
61VBT_DATA = b'vbt'
62MRC_DATA = b'mrc'
Simon Glassbb748372018-07-17 13:25:33 -060063TEXT_DATA = 'text'
64TEXT_DATA2 = 'text2'
65TEXT_DATA3 = 'text3'
Simon Glassc6c10e72019-05-17 22:00:46 -060066CROS_EC_RW_DATA = b'ecrw'
67GBB_DATA = b'gbbd'
68BMPBLK_DATA = b'bmp'
69VBLOCK_DATA = b'vblk'
70FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
71 b"sorry you're alive\n")
Simon Glassff5c7e32019-07-08 13:18:42 -060072COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
Simon Glassc6c10e72019-05-17 22:00:46 -060073REFCODE_DATA = b'refcode'
Simon Glassea0fff92019-08-24 07:23:07 -060074FSP_M_DATA = b'fsp_m'
Simon Glassbc6a88f2019-10-20 21:31:35 -060075FSP_S_DATA = b'fsp_s'
Simon Glass998d1482019-10-20 21:31:36 -060076FSP_T_DATA = b'fsp_t'
Simon Glassdc2f81a2020-09-01 05:13:58 -060077ATF_BL31_DATA = b'bl31'
Simon Glass6cf99532020-09-01 05:13:59 -060078TEST_FDT1_DATA = b'fdt1'
79TEST_FDT2_DATA = b'test-fdt2'
80
81# Subdirectory of the input dir to use to put test FDTs
82TEST_FDT_SUBDIR = 'fdts'
Simon Glassec127af2018-07-17 13:25:39 -060083
Simon Glass6ccbfcd2019-07-20 12:23:47 -060084# The expected size for the device tree in some tests
Simon Glassf667e452019-07-08 14:25:50 -060085EXTRACT_DTB_SIZE = 0x3c9
86
Simon Glass6ccbfcd2019-07-20 12:23:47 -060087# Properties expected to be in the device tree when update_dtb is used
88BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
89
Simon Glass12bb1a92019-07-20 12:23:51 -060090# Extra properties expected to be in the device tree when allow-repack is used
91REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
92
Simon Glass4f443042016-11-25 20:15:52 -070093
94class TestFunctional(unittest.TestCase):
95 """Functional tests for binman
96
97 Most of these use a sample .dts file to build an image and then check
98 that it looks correct. The sample files are in the test/ subdirectory
99 and are numbered.
100
101 For each entry type a very small test file is created using fixed
102 string contents. This makes it easy to test that things look right, and
103 debug problems.
104
105 In some cases a 'real' file must be used - these are also supplied in
106 the test/ diurectory.
107 """
108 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600109 def setUpClass(cls):
Simon Glass4d5994f2017-11-12 21:52:20 -0700110 global entry
Simon Glass16287932020-04-17 18:09:03 -0600111 from binman import entry
Simon Glass4d5994f2017-11-12 21:52:20 -0700112
Simon Glass4f443042016-11-25 20:15:52 -0700113 # Handle the case where argv[0] is 'python'
Simon Glassb986b3b2019-08-24 07:22:43 -0600114 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
115 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
Simon Glass4f443042016-11-25 20:15:52 -0700116
117 # Create a temporary directory for input files
Simon Glassb986b3b2019-08-24 07:22:43 -0600118 cls._indir = tempfile.mkdtemp(prefix='binmant.')
Simon Glass4f443042016-11-25 20:15:52 -0700119
120 # Create some test files
121 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
122 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
123 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glassb8ef5b62018-07-17 13:25:48 -0600124 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700125 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -0700126 TestFunctional._MakeInputFile('me.bin', ME_DATA)
127 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glassb986b3b2019-08-24 07:22:43 -0600128 cls._ResetDtbs()
Simon Glass2250ee62019-08-24 07:22:48 -0600129
Jagdish Gediya9d368f32018-09-03 21:35:08 +0530130 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glass2250ee62019-08-24 07:22:48 -0600131
Simon Glass5e239182019-08-24 07:22:49 -0600132 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
133 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
Simon Glass87722132017-11-12 21:52:26 -0700134 X86_START16_SPL_DATA)
Simon Glass5e239182019-08-24 07:22:49 -0600135 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
Simon Glass35b384c2018-09-14 04:57:10 -0600136 X86_START16_TPL_DATA)
Simon Glass2250ee62019-08-24 07:22:48 -0600137
138 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
139 X86_RESET16_DATA)
140 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
141 X86_RESET16_SPL_DATA)
142 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
143 X86_RESET16_TPL_DATA)
144
Simon Glass4f443042016-11-25 20:15:52 -0700145 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass6b187df2017-11-12 21:52:27 -0700146 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
147 U_BOOT_SPL_NODTB_DATA)
Simon Glassf0253632018-09-14 04:57:32 -0600148 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
149 U_BOOT_TPL_NODTB_DATA)
Simon Glassda229092016-11-25 20:15:56 -0700150 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
151 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Meng59ea8c22017-08-15 22:41:54 -0700152 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassca4f4ff2017-11-12 21:52:28 -0700153 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassec127af2018-07-17 13:25:39 -0600154 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glass0ef87aa2018-07-17 13:25:44 -0600155 TestFunctional._MakeInputDir('devkeys')
156 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass3ae192c2018-10-01 12:22:31 -0600157 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glassea0fff92019-08-24 07:23:07 -0600158 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
Simon Glassbc6a88f2019-10-20 21:31:35 -0600159 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
Simon Glass998d1482019-10-20 21:31:36 -0600160 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700161
Simon Glass53e22bf2019-08-24 07:22:53 -0600162 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
163 elf_test.BuildElfTestFiles(cls._elf_testdir)
164
Simon Glasse0ff8552016-11-25 20:15:53 -0700165 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glassf514d8f2019-08-24 07:22:54 -0600166 TestFunctional._MakeInputFile('u-boot',
167 tools.ReadFile(cls.ElfTestFile('u_boot_ucode_ptr')))
Simon Glasse0ff8552016-11-25 20:15:53 -0700168
169 # Intel flash descriptor file
Simon Glass0ba4b3d2020-07-09 18:39:41 -0600170 cls._SetupDescriptor()
Simon Glasse0ff8552016-11-25 20:15:53 -0700171
Simon Glassb986b3b2019-08-24 07:22:43 -0600172 shutil.copytree(cls.TestFile('files'),
173 os.path.join(cls._indir, 'files'))
Simon Glass0a98b282018-09-14 04:57:28 -0600174
Simon Glass83d73c22018-09-14 04:57:26 -0600175 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
Simon Glassdc2f81a2020-09-01 05:13:58 -0600176 TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
Simon Glass83d73c22018-09-14 04:57:26 -0600177
Simon Glass6cf99532020-09-01 05:13:59 -0600178 # Add a few .dtb files for testing
179 TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR,
180 TEST_FDT1_DATA)
181 TestFunctional._MakeInputFile('%s/test-fdt2.dtb' % TEST_FDT_SUBDIR,
182 TEST_FDT2_DATA)
183
Simon Glassac62fba2019-07-08 13:18:53 -0600184 # Travis-CI may have an old lz4
Simon Glassb986b3b2019-08-24 07:22:43 -0600185 cls.have_lz4 = True
Simon Glassac62fba2019-07-08 13:18:53 -0600186 try:
187 tools.Run('lz4', '--no-frame-crc', '-c',
Simon Glass3b3e3c02019-10-31 07:42:50 -0600188 os.path.join(cls._indir, 'u-boot.bin'), binary=True)
Simon Glassac62fba2019-07-08 13:18:53 -0600189 except:
Simon Glassb986b3b2019-08-24 07:22:43 -0600190 cls.have_lz4 = False
Simon Glassac62fba2019-07-08 13:18:53 -0600191
Simon Glass4f443042016-11-25 20:15:52 -0700192 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600193 def tearDownClass(cls):
Simon Glass4f443042016-11-25 20:15:52 -0700194 """Remove the temporary input directory and its contents"""
Simon Glassb986b3b2019-08-24 07:22:43 -0600195 if cls.preserve_indir:
196 print('Preserving input dir: %s' % cls._indir)
Simon Glassd5164a72019-07-08 13:18:49 -0600197 else:
Simon Glassb986b3b2019-08-24 07:22:43 -0600198 if cls._indir:
199 shutil.rmtree(cls._indir)
200 cls._indir = None
Simon Glass4f443042016-11-25 20:15:52 -0700201
Simon Glassd5164a72019-07-08 13:18:49 -0600202 @classmethod
Simon Glass8acce602019-07-08 13:18:50 -0600203 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
Simon Glass53cd5d92019-07-08 14:25:29 -0600204 toolpath=None, verbosity=None):
Simon Glassd5164a72019-07-08 13:18:49 -0600205 """Accept arguments controlling test execution
206
207 Args:
208 preserve_indir: Preserve the shared input directory used by all
209 tests in this class.
210 preserve_outdir: Preserve the output directories used by tests. Each
211 test has its own, so this is normally only useful when running a
212 single test.
Simon Glass8acce602019-07-08 13:18:50 -0600213 toolpath: ist of paths to use for tools
Simon Glassd5164a72019-07-08 13:18:49 -0600214 """
215 cls.preserve_indir = preserve_indir
216 cls.preserve_outdirs = preserve_outdirs
Simon Glass8acce602019-07-08 13:18:50 -0600217 cls.toolpath = toolpath
Simon Glass53cd5d92019-07-08 14:25:29 -0600218 cls.verbosity = verbosity
Simon Glassd5164a72019-07-08 13:18:49 -0600219
Simon Glassac62fba2019-07-08 13:18:53 -0600220 def _CheckLz4(self):
221 if not self.have_lz4:
222 self.skipTest('lz4 --no-frame-crc not available')
223
Simon Glassbf574f12019-07-20 12:24:09 -0600224 def _CleanupOutputDir(self):
225 """Remove the temporary output directory"""
226 if self.preserve_outdirs:
227 print('Preserving output dir: %s' % tools.outdir)
228 else:
229 tools._FinaliseForTest()
230
Simon Glass4f443042016-11-25 20:15:52 -0700231 def setUp(self):
232 # Enable this to turn on debugging output
233 # tout.Init(tout.DEBUG)
234 command.test_result = None
235
236 def tearDown(self):
237 """Remove the temporary output directory"""
Simon Glassbf574f12019-07-20 12:24:09 -0600238 self._CleanupOutputDir()
Simon Glass4f443042016-11-25 20:15:52 -0700239
Simon Glassf86a7362019-07-20 12:24:10 -0600240 def _SetupImageInTmpdir(self):
241 """Set up the output image in a new temporary directory
242
243 This is used when an image has been generated in the output directory,
244 but we want to run binman again. This will create a new output
245 directory and fail to delete the original one.
246
247 This creates a new temporary directory, copies the image to it (with a
248 new name) and removes the old output directory.
249
250 Returns:
251 Tuple:
252 Temporary directory to use
253 New image filename
254 """
255 image_fname = tools.GetOutputFilename('image.bin')
256 tmpdir = tempfile.mkdtemp(prefix='binman.')
257 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
258 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
259 self._CleanupOutputDir()
260 return tmpdir, updated_fname
261
Simon Glassb8ef5b62018-07-17 13:25:48 -0600262 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600263 def _ResetDtbs(cls):
Simon Glassb8ef5b62018-07-17 13:25:48 -0600264 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
265 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
266 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
267
Simon Glass4f443042016-11-25 20:15:52 -0700268 def _RunBinman(self, *args, **kwargs):
269 """Run binman using the command line
270
271 Args:
272 Arguments to pass, as a list of strings
273 kwargs: Arguments to pass to Command.RunPipe()
274 """
275 result = command.RunPipe([[self._binman_pathname] + list(args)],
276 capture=True, capture_stderr=True, raise_on_error=False)
277 if result.return_code and kwargs.get('raise_on_error', True):
278 raise Exception("Error running '%s': %s" % (' '.join(args),
279 result.stdout + result.stderr))
280 return result
281
Simon Glass53cd5d92019-07-08 14:25:29 -0600282 def _DoBinman(self, *argv):
Simon Glass4f443042016-11-25 20:15:52 -0700283 """Run binman using directly (in the same process)
284
285 Args:
286 Arguments to pass, as a list of strings
287 Returns:
288 Return value (0 for success)
289 """
Simon Glass53cd5d92019-07-08 14:25:29 -0600290 argv = list(argv)
291 args = cmdline.ParseArgs(argv)
292 args.pager = 'binman-invalid-pager'
293 args.build_dir = self._indir
Simon Glass4f443042016-11-25 20:15:52 -0700294
295 # For testing, you can force an increase in verbosity here
Simon Glass53cd5d92019-07-08 14:25:29 -0600296 # args.verbosity = tout.DEBUG
297 return control.Binman(args)
Simon Glass4f443042016-11-25 20:15:52 -0700298
Simon Glass53af22a2018-07-17 13:25:32 -0600299 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glasseb833d82019-04-25 21:58:34 -0600300 entry_args=None, images=None, use_real_dtb=False,
Simon Glass6cf99532020-09-01 05:13:59 -0600301 verbosity=None, allow_missing=False, extra_indirs=None):
Simon Glass4f443042016-11-25 20:15:52 -0700302 """Run binman with a given test file
303
304 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600305 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600306 debug: True to enable debugging output
Simon Glass3b0c3822018-06-01 09:38:20 -0600307 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600308 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600309 tree before packing it into the image
Simon Glass0bfa7b02018-09-14 04:57:12 -0600310 entry_args: Dict of entry args to supply to binman
311 key: arg name
312 value: value of that arg
313 images: List of image names to build
Simon Glasse9d336d2020-09-01 05:13:55 -0600314 use_real_dtb: True to use the test file as the contents of
315 the u-boot-dtb entry. Normally this is not needed and the
316 test contents (the U_BOOT_DTB_DATA string) can be used.
317 But in some test we need the real contents.
318 verbosity: Verbosity level to use (0-3, None=don't set it)
319 allow_missing: Set the '--allow-missing' flag so that missing
320 external binaries just produce a warning instead of an error
Simon Glass6cf99532020-09-01 05:13:59 -0600321 extra_indirs: Extra input directories to add using -I
Simon Glass4f443042016-11-25 20:15:52 -0700322 """
Simon Glass53cd5d92019-07-08 14:25:29 -0600323 args = []
Simon Glass7fe91732017-11-13 18:55:00 -0700324 if debug:
325 args.append('-D')
Simon Glass53cd5d92019-07-08 14:25:29 -0600326 if verbosity is not None:
327 args.append('-v%d' % verbosity)
328 elif self.verbosity:
329 args.append('-v%d' % self.verbosity)
330 if self.toolpath:
331 for path in self.toolpath:
332 args += ['--toolpath', path]
333 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass3b0c3822018-06-01 09:38:20 -0600334 if map:
335 args.append('-m')
Simon Glass16b8d6b2018-07-06 10:27:42 -0600336 if update_dtb:
Simon Glass2569e102019-07-08 13:18:47 -0600337 args.append('-u')
Simon Glass93d17412018-09-14 04:57:23 -0600338 if not use_real_dtb:
339 args.append('--fake-dtb')
Simon Glass53af22a2018-07-17 13:25:32 -0600340 if entry_args:
Simon Glass50979152019-05-14 15:53:41 -0600341 for arg, value in entry_args.items():
Simon Glass53af22a2018-07-17 13:25:32 -0600342 args.append('-a%s=%s' % (arg, value))
Simon Glass4f9f1052020-07-09 18:39:38 -0600343 if allow_missing:
344 args.append('-M')
Simon Glass0bfa7b02018-09-14 04:57:12 -0600345 if images:
346 for image in images:
347 args += ['-i', image]
Simon Glass6cf99532020-09-01 05:13:59 -0600348 if extra_indirs:
349 for indir in extra_indirs:
350 args += ['-I', indir]
Simon Glass7fe91732017-11-13 18:55:00 -0700351 return self._DoBinman(*args)
Simon Glass4f443042016-11-25 20:15:52 -0700352
353 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glasse0ff8552016-11-25 20:15:53 -0700354 """Set up a new test device-tree file
355
356 The given file is compiled and set up as the device tree to be used
357 for ths test.
358
359 Args:
360 fname: Filename of .dts file to read
Simon Glass7ae5f312018-06-01 09:38:19 -0600361 outfile: Output filename for compiled device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700362
363 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600364 Contents of device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700365 """
Simon Glassa004f292019-07-20 12:23:49 -0600366 tmpdir = tempfile.mkdtemp(prefix='binmant.')
367 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
Simon Glass1d0ebf72019-05-14 15:53:42 -0600368 with open(dtb, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700369 data = fd.read()
370 TestFunctional._MakeInputFile(outfile, data)
Simon Glassa004f292019-07-20 12:23:49 -0600371 shutil.rmtree(tmpdir)
Simon Glasse0e62752018-10-01 21:12:41 -0600372 return data
Simon Glass4f443042016-11-25 20:15:52 -0700373
Simon Glass6ed45ba2018-09-14 04:57:24 -0600374 def _GetDtbContentsForSplTpl(self, dtb_data, name):
375 """Create a version of the main DTB for SPL or SPL
376
377 For testing we don't actually have different versions of the DTB. With
378 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
379 we don't normally have any unwanted nodes.
380
381 We still want the DTBs for SPL and TPL to be different though, since
382 otherwise it is confusing to know which one we are looking at. So add
383 an 'spl' or 'tpl' property to the top-level node.
Simon Glasse9d336d2020-09-01 05:13:55 -0600384
385 Args:
386 dtb_data: dtb data to modify (this should be a value devicetree)
387 name: Name of a new property to add
388
389 Returns:
390 New dtb data with the property added
Simon Glass6ed45ba2018-09-14 04:57:24 -0600391 """
392 dtb = fdt.Fdt.FromData(dtb_data)
393 dtb.Scan()
394 dtb.GetNode('/binman').AddZeroProp(name)
395 dtb.Sync(auto_resize=True)
396 dtb.Pack()
397 return dtb.GetContents()
398
Simon Glass16b8d6b2018-07-06 10:27:42 -0600399 def _DoReadFileDtb(self, fname, use_real_dtb=False, map=False,
Simon Glass6cf99532020-09-01 05:13:59 -0600400 update_dtb=False, entry_args=None, reset_dtbs=True,
401 extra_indirs=None):
Simon Glass4f443042016-11-25 20:15:52 -0700402 """Run binman and return the resulting image
403
404 This runs binman with a given test file and then reads the resulting
405 output file. It is a shortcut function since most tests need to do
406 these steps.
407
408 Raises an assertion failure if binman returns a non-zero exit code.
409
410 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600411 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass4f443042016-11-25 20:15:52 -0700412 use_real_dtb: True to use the test file as the contents of
413 the u-boot-dtb entry. Normally this is not needed and the
414 test contents (the U_BOOT_DTB_DATA string) can be used.
415 But in some test we need the real contents.
Simon Glass3b0c3822018-06-01 09:38:20 -0600416 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600417 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600418 tree before packing it into the image
Simon Glasse9d336d2020-09-01 05:13:55 -0600419 entry_args: Dict of entry args to supply to binman
420 key: arg name
421 value: value of that arg
422 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
423 function. If reset_dtbs is True, then the original test dtb
424 is written back before this function finishes
Simon Glass6cf99532020-09-01 05:13:59 -0600425 extra_indirs: Extra input directories to add using -I
Simon Glasse0ff8552016-11-25 20:15:53 -0700426
427 Returns:
428 Tuple:
429 Resulting image contents
430 Device tree contents
Simon Glass3b0c3822018-06-01 09:38:20 -0600431 Map data showing contents of image (or None if none)
Simon Glassea6922e2018-07-17 13:25:27 -0600432 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass4f443042016-11-25 20:15:52 -0700433 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700434 dtb_data = None
Simon Glass4f443042016-11-25 20:15:52 -0700435 # Use the compiled test file as the u-boot-dtb input
436 if use_real_dtb:
Simon Glasse0ff8552016-11-25 20:15:53 -0700437 dtb_data = self._SetupDtb(fname)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600438
439 # For testing purposes, make a copy of the DT for SPL and TPL. Add
440 # a node indicating which it is, so aid verification.
441 for name in ['spl', 'tpl']:
442 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
443 outfile = os.path.join(self._indir, dtb_fname)
444 TestFunctional._MakeInputFile(dtb_fname,
445 self._GetDtbContentsForSplTpl(dtb_data, name))
Simon Glass4f443042016-11-25 20:15:52 -0700446
447 try:
Simon Glass53af22a2018-07-17 13:25:32 -0600448 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glass6cf99532020-09-01 05:13:59 -0600449 entry_args=entry_args, use_real_dtb=use_real_dtb,
450 extra_indirs=extra_indirs)
Simon Glass4f443042016-11-25 20:15:52 -0700451 self.assertEqual(0, retcode)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600452 out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
Simon Glass4f443042016-11-25 20:15:52 -0700453
454 # Find the (only) image, read it and return its contents
455 image = control.images['image']
Simon Glass16b8d6b2018-07-06 10:27:42 -0600456 image_fname = tools.GetOutputFilename('image.bin')
457 self.assertTrue(os.path.exists(image_fname))
Simon Glass3b0c3822018-06-01 09:38:20 -0600458 if map:
459 map_fname = tools.GetOutputFilename('image.map')
460 with open(map_fname) as fd:
461 map_data = fd.read()
462 else:
463 map_data = None
Simon Glass1d0ebf72019-05-14 15:53:42 -0600464 with open(image_fname, 'rb') as fd:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600465 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass4f443042016-11-25 20:15:52 -0700466 finally:
467 # Put the test file back
Simon Glass6ed45ba2018-09-14 04:57:24 -0600468 if reset_dtbs and use_real_dtb:
Simon Glassb8ef5b62018-07-17 13:25:48 -0600469 self._ResetDtbs()
Simon Glass4f443042016-11-25 20:15:52 -0700470
Simon Glass3c081312019-07-08 14:25:26 -0600471 def _DoReadFileRealDtb(self, fname):
472 """Run binman with a real .dtb file and return the resulting data
473
474 Args:
475 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
476
477 Returns:
478 Resulting image contents
479 """
480 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
481
Simon Glasse0ff8552016-11-25 20:15:53 -0700482 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass7ae5f312018-06-01 09:38:19 -0600483 """Helper function which discards the device-tree binary
484
485 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600486 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600487 use_real_dtb: True to use the test file as the contents of
488 the u-boot-dtb entry. Normally this is not needed and the
489 test contents (the U_BOOT_DTB_DATA string) can be used.
490 But in some test we need the real contents.
Simon Glassea6922e2018-07-17 13:25:27 -0600491
492 Returns:
493 Resulting image contents
Simon Glass7ae5f312018-06-01 09:38:19 -0600494 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700495 return self._DoReadFileDtb(fname, use_real_dtb)[0]
496
Simon Glass4f443042016-11-25 20:15:52 -0700497 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600498 def _MakeInputFile(cls, fname, contents):
Simon Glass4f443042016-11-25 20:15:52 -0700499 """Create a new test input file, creating directories as needed
500
501 Args:
Simon Glass3ab95982018-08-01 15:22:37 -0600502 fname: Filename to create
Simon Glass4f443042016-11-25 20:15:52 -0700503 contents: File contents to write in to the file
504 Returns:
505 Full pathname of file created
506 """
Simon Glassb986b3b2019-08-24 07:22:43 -0600507 pathname = os.path.join(cls._indir, fname)
Simon Glass4f443042016-11-25 20:15:52 -0700508 dirname = os.path.dirname(pathname)
509 if dirname and not os.path.exists(dirname):
510 os.makedirs(dirname)
511 with open(pathname, 'wb') as fd:
512 fd.write(contents)
513 return pathname
514
515 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600516 def _MakeInputDir(cls, dirname):
Simon Glass0ef87aa2018-07-17 13:25:44 -0600517 """Create a new test input directory, creating directories as needed
518
519 Args:
520 dirname: Directory name to create
521
522 Returns:
523 Full pathname of directory created
524 """
Simon Glassb986b3b2019-08-24 07:22:43 -0600525 pathname = os.path.join(cls._indir, dirname)
Simon Glass0ef87aa2018-07-17 13:25:44 -0600526 if not os.path.exists(pathname):
527 os.makedirs(pathname)
528 return pathname
529
530 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600531 def _SetupSplElf(cls, src_fname='bss_data'):
Simon Glass11ae93e2018-10-01 21:12:47 -0600532 """Set up an ELF file with a '_dt_ucode_base_size' symbol
533
534 Args:
535 Filename of ELF file to use as SPL
536 """
Simon Glassc9a0b272019-08-24 07:22:59 -0600537 TestFunctional._MakeInputFile('spl/u-boot-spl',
538 tools.ReadFile(cls.ElfTestFile(src_fname)))
Simon Glass11ae93e2018-10-01 21:12:47 -0600539
540 @classmethod
Simon Glass2090f1e2019-08-24 07:23:00 -0600541 def _SetupTplElf(cls, src_fname='bss_data'):
542 """Set up an ELF file with a '_dt_ucode_base_size' symbol
543
544 Args:
545 Filename of ELF file to use as TPL
546 """
547 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
548 tools.ReadFile(cls.ElfTestFile(src_fname)))
549
550 @classmethod
Simon Glass0ba4b3d2020-07-09 18:39:41 -0600551 def _SetupDescriptor(cls):
552 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
553 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
554
555 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600556 def TestFile(cls, fname):
557 return os.path.join(cls._binman_dir, 'test', fname)
Simon Glass4f443042016-11-25 20:15:52 -0700558
Simon Glass53e22bf2019-08-24 07:22:53 -0600559 @classmethod
560 def ElfTestFile(cls, fname):
561 return os.path.join(cls._elf_testdir, fname)
562
Simon Glass4f443042016-11-25 20:15:52 -0700563 def AssertInList(self, grep_list, target):
564 """Assert that at least one of a list of things is in a target
565
566 Args:
567 grep_list: List of strings to check
568 target: Target string
569 """
570 for grep in grep_list:
571 if grep in target:
572 return
Simon Glass1fc62de2019-05-17 22:00:50 -0600573 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass4f443042016-11-25 20:15:52 -0700574
575 def CheckNoGaps(self, entries):
576 """Check that all entries fit together without gaps
577
578 Args:
579 entries: List of entries to check
580 """
Simon Glass3ab95982018-08-01 15:22:37 -0600581 offset = 0
Simon Glass4f443042016-11-25 20:15:52 -0700582 for entry in entries.values():
Simon Glass3ab95982018-08-01 15:22:37 -0600583 self.assertEqual(offset, entry.offset)
584 offset += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700585
Simon Glasse0ff8552016-11-25 20:15:53 -0700586 def GetFdtLen(self, dtb):
Simon Glass7ae5f312018-06-01 09:38:19 -0600587 """Get the totalsize field from a device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700588
589 Args:
Simon Glass7ae5f312018-06-01 09:38:19 -0600590 dtb: Device-tree binary contents
Simon Glasse0ff8552016-11-25 20:15:53 -0700591
592 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600593 Total size of device-tree binary, from the header
Simon Glasse0ff8552016-11-25 20:15:53 -0700594 """
595 return struct.unpack('>L', dtb[4:8])[0]
596
Simon Glass086cec92019-07-08 14:25:27 -0600597 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glass16b8d6b2018-07-06 10:27:42 -0600598 def AddNode(node, path):
599 if node.name != '/':
600 path += '/' + node.name
Simon Glass086cec92019-07-08 14:25:27 -0600601 for prop in node.props.values():
602 if prop.name in prop_names:
603 prop_path = path + ':' + prop.name
604 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
605 prop.value)
Simon Glass16b8d6b2018-07-06 10:27:42 -0600606 for subnode in node.subnodes:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600607 AddNode(subnode, path)
608
609 tree = {}
Simon Glass16b8d6b2018-07-06 10:27:42 -0600610 AddNode(dtb.GetRoot(), '')
611 return tree
612
Simon Glass4f443042016-11-25 20:15:52 -0700613 def testRun(self):
614 """Test a basic run with valid args"""
615 result = self._RunBinman('-h')
616
617 def testFullHelp(self):
618 """Test that the full help is displayed with -H"""
619 result = self._RunBinman('-H')
620 help_file = os.path.join(self._binman_dir, 'README')
Tom Rini3759df02018-01-16 15:29:50 -0500621 # Remove possible extraneous strings
622 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
623 gothelp = result.stdout.replace(extra, '')
624 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass4f443042016-11-25 20:15:52 -0700625 self.assertEqual(0, len(result.stderr))
626 self.assertEqual(0, result.return_code)
627
628 def testFullHelpInternal(self):
629 """Test that the full help is displayed with -H"""
630 try:
631 command.test_result = command.CommandResult()
632 result = self._DoBinman('-H')
633 help_file = os.path.join(self._binman_dir, 'README')
634 finally:
635 command.test_result = None
636
637 def testHelp(self):
638 """Test that the basic help is displayed with -h"""
639 result = self._RunBinman('-h')
640 self.assertTrue(len(result.stdout) > 200)
641 self.assertEqual(0, len(result.stderr))
642 self.assertEqual(0, result.return_code)
643
Simon Glass4f443042016-11-25 20:15:52 -0700644 def testBoard(self):
645 """Test that we can run it with a specific board"""
Simon Glass741f2d62018-10-01 12:22:30 -0600646 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass4f443042016-11-25 20:15:52 -0700647 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glass53cd5d92019-07-08 14:25:29 -0600648 result = self._DoBinman('build', '-b', 'sandbox')
Simon Glass4f443042016-11-25 20:15:52 -0700649 self.assertEqual(0, result)
650
651 def testNeedBoard(self):
652 """Test that we get an error when no board ius supplied"""
653 with self.assertRaises(ValueError) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600654 result = self._DoBinman('build')
Simon Glass4f443042016-11-25 20:15:52 -0700655 self.assertIn("Must provide a board to process (use -b <board>)",
656 str(e.exception))
657
658 def testMissingDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600659 """Test that an invalid device-tree file generates an error"""
Simon Glass4f443042016-11-25 20:15:52 -0700660 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600661 self._RunBinman('build', '-d', 'missing_file')
Simon Glass4f443042016-11-25 20:15:52 -0700662 # We get one error from libfdt, and a different one from fdtget.
663 self.AssertInList(["Couldn't open blob from 'missing_file'",
664 'No such file or directory'], str(e.exception))
665
666 def testBrokenDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600667 """Test that an invalid device-tree source file generates an error
Simon Glass4f443042016-11-25 20:15:52 -0700668
669 Since this is a source file it should be compiled and the error
670 will come from the device-tree compiler (dtc).
671 """
672 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600673 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700674 self.assertIn("FATAL ERROR: Unable to parse input tree",
675 str(e.exception))
676
677 def testMissingNode(self):
678 """Test that a device tree without a 'binman' node generates an error"""
679 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600680 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700681 self.assertIn("does not have a 'binman' node", str(e.exception))
682
683 def testEmpty(self):
684 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glass53cd5d92019-07-08 14:25:29 -0600685 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700686 self.assertEqual(0, len(result.stderr))
687 self.assertEqual(0, result.return_code)
688
689 def testInvalidEntry(self):
690 """Test that an invalid entry is flagged"""
691 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600692 result = self._RunBinman('build', '-d',
Simon Glass741f2d62018-10-01 12:22:30 -0600693 self.TestFile('004_invalid_entry.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700694 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
695 "'/binman/not-a-valid-type'", str(e.exception))
696
697 def testSimple(self):
698 """Test a simple binman with a single file"""
Simon Glass741f2d62018-10-01 12:22:30 -0600699 data = self._DoReadFile('005_simple.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700700 self.assertEqual(U_BOOT_DATA, data)
701
Simon Glass7fe91732017-11-13 18:55:00 -0700702 def testSimpleDebug(self):
703 """Test a simple binman run with debugging enabled"""
Simon Glasse2705fa2019-07-08 14:25:53 -0600704 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass7fe91732017-11-13 18:55:00 -0700705
Simon Glass4f443042016-11-25 20:15:52 -0700706 def testDual(self):
707 """Test that we can handle creating two images
708
709 This also tests image padding.
710 """
Simon Glass741f2d62018-10-01 12:22:30 -0600711 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700712 self.assertEqual(0, retcode)
713
714 image = control.images['image1']
Simon Glass8beb11e2019-07-08 14:25:47 -0600715 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700716 fname = tools.GetOutputFilename('image1.bin')
717 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600718 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700719 data = fd.read()
720 self.assertEqual(U_BOOT_DATA, data)
721
722 image = control.images['image2']
Simon Glass8beb11e2019-07-08 14:25:47 -0600723 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700724 fname = tools.GetOutputFilename('image2.bin')
725 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600726 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700727 data = fd.read()
728 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glasse6d85ff2019-05-14 15:53:47 -0600729 self.assertEqual(tools.GetBytes(0, 3), data[:3])
730 self.assertEqual(tools.GetBytes(0, 5), data[7:])
Simon Glass4f443042016-11-25 20:15:52 -0700731
732 def testBadAlign(self):
733 """Test that an invalid alignment value is detected"""
734 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600735 self._DoTestFile('007_bad_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700736 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
737 "of two", str(e.exception))
738
739 def testPackSimple(self):
740 """Test that packing works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600741 retcode = self._DoTestFile('008_pack.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700742 self.assertEqual(0, retcode)
743 self.assertIn('image', control.images)
744 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600745 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700746 self.assertEqual(5, len(entries))
747
748 # First u-boot
749 self.assertIn('u-boot', entries)
750 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600751 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700752 self.assertEqual(len(U_BOOT_DATA), entry.size)
753
754 # Second u-boot, aligned to 16-byte boundary
755 self.assertIn('u-boot-align', entries)
756 entry = entries['u-boot-align']
Simon Glass3ab95982018-08-01 15:22:37 -0600757 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700758 self.assertEqual(len(U_BOOT_DATA), entry.size)
759
760 # Third u-boot, size 23 bytes
761 self.assertIn('u-boot-size', entries)
762 entry = entries['u-boot-size']
Simon Glass3ab95982018-08-01 15:22:37 -0600763 self.assertEqual(20, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700764 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
765 self.assertEqual(23, entry.size)
766
767 # Fourth u-boot, placed immediate after the above
768 self.assertIn('u-boot-next', entries)
769 entry = entries['u-boot-next']
Simon Glass3ab95982018-08-01 15:22:37 -0600770 self.assertEqual(43, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700771 self.assertEqual(len(U_BOOT_DATA), entry.size)
772
Simon Glass3ab95982018-08-01 15:22:37 -0600773 # Fifth u-boot, placed at a fixed offset
Simon Glass4f443042016-11-25 20:15:52 -0700774 self.assertIn('u-boot-fixed', entries)
775 entry = entries['u-boot-fixed']
Simon Glass3ab95982018-08-01 15:22:37 -0600776 self.assertEqual(61, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700777 self.assertEqual(len(U_BOOT_DATA), entry.size)
778
Simon Glass8beb11e2019-07-08 14:25:47 -0600779 self.assertEqual(65, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700780
781 def testPackExtra(self):
782 """Test that extra packing feature works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600783 retcode = self._DoTestFile('009_pack_extra.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700784
785 self.assertEqual(0, retcode)
786 self.assertIn('image', control.images)
787 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600788 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700789 self.assertEqual(5, len(entries))
790
791 # First u-boot with padding before and after
792 self.assertIn('u-boot', entries)
793 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600794 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700795 self.assertEqual(3, entry.pad_before)
796 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
797
798 # Second u-boot has an aligned size, but it has no effect
799 self.assertIn('u-boot-align-size-nop', entries)
800 entry = entries['u-boot-align-size-nop']
Simon Glass3ab95982018-08-01 15:22:37 -0600801 self.assertEqual(12, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700802 self.assertEqual(4, entry.size)
803
804 # Third u-boot has an aligned size too
805 self.assertIn('u-boot-align-size', entries)
806 entry = entries['u-boot-align-size']
Simon Glass3ab95982018-08-01 15:22:37 -0600807 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700808 self.assertEqual(32, entry.size)
809
810 # Fourth u-boot has an aligned end
811 self.assertIn('u-boot-align-end', entries)
812 entry = entries['u-boot-align-end']
Simon Glass3ab95982018-08-01 15:22:37 -0600813 self.assertEqual(48, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700814 self.assertEqual(16, entry.size)
815
816 # Fifth u-boot immediately afterwards
817 self.assertIn('u-boot-align-both', entries)
818 entry = entries['u-boot-align-both']
Simon Glass3ab95982018-08-01 15:22:37 -0600819 self.assertEqual(64, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700820 self.assertEqual(64, entry.size)
821
822 self.CheckNoGaps(entries)
Simon Glass8beb11e2019-07-08 14:25:47 -0600823 self.assertEqual(128, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700824
825 def testPackAlignPowerOf2(self):
826 """Test that invalid entry alignment is detected"""
827 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600828 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700829 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
830 "of two", str(e.exception))
831
832 def testPackAlignSizePowerOf2(self):
833 """Test that invalid entry size alignment is detected"""
834 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600835 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700836 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
837 "power of two", str(e.exception))
838
839 def testPackInvalidAlign(self):
Simon Glass3ab95982018-08-01 15:22:37 -0600840 """Test detection of an offset that does not match its alignment"""
Simon Glass4f443042016-11-25 20:15:52 -0700841 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600842 self._DoTestFile('012_pack_inv_align.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600843 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700844 "align 0x4 (4)", str(e.exception))
845
846 def testPackInvalidSizeAlign(self):
847 """Test that invalid entry size alignment is detected"""
848 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600849 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700850 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
851 "align-size 0x4 (4)", str(e.exception))
852
853 def testPackOverlap(self):
854 """Test that overlapping regions are detected"""
855 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600856 self._DoTestFile('014_pack_overlap.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600857 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -0700858 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
859 str(e.exception))
860
861 def testPackEntryOverflow(self):
862 """Test that entries that overflow their size are detected"""
863 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600864 self._DoTestFile('015_pack_overflow.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700865 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
866 "but entry size is 0x3 (3)", str(e.exception))
867
868 def testPackImageOverflow(self):
869 """Test that entries which overflow the image size are detected"""
870 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600871 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600872 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass4f443042016-11-25 20:15:52 -0700873 "size 0x3 (3)", str(e.exception))
874
875 def testPackImageSize(self):
876 """Test that the image size can be set"""
Simon Glass741f2d62018-10-01 12:22:30 -0600877 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700878 self.assertEqual(0, retcode)
879 self.assertIn('image', control.images)
880 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -0600881 self.assertEqual(7, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700882
883 def testPackImageSizeAlign(self):
884 """Test that image size alignemnt works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600885 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700886 self.assertEqual(0, retcode)
887 self.assertIn('image', control.images)
888 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -0600889 self.assertEqual(16, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700890
891 def testPackInvalidImageAlign(self):
892 """Test that invalid image alignment is detected"""
893 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600894 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600895 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700896 "align-size 0x8 (8)", str(e.exception))
897
898 def testPackAlignPowerOf2(self):
899 """Test that invalid image alignment is detected"""
900 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600901 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -0600902 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass4f443042016-11-25 20:15:52 -0700903 "two", str(e.exception))
904
905 def testImagePadByte(self):
906 """Test that the image pad byte can be specified"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600907 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600908 data = self._DoReadFile('021_image_pad.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -0600909 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0xff, 1) +
910 U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -0700911
912 def testImageName(self):
913 """Test that image files can be named"""
Simon Glass741f2d62018-10-01 12:22:30 -0600914 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700915 self.assertEqual(0, retcode)
916 image = control.images['image1']
917 fname = tools.GetOutputFilename('test-name')
918 self.assertTrue(os.path.exists(fname))
919
920 image = control.images['image2']
921 fname = tools.GetOutputFilename('test-name.xx')
922 self.assertTrue(os.path.exists(fname))
923
924 def testBlobFilename(self):
925 """Test that generic blobs can be provided by filename"""
Simon Glass741f2d62018-10-01 12:22:30 -0600926 data = self._DoReadFile('023_blob.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700927 self.assertEqual(BLOB_DATA, data)
928
929 def testPackSorted(self):
930 """Test that entries can be sorted"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600931 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600932 data = self._DoReadFile('024_sorted.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -0600933 self.assertEqual(tools.GetBytes(0, 1) + U_BOOT_SPL_DATA +
934 tools.GetBytes(0, 2) + U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -0700935
Simon Glass3ab95982018-08-01 15:22:37 -0600936 def testPackZeroOffset(self):
937 """Test that an entry at offset 0 is not given a new offset"""
Simon Glass4f443042016-11-25 20:15:52 -0700938 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600939 self._DoTestFile('025_pack_zero_size.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600940 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -0700941 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
942 str(e.exception))
943
944 def testPackUbootDtb(self):
945 """Test that a device tree can be added to U-Boot"""
Simon Glass741f2d62018-10-01 12:22:30 -0600946 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700947 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glasse0ff8552016-11-25 20:15:53 -0700948
949 def testPackX86RomNoSize(self):
950 """Test that the end-at-4gb property requires a size property"""
951 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600952 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -0600953 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glasse0ff8552016-11-25 20:15:53 -0700954 "using end-at-4gb", str(e.exception))
955
Jagdish Gediya94b57db2018-09-03 21:35:07 +0530956 def test4gbAndSkipAtStartTogether(self):
957 """Test that the end-at-4gb and skip-at-size property can't be used
958 together"""
959 with self.assertRaises(ValueError) as e:
Simon Glassdfdd2b62019-08-24 07:23:02 -0600960 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -0600961 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya94b57db2018-09-03 21:35:07 +0530962 "'skip-at-start'", str(e.exception))
963
Simon Glasse0ff8552016-11-25 20:15:53 -0700964 def testPackX86RomOutside(self):
Simon Glass3ab95982018-08-01 15:22:37 -0600965 """Test that the end-at-4gb property checks for offset boundaries"""
Simon Glasse0ff8552016-11-25 20:15:53 -0700966 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600967 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600968 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) is outside "
Simon Glass8f1da502018-06-01 09:38:12 -0600969 "the section starting at 0xffffffe0 (4294967264)",
Simon Glasse0ff8552016-11-25 20:15:53 -0700970 str(e.exception))
971
972 def testPackX86Rom(self):
973 """Test that a basic x86 ROM can be created"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600974 self._SetupSplElf()
Simon Glass9255f3c2019-08-24 07:23:01 -0600975 data = self._DoReadFile('029_x86_rom.dts')
Simon Glasseb0086f2019-08-24 07:23:04 -0600976 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 3) + U_BOOT_SPL_DATA +
Simon Glasse6d85ff2019-05-14 15:53:47 -0600977 tools.GetBytes(0, 2), data)
Simon Glasse0ff8552016-11-25 20:15:53 -0700978
979 def testPackX86RomMeNoDesc(self):
980 """Test that an invalid Intel descriptor entry is detected"""
Simon Glass0ba4b3d2020-07-09 18:39:41 -0600981 try:
Simon Glass52b10dd2020-07-25 15:11:19 -0600982 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
Simon Glass0ba4b3d2020-07-09 18:39:41 -0600983 with self.assertRaises(ValueError) as e:
Simon Glass52b10dd2020-07-25 15:11:19 -0600984 self._DoTestFile('163_x86_rom_me_empty.dts')
Simon Glass0ba4b3d2020-07-09 18:39:41 -0600985 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
986 str(e.exception))
987 finally:
988 self._SetupDescriptor()
Simon Glasse0ff8552016-11-25 20:15:53 -0700989
990 def testPackX86RomBadDesc(self):
991 """Test that the Intel requires a descriptor entry"""
992 with self.assertRaises(ValueError) as e:
Simon Glass9255f3c2019-08-24 07:23:01 -0600993 self._DoTestFile('030_x86_rom_me_no_desc.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600994 self.assertIn("Node '/binman/intel-me': No offset set with "
995 "offset-unset: should another entry provide this correct "
996 "offset?", str(e.exception))
Simon Glasse0ff8552016-11-25 20:15:53 -0700997
998 def testPackX86RomMe(self):
999 """Test that an x86 ROM with an ME region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001000 data = self._DoReadFile('031_x86_rom_me.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06001001 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
1002 if data[:0x1000] != expected_desc:
1003 self.fail('Expected descriptor binary at start of image')
Simon Glasse0ff8552016-11-25 20:15:53 -07001004 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1005
1006 def testPackVga(self):
1007 """Test that an image with a VGA binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001008 data = self._DoReadFile('032_intel_vga.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -07001009 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1010
1011 def testPackStart16(self):
1012 """Test that an image with an x86 start16 region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001013 data = self._DoReadFile('033_x86_start16.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -07001014 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1015
Jagdish Gediya9d368f32018-09-03 21:35:08 +05301016 def testPackPowerpcMpc85xxBootpgResetvec(self):
1017 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1018 created"""
Simon Glassdfdd2b62019-08-24 07:23:02 -06001019 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
Jagdish Gediya9d368f32018-09-03 21:35:08 +05301020 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1021
Simon Glass736bb0a2018-07-06 10:27:17 -06001022 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glassadc57012018-07-06 10:27:16 -06001023 """Handle running a test for insertion of microcode
1024
1025 Args:
1026 dts_fname: Name of test .dts file
1027 nodtb_data: Data that we expect in the first section
Simon Glass736bb0a2018-07-06 10:27:17 -06001028 ucode_second: True if the microsecond entry is second instead of
1029 third
Simon Glassadc57012018-07-06 10:27:16 -06001030
1031 Returns:
1032 Tuple:
1033 Contents of first region (U-Boot or SPL)
Simon Glass3ab95982018-08-01 15:22:37 -06001034 Offset and size components of microcode pointer, as inserted
Simon Glassadc57012018-07-06 10:27:16 -06001035 in the above (two 4-byte words)
1036 """
Simon Glass6b187df2017-11-12 21:52:27 -07001037 data = self._DoReadFile(dts_fname, True)
Simon Glasse0ff8552016-11-25 20:15:53 -07001038
1039 # Now check the device tree has no microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001040 if ucode_second:
1041 ucode_content = data[len(nodtb_data):]
1042 ucode_pos = len(nodtb_data)
1043 dtb_with_ucode = ucode_content[16:]
1044 fdt_len = self.GetFdtLen(dtb_with_ucode)
1045 else:
1046 dtb_with_ucode = data[len(nodtb_data):]
1047 fdt_len = self.GetFdtLen(dtb_with_ucode)
1048 ucode_content = dtb_with_ucode[fdt_len:]
1049 ucode_pos = len(nodtb_data) + fdt_len
Simon Glasse0ff8552016-11-25 20:15:53 -07001050 fname = tools.GetOutputFilename('test.dtb')
1051 with open(fname, 'wb') as fd:
Simon Glassadc57012018-07-06 10:27:16 -06001052 fd.write(dtb_with_ucode)
Simon Glassec3f3782017-05-27 07:38:29 -06001053 dtb = fdt.FdtScan(fname)
1054 ucode = dtb.GetNode('/microcode')
Simon Glasse0ff8552016-11-25 20:15:53 -07001055 self.assertTrue(ucode)
1056 for node in ucode.subnodes:
1057 self.assertFalse(node.props.get('data'))
1058
Simon Glasse0ff8552016-11-25 20:15:53 -07001059 # Check that the microcode appears immediately after the Fdt
1060 # This matches the concatenation of the data properties in
Simon Glass87722132017-11-12 21:52:26 -07001061 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glasse0ff8552016-11-25 20:15:53 -07001062 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1063 0x78235609)
Simon Glassadc57012018-07-06 10:27:16 -06001064 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glasse0ff8552016-11-25 20:15:53 -07001065
1066 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -06001067 # expected offset and size
Simon Glasse0ff8552016-11-25 20:15:53 -07001068 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1069 len(ucode_data))
Simon Glass736bb0a2018-07-06 10:27:17 -06001070 u_boot = data[:len(nodtb_data)]
1071 return u_boot, pos_and_size
Simon Glass6b187df2017-11-12 21:52:27 -07001072
1073 def testPackUbootMicrocode(self):
1074 """Test that x86 microcode can be handled correctly
1075
1076 We expect to see the following in the image, in order:
1077 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1078 place
1079 u-boot.dtb with the microcode removed
1080 the microcode
1081 """
Simon Glass741f2d62018-10-01 12:22:30 -06001082 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass6b187df2017-11-12 21:52:27 -07001083 U_BOOT_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001084 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1085 b' somewhere in here', first)
Simon Glasse0ff8552016-11-25 20:15:53 -07001086
Simon Glass160a7662017-05-27 07:38:26 -06001087 def _RunPackUbootSingleMicrocode(self):
Simon Glasse0ff8552016-11-25 20:15:53 -07001088 """Test that x86 microcode can be handled correctly
1089
1090 We expect to see the following in the image, in order:
1091 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1092 place
1093 u-boot.dtb with the microcode
1094 an empty microcode region
1095 """
1096 # We need the libfdt library to run this test since only that allows
1097 # finding the offset of a property. This is required by
1098 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass741f2d62018-10-01 12:22:30 -06001099 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glasse0ff8552016-11-25 20:15:53 -07001100
1101 second = data[len(U_BOOT_NODTB_DATA):]
1102
1103 fdt_len = self.GetFdtLen(second)
1104 third = second[fdt_len:]
1105 second = second[:fdt_len]
1106
Simon Glass160a7662017-05-27 07:38:26 -06001107 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1108 self.assertIn(ucode_data, second)
1109 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -07001110
Simon Glass160a7662017-05-27 07:38:26 -06001111 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -06001112 # expected offset and size
Simon Glass160a7662017-05-27 07:38:26 -06001113 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1114 len(ucode_data))
1115 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glassc6c10e72019-05-17 22:00:46 -06001116 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1117 b' somewhere in here', first)
Simon Glassc49deb82016-11-25 20:15:54 -07001118
Simon Glass75db0862016-11-25 20:15:55 -07001119 def testPackUbootSingleMicrocode(self):
1120 """Test that x86 microcode can be handled correctly with fdt_normal.
1121 """
Simon Glass160a7662017-05-27 07:38:26 -06001122 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001123
Simon Glassc49deb82016-11-25 20:15:54 -07001124 def testUBootImg(self):
1125 """Test that u-boot.img can be put in a file"""
Simon Glass741f2d62018-10-01 12:22:30 -06001126 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glassc49deb82016-11-25 20:15:54 -07001127 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glass75db0862016-11-25 20:15:55 -07001128
1129 def testNoMicrocode(self):
1130 """Test that a missing microcode region is detected"""
1131 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001132 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001133 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1134 "node found in ", str(e.exception))
1135
1136 def testMicrocodeWithoutNode(self):
1137 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1138 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001139 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001140 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1141 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1142
1143 def testMicrocodeWithoutNode2(self):
1144 """Test that a missing u-boot-ucode node is detected"""
1145 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001146 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001147 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1148 "microcode region u-boot-ucode", str(e.exception))
1149
1150 def testMicrocodeWithoutPtrInElf(self):
1151 """Test that a U-Boot binary without the microcode symbol is detected"""
1152 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glass75db0862016-11-25 20:15:55 -07001153 try:
Simon Glassbccd91d2019-08-24 07:22:55 -06001154 TestFunctional._MakeInputFile('u-boot',
1155 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass75db0862016-11-25 20:15:55 -07001156
1157 with self.assertRaises(ValueError) as e:
Simon Glass160a7662017-05-27 07:38:26 -06001158 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001159 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1160 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1161
1162 finally:
1163 # Put the original file back
Simon Glassf514d8f2019-08-24 07:22:54 -06001164 TestFunctional._MakeInputFile('u-boot',
1165 tools.ReadFile(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glass75db0862016-11-25 20:15:55 -07001166
1167 def testMicrocodeNotInImage(self):
1168 """Test that microcode must be placed within the image"""
1169 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001170 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001171 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1172 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glass25ac0e62018-06-01 09:38:14 -06001173 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glass75db0862016-11-25 20:15:55 -07001174
1175 def testWithoutMicrocode(self):
1176 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glassbccd91d2019-08-24 07:22:55 -06001177 TestFunctional._MakeInputFile('u-boot',
1178 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass741f2d62018-10-01 12:22:30 -06001179 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001180
1181 # Now check the device tree has no microcode
1182 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1183 second = data[len(U_BOOT_NODTB_DATA):]
1184
1185 fdt_len = self.GetFdtLen(second)
1186 self.assertEqual(dtb, second[:fdt_len])
1187
1188 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1189 third = data[used_len:]
Simon Glasse6d85ff2019-05-14 15:53:47 -06001190 self.assertEqual(tools.GetBytes(0, 0x200 - used_len), third)
Simon Glass75db0862016-11-25 20:15:55 -07001191
1192 def testUnknownPosSize(self):
1193 """Test that microcode must be placed within the image"""
1194 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001195 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glass3ab95982018-08-01 15:22:37 -06001196 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glass75db0862016-11-25 20:15:55 -07001197 "entry 'invalid-entry'", str(e.exception))
Simon Glassda229092016-11-25 20:15:56 -07001198
1199 def testPackFsp(self):
1200 """Test that an image with a FSP binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001201 data = self._DoReadFile('042_intel_fsp.dts')
Simon Glassda229092016-11-25 20:15:56 -07001202 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1203
1204 def testPackCmc(self):
Bin Meng59ea8c22017-08-15 22:41:54 -07001205 """Test that an image with a CMC binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001206 data = self._DoReadFile('043_intel_cmc.dts')
Simon Glassda229092016-11-25 20:15:56 -07001207 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Meng59ea8c22017-08-15 22:41:54 -07001208
1209 def testPackVbt(self):
1210 """Test that an image with a VBT binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001211 data = self._DoReadFile('046_intel_vbt.dts')
Bin Meng59ea8c22017-08-15 22:41:54 -07001212 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glass9fc60b42017-11-12 21:52:22 -07001213
Simon Glass56509842017-11-12 21:52:25 -07001214 def testSplBssPad(self):
1215 """Test that we can pad SPL's BSS with zeros"""
Simon Glass6b187df2017-11-12 21:52:27 -07001216 # ELF file with a '__bss_size' symbol
Simon Glass11ae93e2018-10-01 21:12:47 -06001217 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001218 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001219 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
1220 data)
Simon Glass56509842017-11-12 21:52:25 -07001221
Simon Glass86af5112018-10-01 21:12:42 -06001222 def testSplBssPadMissing(self):
1223 """Test that a missing symbol is detected"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001224 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glassb50e5612017-11-13 18:54:54 -07001225 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001226 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassb50e5612017-11-13 18:54:54 -07001227 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1228 str(e.exception))
1229
Simon Glass87722132017-11-12 21:52:26 -07001230 def testPackStart16Spl(self):
Simon Glass35b384c2018-09-14 04:57:10 -06001231 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001232 data = self._DoReadFile('048_x86_start16_spl.dts')
Simon Glass87722132017-11-12 21:52:26 -07001233 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1234
Simon Glass736bb0a2018-07-06 10:27:17 -06001235 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1236 """Helper function for microcode tests
Simon Glass6b187df2017-11-12 21:52:27 -07001237
1238 We expect to see the following in the image, in order:
1239 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1240 correct place
1241 u-boot.dtb with the microcode removed
1242 the microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001243
1244 Args:
1245 dts: Device tree file to use for test
1246 ucode_second: True if the microsecond entry is second instead of
1247 third
Simon Glass6b187df2017-11-12 21:52:27 -07001248 """
Simon Glass11ae93e2018-10-01 21:12:47 -06001249 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass736bb0a2018-07-06 10:27:17 -06001250 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1251 ucode_second=ucode_second)
Simon Glassc6c10e72019-05-17 22:00:46 -06001252 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1253 b'ter somewhere in here', first)
Simon Glass6b187df2017-11-12 21:52:27 -07001254
Simon Glass736bb0a2018-07-06 10:27:17 -06001255 def testPackUbootSplMicrocode(self):
1256 """Test that x86 microcode can be handled correctly in SPL"""
Simon Glass741f2d62018-10-01 12:22:30 -06001257 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass736bb0a2018-07-06 10:27:17 -06001258
1259 def testPackUbootSplMicrocodeReorder(self):
1260 """Test that order doesn't matter for microcode entries
1261
1262 This is the same as testPackUbootSplMicrocode but when we process the
1263 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1264 entry, so we reply on binman to try later.
1265 """
Simon Glass741f2d62018-10-01 12:22:30 -06001266 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass736bb0a2018-07-06 10:27:17 -06001267 ucode_second=True)
1268
Simon Glassca4f4ff2017-11-12 21:52:28 -07001269 def testPackMrc(self):
1270 """Test that an image with an MRC binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001271 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassca4f4ff2017-11-12 21:52:28 -07001272 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1273
Simon Glass47419ea2017-11-13 18:54:55 -07001274 def testSplDtb(self):
1275 """Test that an image with spl/u-boot-spl.dtb can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001276 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass47419ea2017-11-13 18:54:55 -07001277 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1278
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001279 def testSplNoDtb(self):
1280 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001281 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001282 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1283
Simon Glass19790632017-11-13 18:55:01 -07001284 def testSymbols(self):
1285 """Test binman can assign symbols embedded in U-Boot"""
Simon Glass1542c8b2019-08-24 07:22:56 -06001286 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass19790632017-11-13 18:55:01 -07001287 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1288 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Simon Glass3ab95982018-08-01 15:22:37 -06001289 self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr)
Simon Glass19790632017-11-13 18:55:01 -07001290
Simon Glass11ae93e2018-10-01 21:12:47 -06001291 self._SetupSplElf('u_boot_binman_syms')
Simon Glass741f2d62018-10-01 12:22:30 -06001292 data = self._DoReadFile('053_symbols.dts')
Simon Glass7c150132019-11-06 17:22:44 -07001293 sym_values = struct.pack('<LQLL', 0x00, 0x1c, 0x28, 0x04)
Simon Glassb87064c2019-08-24 07:23:05 -06001294 expected = (sym_values + U_BOOT_SPL_DATA[20:] +
Simon Glasse6d85ff2019-05-14 15:53:47 -06001295 tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
Simon Glassb87064c2019-08-24 07:23:05 -06001296 U_BOOT_SPL_DATA[20:])
Simon Glass19790632017-11-13 18:55:01 -07001297 self.assertEqual(expected, data)
1298
Simon Glassdd57c132018-06-01 09:38:11 -06001299 def testPackUnitAddress(self):
1300 """Test that we support multiple binaries with the same name"""
Simon Glass741f2d62018-10-01 12:22:30 -06001301 data = self._DoReadFile('054_unit_address.dts')
Simon Glassdd57c132018-06-01 09:38:11 -06001302 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1303
Simon Glass18546952018-06-01 09:38:16 -06001304 def testSections(self):
1305 """Basic test of sections"""
Simon Glass741f2d62018-10-01 12:22:30 -06001306 data = self._DoReadFile('055_sections.dts')
Simon Glassc6c10e72019-05-17 22:00:46 -06001307 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1308 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
1309 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
Simon Glass18546952018-06-01 09:38:16 -06001310 self.assertEqual(expected, data)
Simon Glass9fc60b42017-11-12 21:52:22 -07001311
Simon Glass3b0c3822018-06-01 09:38:20 -06001312 def testMap(self):
1313 """Tests outputting a map of the images"""
Simon Glass741f2d62018-10-01 12:22:30 -06001314 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001315 self.assertEqual('''ImagePos Offset Size Name
131600000000 00000000 00000028 main-section
131700000000 00000000 00000010 section@0
131800000000 00000000 00000004 u-boot
131900000010 00000010 00000010 section@1
132000000010 00000000 00000004 u-boot
132100000020 00000020 00000004 section@2
132200000020 00000000 00000004 u-boot
Simon Glass3b0c3822018-06-01 09:38:20 -06001323''', map_data)
1324
Simon Glassc8d48ef2018-06-01 09:38:21 -06001325 def testNamePrefix(self):
1326 """Tests that name prefixes are used"""
Simon Glass741f2d62018-10-01 12:22:30 -06001327 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001328 self.assertEqual('''ImagePos Offset Size Name
132900000000 00000000 00000028 main-section
133000000000 00000000 00000010 section@0
133100000000 00000000 00000004 ro-u-boot
133200000010 00000010 00000010 section@1
133300000010 00000000 00000004 rw-u-boot
Simon Glassc8d48ef2018-06-01 09:38:21 -06001334''', map_data)
1335
Simon Glass736bb0a2018-07-06 10:27:17 -06001336 def testUnknownContents(self):
1337 """Test that obtaining the contents works as expected"""
1338 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001339 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass8beb11e2019-07-08 14:25:47 -06001340 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glass16287932020-04-17 18:09:03 -06001341 "processing of contents: remaining ["
1342 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass736bb0a2018-07-06 10:27:17 -06001343
Simon Glass5c890232018-07-06 10:27:19 -06001344 def testBadChangeSize(self):
1345 """Test that trying to change the size of an entry fails"""
Simon Glassc52c9e72019-07-08 14:25:37 -06001346 try:
1347 state.SetAllowEntryExpansion(False)
1348 with self.assertRaises(ValueError) as e:
1349 self._DoReadFile('059_change_size.dts', True)
Simon Glass79d3c582019-07-20 12:23:57 -06001350 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glassc52c9e72019-07-08 14:25:37 -06001351 str(e.exception))
1352 finally:
1353 state.SetAllowEntryExpansion(True)
Simon Glass5c890232018-07-06 10:27:19 -06001354
Simon Glass16b8d6b2018-07-06 10:27:42 -06001355 def testUpdateFdt(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001356 """Test that we can update the device tree with offset/size info"""
Simon Glass741f2d62018-10-01 12:22:30 -06001357 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glass16b8d6b2018-07-06 10:27:42 -06001358 update_dtb=True)
Simon Glasscee02e62018-07-17 13:25:52 -06001359 dtb = fdt.Fdt(out_dtb_fname)
1360 dtb.Scan()
Simon Glass12bb1a92019-07-20 12:23:51 -06001361 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001362 self.assertEqual({
Simon Glassdbf6be92018-08-01 15:22:42 -06001363 'image-pos': 0,
Simon Glass8122f392018-07-17 13:25:28 -06001364 'offset': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001365 '_testing:offset': 32,
Simon Glass79d3c582019-07-20 12:23:57 -06001366 '_testing:size': 2,
Simon Glassdbf6be92018-08-01 15:22:42 -06001367 '_testing:image-pos': 32,
Simon Glass3ab95982018-08-01 15:22:37 -06001368 'section@0/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001369 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001370 'section@0/u-boot:image-pos': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001371 'section@0:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001372 'section@0:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001373 'section@0:image-pos': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001374
Simon Glass3ab95982018-08-01 15:22:37 -06001375 'section@1/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001376 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001377 'section@1/u-boot:image-pos': 16,
Simon Glass3ab95982018-08-01 15:22:37 -06001378 'section@1:offset': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001379 'section@1:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001380 'section@1:image-pos': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001381 'size': 40
1382 }, props)
1383
1384 def testUpdateFdtBad(self):
1385 """Test that we detect when ProcessFdt never completes"""
1386 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001387 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001388 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glass16287932020-04-17 18:09:03 -06001389 '[<binman.etype._testing.Entry__testing',
1390 str(e.exception))
Simon Glass5c890232018-07-06 10:27:19 -06001391
Simon Glass53af22a2018-07-17 13:25:32 -06001392 def testEntryArgs(self):
1393 """Test passing arguments to entries from the command line"""
1394 entry_args = {
1395 'test-str-arg': 'test1',
1396 'test-int-arg': '456',
1397 }
Simon Glass741f2d62018-10-01 12:22:30 -06001398 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001399 self.assertIn('image', control.images)
1400 entry = control.images['image'].GetEntries()['_testing']
1401 self.assertEqual('test0', entry.test_str_fdt)
1402 self.assertEqual('test1', entry.test_str_arg)
1403 self.assertEqual(123, entry.test_int_fdt)
1404 self.assertEqual(456, entry.test_int_arg)
1405
1406 def testEntryArgsMissing(self):
1407 """Test missing arguments and properties"""
1408 entry_args = {
1409 'test-int-arg': '456',
1410 }
Simon Glass741f2d62018-10-01 12:22:30 -06001411 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001412 entry = control.images['image'].GetEntries()['_testing']
1413 self.assertEqual('test0', entry.test_str_fdt)
1414 self.assertEqual(None, entry.test_str_arg)
1415 self.assertEqual(None, entry.test_int_fdt)
1416 self.assertEqual(456, entry.test_int_arg)
1417
1418 def testEntryArgsRequired(self):
1419 """Test missing arguments and properties"""
1420 entry_args = {
1421 'test-int-arg': '456',
1422 }
1423 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001424 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass3decfa32020-09-01 05:13:54 -06001425 self.assertIn("Node '/binman/_testing': "
1426 'Missing required properties/entry args: test-str-arg, '
1427 'test-int-fdt, test-int-arg',
Simon Glass53af22a2018-07-17 13:25:32 -06001428 str(e.exception))
1429
1430 def testEntryArgsInvalidFormat(self):
1431 """Test that an invalid entry-argument format is detected"""
Simon Glass53cd5d92019-07-08 14:25:29 -06001432 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1433 '-ano-value']
Simon Glass53af22a2018-07-17 13:25:32 -06001434 with self.assertRaises(ValueError) as e:
1435 self._DoBinman(*args)
1436 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1437
1438 def testEntryArgsInvalidInteger(self):
1439 """Test that an invalid entry-argument integer is detected"""
1440 entry_args = {
1441 'test-int-arg': 'abc',
1442 }
1443 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001444 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001445 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1446 "'test-int-arg' (value 'abc') to integer",
1447 str(e.exception))
1448
1449 def testEntryArgsInvalidDatatype(self):
1450 """Test that an invalid entry-argument datatype is detected
1451
1452 This test could be written in entry_test.py except that it needs
1453 access to control.entry_args, which seems more than that module should
1454 be able to see.
1455 """
1456 entry_args = {
1457 'test-bad-datatype-arg': '12',
1458 }
1459 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001460 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass53af22a2018-07-17 13:25:32 -06001461 entry_args=entry_args)
1462 self.assertIn('GetArg() internal error: Unknown data type ',
1463 str(e.exception))
1464
Simon Glassbb748372018-07-17 13:25:33 -06001465 def testText(self):
1466 """Test for a text entry type"""
1467 entry_args = {
1468 'test-id': TEXT_DATA,
1469 'test-id2': TEXT_DATA2,
1470 'test-id3': TEXT_DATA3,
1471 }
Simon Glass741f2d62018-10-01 12:22:30 -06001472 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glassbb748372018-07-17 13:25:33 -06001473 entry_args=entry_args)
Simon Glassc6c10e72019-05-17 22:00:46 -06001474 expected = (tools.ToBytes(TEXT_DATA) +
1475 tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1476 tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
Simon Glassaa88b502019-07-08 13:18:40 -06001477 b'some text' + b'more text')
Simon Glassbb748372018-07-17 13:25:33 -06001478 self.assertEqual(expected, data)
1479
Simon Glassfd8d1f72018-07-17 13:25:36 -06001480 def testEntryDocs(self):
1481 """Test for creation of entry documentation"""
1482 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass87d43322020-08-05 13:27:46 -06001483 control.WriteEntryDocs(control.GetEntryModules())
Simon Glassfd8d1f72018-07-17 13:25:36 -06001484 self.assertTrue(len(stdout.getvalue()) > 0)
1485
1486 def testEntryDocsMissing(self):
1487 """Test handling of missing entry documentation"""
1488 with self.assertRaises(ValueError) as e:
1489 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass87d43322020-08-05 13:27:46 -06001490 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glassfd8d1f72018-07-17 13:25:36 -06001491 self.assertIn('Documentation is missing for modules: u_boot',
1492 str(e.exception))
1493
Simon Glass11e36cc2018-07-17 13:25:38 -06001494 def testFmap(self):
1495 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001496 data = self._DoReadFile('067_fmap.dts')
Simon Glass11e36cc2018-07-17 13:25:38 -06001497 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc6c10e72019-05-17 22:00:46 -06001498 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1499 U_BOOT_DATA + tools.GetBytes(ord('a'), 12))
Simon Glass11e36cc2018-07-17 13:25:38 -06001500 self.assertEqual(expected, data[:32])
Simon Glassc6c10e72019-05-17 22:00:46 -06001501 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass11e36cc2018-07-17 13:25:38 -06001502 self.assertEqual(1, fhdr.ver_major)
1503 self.assertEqual(0, fhdr.ver_minor)
1504 self.assertEqual(0, fhdr.base)
1505 self.assertEqual(16 + 16 +
1506 fmap_util.FMAP_HEADER_LEN +
1507 fmap_util.FMAP_AREA_LEN * 3, fhdr.image_size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001508 self.assertEqual(b'FMAP', fhdr.name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001509 self.assertEqual(3, fhdr.nareas)
1510 for fentry in fentries:
1511 self.assertEqual(0, fentry.flags)
1512
1513 self.assertEqual(0, fentries[0].offset)
1514 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001515 self.assertEqual(b'RO_U_BOOT', fentries[0].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001516
1517 self.assertEqual(16, fentries[1].offset)
1518 self.assertEqual(4, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001519 self.assertEqual(b'RW_U_BOOT', fentries[1].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001520
1521 self.assertEqual(32, fentries[2].offset)
1522 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1523 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001524 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001525
Simon Glassec127af2018-07-17 13:25:39 -06001526 def testBlobNamedByArg(self):
1527 """Test we can add a blob with the filename coming from an entry arg"""
1528 entry_args = {
1529 'cros-ec-rw-path': 'ecrw.bin',
1530 }
Simon Glass3decfa32020-09-01 05:13:54 -06001531 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassec127af2018-07-17 13:25:39 -06001532
Simon Glass3af8e492018-07-17 13:25:40 -06001533 def testFill(self):
1534 """Test for an fill entry type"""
Simon Glass741f2d62018-10-01 12:22:30 -06001535 data = self._DoReadFile('069_fill.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001536 expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
Simon Glass3af8e492018-07-17 13:25:40 -06001537 self.assertEqual(expected, data)
1538
1539 def testFillNoSize(self):
1540 """Test for an fill entry type with no size"""
1541 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001542 self._DoReadFile('070_fill_no_size.dts')
Simon Glass3af8e492018-07-17 13:25:40 -06001543 self.assertIn("'fill' entry must have a size property",
1544 str(e.exception))
1545
Simon Glass0ef87aa2018-07-17 13:25:44 -06001546 def _HandleGbbCommand(self, pipe_list):
1547 """Fake calls to the futility utility"""
1548 if pipe_list[0][0] == 'futility':
1549 fname = pipe_list[0][-1]
1550 # Append our GBB data to the file, which will happen every time the
1551 # futility command is called.
Simon Glass1d0ebf72019-05-14 15:53:42 -06001552 with open(fname, 'ab') as fd:
Simon Glass0ef87aa2018-07-17 13:25:44 -06001553 fd.write(GBB_DATA)
1554 return command.CommandResult()
1555
1556 def testGbb(self):
1557 """Test for the Chromium OS Google Binary Block"""
1558 command.test_result = self._HandleGbbCommand
1559 entry_args = {
1560 'keydir': 'devkeys',
1561 'bmpblk': 'bmpblk.bin',
1562 }
Simon Glass741f2d62018-10-01 12:22:30 -06001563 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glass0ef87aa2018-07-17 13:25:44 -06001564
1565 # Since futility
Simon Glasse6d85ff2019-05-14 15:53:47 -06001566 expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1567 tools.GetBytes(0, 0x2180 - 16))
Simon Glass0ef87aa2018-07-17 13:25:44 -06001568 self.assertEqual(expected, data)
1569
1570 def testGbbTooSmall(self):
1571 """Test for the Chromium OS Google Binary Block being large enough"""
1572 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001573 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001574 self.assertIn("Node '/binman/gbb': GBB is too small",
1575 str(e.exception))
1576
1577 def testGbbNoSize(self):
1578 """Test for the Chromium OS Google Binary Block having a size"""
1579 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001580 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001581 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1582 str(e.exception))
1583
Simon Glass24d0d3c2018-07-17 13:25:47 -06001584 def _HandleVblockCommand(self, pipe_list):
1585 """Fake calls to the futility utility"""
1586 if pipe_list[0][0] == 'futility':
1587 fname = pipe_list[0][3]
Simon Glassa326b492018-09-14 04:57:11 -06001588 with open(fname, 'wb') as fd:
Simon Glass24d0d3c2018-07-17 13:25:47 -06001589 fd.write(VBLOCK_DATA)
1590 return command.CommandResult()
1591
1592 def testVblock(self):
1593 """Test for the Chromium OS Verified Boot Block"""
1594 command.test_result = self._HandleVblockCommand
1595 entry_args = {
1596 'keydir': 'devkeys',
1597 }
Simon Glass741f2d62018-10-01 12:22:30 -06001598 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass24d0d3c2018-07-17 13:25:47 -06001599 entry_args=entry_args)
1600 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1601 self.assertEqual(expected, data)
1602
1603 def testVblockNoContent(self):
1604 """Test we detect a vblock which has no content to sign"""
1605 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001606 self._DoReadFile('075_vblock_no_content.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001607 self.assertIn("Node '/binman/vblock': Vblock must have a 'content' "
1608 'property', str(e.exception))
1609
1610 def testVblockBadPhandle(self):
1611 """Test that we detect a vblock with an invalid phandle in contents"""
1612 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001613 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001614 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1615 '1000', str(e.exception))
1616
1617 def testVblockBadEntry(self):
1618 """Test that we detect an entry that points to a non-entry"""
1619 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001620 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001621 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1622 "'other'", str(e.exception))
1623
Simon Glassb8ef5b62018-07-17 13:25:48 -06001624 def testTpl(self):
Simon Glass2090f1e2019-08-24 07:23:00 -06001625 """Test that an image with TPL and its device tree can be created"""
Simon Glassb8ef5b62018-07-17 13:25:48 -06001626 # ELF file with a '__bss_size' symbol
Simon Glass2090f1e2019-08-24 07:23:00 -06001627 self._SetupTplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001628 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glassb8ef5b62018-07-17 13:25:48 -06001629 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1630
Simon Glass15a587c2018-07-17 13:25:51 -06001631 def testUsesPos(self):
1632 """Test that the 'pos' property cannot be used anymore"""
1633 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001634 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass15a587c2018-07-17 13:25:51 -06001635 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1636 "'pos'", str(e.exception))
1637
Simon Glassd178eab2018-09-14 04:57:08 -06001638 def testFillZero(self):
1639 """Test for an fill entry type with a size of 0"""
Simon Glass741f2d62018-10-01 12:22:30 -06001640 data = self._DoReadFile('080_fill_empty.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001641 self.assertEqual(tools.GetBytes(0, 16), data)
Simon Glassd178eab2018-09-14 04:57:08 -06001642
Simon Glass0b489362018-09-14 04:57:09 -06001643 def testTextMissing(self):
1644 """Test for a text entry type where there is no text"""
1645 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001646 self._DoReadFileDtb('066_text.dts',)
Simon Glass0b489362018-09-14 04:57:09 -06001647 self.assertIn("Node '/binman/text': No value provided for text label "
1648 "'test-id'", str(e.exception))
1649
Simon Glass35b384c2018-09-14 04:57:10 -06001650 def testPackStart16Tpl(self):
1651 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001652 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glass35b384c2018-09-14 04:57:10 -06001653 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1654
Simon Glass0bfa7b02018-09-14 04:57:12 -06001655 def testSelectImage(self):
1656 """Test that we can select which images to build"""
Simon Glasseb833d82019-04-25 21:58:34 -06001657 expected = 'Skipping images: image1'
Simon Glass0bfa7b02018-09-14 04:57:12 -06001658
Simon Glasseb833d82019-04-25 21:58:34 -06001659 # We should only get the expected message in verbose mode
Simon Glassee0c9a72019-07-08 13:18:48 -06001660 for verbosity in (0, 2):
Simon Glasseb833d82019-04-25 21:58:34 -06001661 with test_util.capture_sys_output() as (stdout, stderr):
1662 retcode = self._DoTestFile('006_dual_image.dts',
1663 verbosity=verbosity,
1664 images=['image2'])
1665 self.assertEqual(0, retcode)
1666 if verbosity:
1667 self.assertIn(expected, stdout.getvalue())
1668 else:
1669 self.assertNotIn(expected, stdout.getvalue())
1670
1671 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1672 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
Simon Glassf86a7362019-07-20 12:24:10 -06001673 self._CleanupOutputDir()
Simon Glass0bfa7b02018-09-14 04:57:12 -06001674
Simon Glass6ed45ba2018-09-14 04:57:24 -06001675 def testUpdateFdtAll(self):
1676 """Test that all device trees are updated with offset/size info"""
Simon Glass3c081312019-07-08 14:25:26 -06001677 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glass6ed45ba2018-09-14 04:57:24 -06001678
1679 base_expected = {
1680 'section:image-pos': 0,
1681 'u-boot-tpl-dtb:size': 513,
1682 'u-boot-spl-dtb:size': 513,
1683 'u-boot-spl-dtb:offset': 493,
1684 'image-pos': 0,
1685 'section/u-boot-dtb:image-pos': 0,
1686 'u-boot-spl-dtb:image-pos': 493,
1687 'section/u-boot-dtb:size': 493,
1688 'u-boot-tpl-dtb:image-pos': 1006,
1689 'section/u-boot-dtb:offset': 0,
1690 'section:size': 493,
1691 'offset': 0,
1692 'section:offset': 0,
1693 'u-boot-tpl-dtb:offset': 1006,
1694 'size': 1519
1695 }
1696
1697 # We expect three device-tree files in the output, one after the other.
1698 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1699 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1700 # main U-Boot tree. All three should have the same postions and offset.
1701 start = 0
1702 for item in ['', 'spl', 'tpl']:
1703 dtb = fdt.Fdt.FromData(data[start:])
1704 dtb.Scan()
Simon Glass12bb1a92019-07-20 12:23:51 -06001705 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
1706 ['spl', 'tpl'])
Simon Glass6ed45ba2018-09-14 04:57:24 -06001707 expected = dict(base_expected)
1708 if item:
1709 expected[item] = 0
1710 self.assertEqual(expected, props)
1711 start += dtb._fdt_obj.totalsize()
1712
1713 def testUpdateFdtOutput(self):
1714 """Test that output DTB files are updated"""
1715 try:
Simon Glass741f2d62018-10-01 12:22:30 -06001716 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glass6ed45ba2018-09-14 04:57:24 -06001717 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1718
1719 # Unfortunately, compiling a source file always results in a file
1720 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass741f2d62018-10-01 12:22:30 -06001721 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glass6ed45ba2018-09-14 04:57:24 -06001722 # binman as a file called u-boot.dtb. To fix this, copy the file
1723 # over to the expected place.
Simon Glass6ed45ba2018-09-14 04:57:24 -06001724 start = 0
1725 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1726 'tpl/u-boot-tpl.dtb.out']:
1727 dtb = fdt.Fdt.FromData(data[start:])
1728 size = dtb._fdt_obj.totalsize()
1729 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1730 outdata = tools.ReadFile(pathname)
1731 name = os.path.split(fname)[0]
1732
1733 if name:
1734 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1735 else:
1736 orig_indata = dtb_data
1737 self.assertNotEqual(outdata, orig_indata,
1738 "Expected output file '%s' be updated" % pathname)
1739 self.assertEqual(outdata, data[start:start + size],
1740 "Expected output file '%s' to match output image" %
1741 pathname)
1742 start += size
1743 finally:
1744 self._ResetDtbs()
1745
Simon Glass83d73c22018-09-14 04:57:26 -06001746 def _decompress(self, data):
Simon Glassff5c7e32019-07-08 13:18:42 -06001747 return tools.Decompress(data, 'lz4')
Simon Glass83d73c22018-09-14 04:57:26 -06001748
1749 def testCompress(self):
1750 """Test compression of blobs"""
Simon Glassac62fba2019-07-08 13:18:53 -06001751 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06001752 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass83d73c22018-09-14 04:57:26 -06001753 use_real_dtb=True, update_dtb=True)
1754 dtb = fdt.Fdt(out_dtb_fname)
1755 dtb.Scan()
1756 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1757 orig = self._decompress(data)
1758 self.assertEquals(COMPRESS_DATA, orig)
1759 expected = {
1760 'blob:uncomp-size': len(COMPRESS_DATA),
1761 'blob:size': len(data),
1762 'size': len(data),
1763 }
1764 self.assertEqual(expected, props)
1765
Simon Glass0a98b282018-09-14 04:57:28 -06001766 def testFiles(self):
1767 """Test bringing in multiple files"""
Simon Glass741f2d62018-10-01 12:22:30 -06001768 data = self._DoReadFile('084_files.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001769 self.assertEqual(FILES_DATA, data)
1770
1771 def testFilesCompress(self):
1772 """Test bringing in multiple files and compressing them"""
Simon Glassac62fba2019-07-08 13:18:53 -06001773 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06001774 data = self._DoReadFile('085_files_compress.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001775
1776 image = control.images['image']
1777 entries = image.GetEntries()
1778 files = entries['files']
Simon Glass8beb11e2019-07-08 14:25:47 -06001779 entries = files._entries
Simon Glass0a98b282018-09-14 04:57:28 -06001780
Simon Glassc6c10e72019-05-17 22:00:46 -06001781 orig = b''
Simon Glass0a98b282018-09-14 04:57:28 -06001782 for i in range(1, 3):
1783 key = '%d.dat' % i
1784 start = entries[key].image_pos
1785 len = entries[key].size
1786 chunk = data[start:start + len]
1787 orig += self._decompress(chunk)
1788
1789 self.assertEqual(FILES_DATA, orig)
1790
1791 def testFilesMissing(self):
1792 """Test missing files"""
1793 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001794 data = self._DoReadFile('086_files_none.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001795 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1796 'no files', str(e.exception))
1797
1798 def testFilesNoPattern(self):
1799 """Test missing files"""
1800 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001801 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001802 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1803 str(e.exception))
1804
Simon Glassba64a0b2018-09-14 04:57:29 -06001805 def testExpandSize(self):
1806 """Test an expanding entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001807 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
Simon Glassba64a0b2018-09-14 04:57:29 -06001808 map=True)
Simon Glassc6c10e72019-05-17 22:00:46 -06001809 expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA +
1810 MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA +
1811 tools.GetBytes(ord('c'), 8) + U_BOOT_DATA +
1812 tools.GetBytes(ord('d'), 8))
Simon Glassba64a0b2018-09-14 04:57:29 -06001813 self.assertEqual(expect, data)
1814 self.assertEqual('''ImagePos Offset Size Name
181500000000 00000000 00000028 main-section
181600000000 00000000 00000008 fill
181700000008 00000008 00000004 u-boot
18180000000c 0000000c 00000004 section
18190000000c 00000000 00000003 intel-mrc
182000000010 00000010 00000004 u-boot2
182100000014 00000014 0000000c section2
182200000014 00000000 00000008 fill
18230000001c 00000008 00000004 u-boot
182400000020 00000020 00000008 fill2
1825''', map_data)
1826
1827 def testExpandSizeBad(self):
1828 """Test an expanding entry which fails to provide contents"""
Simon Glass163ed6c2018-09-14 04:57:36 -06001829 with test_util.capture_sys_output() as (stdout, stderr):
1830 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001831 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
Simon Glassba64a0b2018-09-14 04:57:29 -06001832 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
1833 'expanding entry', str(e.exception))
1834
Simon Glasse0e5df92018-09-14 04:57:31 -06001835 def testHash(self):
1836 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001837 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06001838 use_real_dtb=True, update_dtb=True)
1839 dtb = fdt.Fdt(out_dtb_fname)
1840 dtb.Scan()
1841 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
1842 m = hashlib.sha256()
1843 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001844 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06001845
1846 def testHashNoAlgo(self):
1847 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001848 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06001849 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
1850 'hash node', str(e.exception))
1851
1852 def testHashBadAlgo(self):
1853 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001854 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06001855 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
1856 str(e.exception))
1857
1858 def testHashSection(self):
1859 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001860 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06001861 use_real_dtb=True, update_dtb=True)
1862 dtb = fdt.Fdt(out_dtb_fname)
1863 dtb.Scan()
1864 hash_node = dtb.GetNode('/binman/section/hash').props['value']
1865 m = hashlib.sha256()
1866 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001867 m.update(tools.GetBytes(ord('a'), 16))
1868 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06001869
Simon Glassf0253632018-09-14 04:57:32 -06001870 def testPackUBootTplMicrocode(self):
1871 """Test that x86 microcode can be handled correctly in TPL
1872
1873 We expect to see the following in the image, in order:
1874 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
1875 place
1876 u-boot-tpl.dtb with the microcode removed
1877 the microcode
1878 """
Simon Glass2090f1e2019-08-24 07:23:00 -06001879 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass741f2d62018-10-01 12:22:30 -06001880 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glassf0253632018-09-14 04:57:32 -06001881 U_BOOT_TPL_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001882 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
1883 b'ter somewhere in here', first)
Simon Glassf0253632018-09-14 04:57:32 -06001884
Simon Glassf8f8df62018-09-14 04:57:34 -06001885 def testFmapX86(self):
1886 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001887 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassf8f8df62018-09-14 04:57:34 -06001888 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc6c10e72019-05-17 22:00:46 -06001889 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06001890 self.assertEqual(expected, data[:32])
1891 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1892
1893 self.assertEqual(0x100, fhdr.image_size)
1894
1895 self.assertEqual(0, fentries[0].offset)
1896 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001897 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001898
1899 self.assertEqual(4, fentries[1].offset)
1900 self.assertEqual(3, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001901 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001902
1903 self.assertEqual(32, fentries[2].offset)
1904 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1905 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001906 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001907
1908 def testFmapX86Section(self):
1909 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001910 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glassc6c10e72019-05-17 22:00:46 -06001911 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06001912 self.assertEqual(expected, data[:32])
1913 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
1914
1915 self.assertEqual(0x100, fhdr.image_size)
1916
1917 self.assertEqual(0, fentries[0].offset)
1918 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001919 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001920
1921 self.assertEqual(4, fentries[1].offset)
1922 self.assertEqual(3, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001923 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001924
1925 self.assertEqual(36, fentries[2].offset)
1926 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1927 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001928 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001929
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001930 def testElf(self):
1931 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001932 self._SetupSplElf()
Simon Glass2090f1e2019-08-24 07:23:00 -06001933 self._SetupTplElf()
Simon Glass53e22bf2019-08-24 07:22:53 -06001934 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001935 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001936 data = self._DoReadFile('096_elf.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001937
Simon Glass093d1682019-07-08 13:18:25 -06001938 def testElfStrip(self):
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001939 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001940 self._SetupSplElf()
Simon Glass53e22bf2019-08-24 07:22:53 -06001941 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001942 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001943 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001944
Simon Glass163ed6c2018-09-14 04:57:36 -06001945 def testPackOverlapMap(self):
1946 """Test that overlapping regions are detected"""
1947 with test_util.capture_sys_output() as (stdout, stderr):
1948 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001949 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glass163ed6c2018-09-14 04:57:36 -06001950 map_fname = tools.GetOutputFilename('image.map')
1951 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
1952 stdout.getvalue())
1953
1954 # We should not get an inmage, but there should be a map file
1955 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
1956 self.assertTrue(os.path.exists(map_fname))
Simon Glasseb546ac2019-05-17 22:00:51 -06001957 map_data = tools.ReadFile(map_fname, binary=False)
Simon Glass163ed6c2018-09-14 04:57:36 -06001958 self.assertEqual('''ImagePos Offset Size Name
1959<none> 00000000 00000007 main-section
1960<none> 00000000 00000004 u-boot
1961<none> 00000003 00000004 u-boot-align
1962''', map_data)
1963
Simon Glass093d1682019-07-08 13:18:25 -06001964 def testPackRefCode(self):
Simon Glass3ae192c2018-10-01 12:22:31 -06001965 """Test that an image with an Intel Reference code binary works"""
1966 data = self._DoReadFile('100_intel_refcode.dts')
1967 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
1968
Simon Glass9481c802019-04-25 21:58:39 -06001969 def testSectionOffset(self):
1970 """Tests use of a section with an offset"""
1971 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
1972 map=True)
1973 self.assertEqual('''ImagePos Offset Size Name
197400000000 00000000 00000038 main-section
197500000004 00000004 00000010 section@0
197600000004 00000000 00000004 u-boot
197700000018 00000018 00000010 section@1
197800000018 00000000 00000004 u-boot
19790000002c 0000002c 00000004 section@2
19800000002c 00000000 00000004 u-boot
1981''', map_data)
1982 self.assertEqual(data,
Simon Glasse6d85ff2019-05-14 15:53:47 -06001983 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1984 tools.GetBytes(0x21, 12) +
1985 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1986 tools.GetBytes(0x61, 12) +
1987 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1988 tools.GetBytes(0x26, 8))
Simon Glass9481c802019-04-25 21:58:39 -06001989
Simon Glassac62fba2019-07-08 13:18:53 -06001990 def testCbfsRaw(self):
1991 """Test base handling of a Coreboot Filesystem (CBFS)
1992
1993 The exact contents of the CBFS is verified by similar tests in
1994 cbfs_util_test.py. The tests here merely check that the files added to
1995 the CBFS can be found in the final image.
1996 """
1997 data = self._DoReadFile('102_cbfs_raw.dts')
1998 size = 0xb0
1999
2000 cbfs = cbfs_util.CbfsReader(data)
2001 self.assertEqual(size, cbfs.rom_size)
2002
2003 self.assertIn('u-boot-dtb', cbfs.files)
2004 cfile = cbfs.files['u-boot-dtb']
2005 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2006
2007 def testCbfsArch(self):
2008 """Test on non-x86 architecture"""
2009 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2010 size = 0x100
2011
2012 cbfs = cbfs_util.CbfsReader(data)
2013 self.assertEqual(size, cbfs.rom_size)
2014
2015 self.assertIn('u-boot-dtb', cbfs.files)
2016 cfile = cbfs.files['u-boot-dtb']
2017 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2018
2019 def testCbfsStage(self):
2020 """Tests handling of a Coreboot Filesystem (CBFS)"""
2021 if not elf.ELF_TOOLS:
2022 self.skipTest('Python elftools not available')
2023 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2024 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2025 size = 0xb0
2026
2027 data = self._DoReadFile('104_cbfs_stage.dts')
2028 cbfs = cbfs_util.CbfsReader(data)
2029 self.assertEqual(size, cbfs.rom_size)
2030
2031 self.assertIn('u-boot', cbfs.files)
2032 cfile = cbfs.files['u-boot']
2033 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2034
2035 def testCbfsRawCompress(self):
2036 """Test handling of compressing raw files"""
2037 self._CheckLz4()
2038 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2039 size = 0x140
2040
2041 cbfs = cbfs_util.CbfsReader(data)
2042 self.assertIn('u-boot', cbfs.files)
2043 cfile = cbfs.files['u-boot']
2044 self.assertEqual(COMPRESS_DATA, cfile.data)
2045
2046 def testCbfsBadArch(self):
2047 """Test handling of a bad architecture"""
2048 with self.assertRaises(ValueError) as e:
2049 self._DoReadFile('106_cbfs_bad_arch.dts')
2050 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2051
2052 def testCbfsNoSize(self):
2053 """Test handling of a missing size property"""
2054 with self.assertRaises(ValueError) as e:
2055 self._DoReadFile('107_cbfs_no_size.dts')
2056 self.assertIn('entry must have a size property', str(e.exception))
2057
2058 def testCbfsNoCOntents(self):
2059 """Test handling of a CBFS entry which does not provide contentsy"""
2060 with self.assertRaises(ValueError) as e:
2061 self._DoReadFile('108_cbfs_no_contents.dts')
2062 self.assertIn('Could not complete processing of contents',
2063 str(e.exception))
2064
2065 def testCbfsBadCompress(self):
2066 """Test handling of a bad architecture"""
2067 with self.assertRaises(ValueError) as e:
2068 self._DoReadFile('109_cbfs_bad_compress.dts')
2069 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2070 str(e.exception))
2071
2072 def testCbfsNamedEntries(self):
2073 """Test handling of named entries"""
2074 data = self._DoReadFile('110_cbfs_name.dts')
2075
2076 cbfs = cbfs_util.CbfsReader(data)
2077 self.assertIn('FRED', cbfs.files)
2078 cfile1 = cbfs.files['FRED']
2079 self.assertEqual(U_BOOT_DATA, cfile1.data)
2080
2081 self.assertIn('hello', cbfs.files)
2082 cfile2 = cbfs.files['hello']
2083 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2084
Simon Glassc5ac1382019-07-08 13:18:54 -06002085 def _SetupIfwi(self, fname):
2086 """Set up to run an IFWI test
2087
2088 Args:
2089 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2090 """
2091 self._SetupSplElf()
Simon Glass2090f1e2019-08-24 07:23:00 -06002092 self._SetupTplElf()
Simon Glassc5ac1382019-07-08 13:18:54 -06002093
2094 # Intel Integrated Firmware Image (IFWI) file
2095 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2096 data = fd.read()
2097 TestFunctional._MakeInputFile(fname,data)
2098
2099 def _CheckIfwi(self, data):
2100 """Check that an image with an IFWI contains the correct output
2101
2102 Args:
2103 data: Conents of output file
2104 """
2105 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
2106 if data[:0x1000] != expected_desc:
2107 self.fail('Expected descriptor binary at start of image')
2108
2109 # We expect to find the TPL wil in subpart IBBP entry IBBL
2110 image_fname = tools.GetOutputFilename('image.bin')
2111 tpl_fname = tools.GetOutputFilename('tpl.out')
2112 tools.RunIfwiTool(image_fname, tools.CMD_EXTRACT, fname=tpl_fname,
2113 subpart='IBBP', entry_name='IBBL')
2114
2115 tpl_data = tools.ReadFile(tpl_fname)
Simon Glasse95be632019-08-24 07:22:51 -06002116 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glassc5ac1382019-07-08 13:18:54 -06002117
2118 def testPackX86RomIfwi(self):
2119 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2120 self._SetupIfwi('fitimage.bin')
Simon Glass9255f3c2019-08-24 07:23:01 -06002121 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002122 self._CheckIfwi(data)
2123
2124 def testPackX86RomIfwiNoDesc(self):
2125 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2126 self._SetupIfwi('ifwi.bin')
Simon Glass9255f3c2019-08-24 07:23:01 -06002127 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002128 self._CheckIfwi(data)
2129
2130 def testPackX86RomIfwiNoData(self):
2131 """Test that an x86 ROM with IFWI handles missing data"""
2132 self._SetupIfwi('ifwi.bin')
2133 with self.assertRaises(ValueError) as e:
Simon Glass9255f3c2019-08-24 07:23:01 -06002134 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002135 self.assertIn('Could not complete processing of contents',
2136 str(e.exception))
Simon Glass53af22a2018-07-17 13:25:32 -06002137
Simon Glasse073d4e2019-07-08 13:18:56 -06002138 def testCbfsOffset(self):
2139 """Test a CBFS with files at particular offsets
2140
2141 Like all CFBS tests, this is just checking the logic that calls
2142 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2143 """
2144 data = self._DoReadFile('114_cbfs_offset.dts')
2145 size = 0x200
2146
2147 cbfs = cbfs_util.CbfsReader(data)
2148 self.assertEqual(size, cbfs.rom_size)
2149
2150 self.assertIn('u-boot', cbfs.files)
2151 cfile = cbfs.files['u-boot']
2152 self.assertEqual(U_BOOT_DATA, cfile.data)
2153 self.assertEqual(0x40, cfile.cbfs_offset)
2154
2155 self.assertIn('u-boot-dtb', cbfs.files)
2156 cfile2 = cbfs.files['u-boot-dtb']
2157 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2158 self.assertEqual(0x140, cfile2.cbfs_offset)
2159
Simon Glass086cec92019-07-08 14:25:27 -06002160 def testFdtmap(self):
2161 """Test an FDT map can be inserted in the image"""
2162 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2163 fdtmap_data = data[len(U_BOOT_DATA):]
2164 magic = fdtmap_data[:8]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002165 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass086cec92019-07-08 14:25:27 -06002166 self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
2167
2168 fdt_data = fdtmap_data[16:]
2169 dtb = fdt.Fdt.FromData(fdt_data)
2170 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002171 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass086cec92019-07-08 14:25:27 -06002172 self.assertEqual({
2173 'image-pos': 0,
2174 'offset': 0,
2175 'u-boot:offset': 0,
2176 'u-boot:size': len(U_BOOT_DATA),
2177 'u-boot:image-pos': 0,
2178 'fdtmap:image-pos': 4,
2179 'fdtmap:offset': 4,
2180 'fdtmap:size': len(fdtmap_data),
2181 'size': len(data),
2182 }, props)
2183
2184 def testFdtmapNoMatch(self):
2185 """Check handling of an FDT map when the section cannot be found"""
2186 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2187
2188 # Mangle the section name, which should cause a mismatch between the
2189 # correct FDT path and the one expected by the section
2190 image = control.images['image']
Simon Glasscf228942019-07-08 14:25:28 -06002191 image._node.path += '-suffix'
Simon Glass086cec92019-07-08 14:25:27 -06002192 entries = image.GetEntries()
2193 fdtmap = entries['fdtmap']
2194 with self.assertRaises(ValueError) as e:
2195 fdtmap._GetFdtmap()
2196 self.assertIn("Cannot locate node for path '/binman-suffix'",
2197 str(e.exception))
2198
Simon Glasscf228942019-07-08 14:25:28 -06002199 def testFdtmapHeader(self):
2200 """Test an FDT map and image header can be inserted in the image"""
2201 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2202 fdtmap_pos = len(U_BOOT_DATA)
2203 fdtmap_data = data[fdtmap_pos:]
2204 fdt_data = fdtmap_data[16:]
2205 dtb = fdt.Fdt.FromData(fdt_data)
2206 fdt_size = dtb.GetFdtObj().totalsize()
2207 hdr_data = data[-8:]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002208 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002209 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2210 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2211
2212 def testFdtmapHeaderStart(self):
2213 """Test an image header can be inserted at the image start"""
2214 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2215 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2216 hdr_data = data[:8]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002217 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002218 offset = struct.unpack('<I', hdr_data[4:])[0]
2219 self.assertEqual(fdtmap_pos, offset)
2220
2221 def testFdtmapHeaderPos(self):
2222 """Test an image header can be inserted at a chosen position"""
2223 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2224 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2225 hdr_data = data[0x80:0x88]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002226 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002227 offset = struct.unpack('<I', hdr_data[4:])[0]
2228 self.assertEqual(fdtmap_pos, offset)
2229
2230 def testHeaderMissingFdtmap(self):
2231 """Test an image header requires an fdtmap"""
2232 with self.assertRaises(ValueError) as e:
2233 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2234 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2235 str(e.exception))
2236
2237 def testHeaderNoLocation(self):
2238 """Test an image header with a no specified location is detected"""
2239 with self.assertRaises(ValueError) as e:
2240 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2241 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2242 str(e.exception))
2243
Simon Glassc52c9e72019-07-08 14:25:37 -06002244 def testEntryExpand(self):
2245 """Test expanding an entry after it is packed"""
2246 data = self._DoReadFile('121_entry_expand.dts')
Simon Glass79d3c582019-07-20 12:23:57 -06002247 self.assertEqual(b'aaa', data[:3])
2248 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2249 self.assertEqual(b'aaa', data[-3:])
Simon Glassc52c9e72019-07-08 14:25:37 -06002250
2251 def testEntryExpandBad(self):
2252 """Test expanding an entry after it is packed, twice"""
2253 with self.assertRaises(ValueError) as e:
2254 self._DoReadFile('122_entry_expand_twice.dts')
Simon Glass61ec04f2019-07-20 12:23:58 -06002255 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glassc52c9e72019-07-08 14:25:37 -06002256 str(e.exception))
2257
2258 def testEntryExpandSection(self):
2259 """Test expanding an entry within a section after it is packed"""
2260 data = self._DoReadFile('123_entry_expand_section.dts')
Simon Glass79d3c582019-07-20 12:23:57 -06002261 self.assertEqual(b'aaa', data[:3])
2262 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2263 self.assertEqual(b'aaa', data[-3:])
Simon Glassc52c9e72019-07-08 14:25:37 -06002264
Simon Glass6c223fd2019-07-08 14:25:38 -06002265 def testCompressDtb(self):
2266 """Test that compress of device-tree files is supported"""
2267 self._CheckLz4()
2268 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2269 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2270 comp_data = data[len(U_BOOT_DATA):]
2271 orig = self._decompress(comp_data)
2272 dtb = fdt.Fdt.FromData(orig)
2273 dtb.Scan()
2274 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2275 expected = {
2276 'u-boot:size': len(U_BOOT_DATA),
2277 'u-boot-dtb:uncomp-size': len(orig),
2278 'u-boot-dtb:size': len(comp_data),
2279 'size': len(data),
2280 }
2281 self.assertEqual(expected, props)
2282
Simon Glass69f7cb32019-07-08 14:25:41 -06002283 def testCbfsUpdateFdt(self):
2284 """Test that we can update the device tree with CBFS offset/size info"""
2285 self._CheckLz4()
2286 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2287 update_dtb=True)
2288 dtb = fdt.Fdt(out_dtb_fname)
2289 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002290 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass69f7cb32019-07-08 14:25:41 -06002291 del props['cbfs/u-boot:size']
2292 self.assertEqual({
2293 'offset': 0,
2294 'size': len(data),
2295 'image-pos': 0,
2296 'cbfs:offset': 0,
2297 'cbfs:size': len(data),
2298 'cbfs:image-pos': 0,
2299 'cbfs/u-boot:offset': 0x38,
2300 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2301 'cbfs/u-boot:image-pos': 0x38,
2302 'cbfs/u-boot-dtb:offset': 0xb8,
2303 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2304 'cbfs/u-boot-dtb:image-pos': 0xb8,
2305 }, props)
2306
Simon Glass8a1ad062019-07-08 14:25:42 -06002307 def testCbfsBadType(self):
2308 """Test an image header with a no specified location is detected"""
2309 with self.assertRaises(ValueError) as e:
2310 self._DoReadFile('126_cbfs_bad_type.dts')
2311 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2312
Simon Glass41b8ba02019-07-08 14:25:43 -06002313 def testList(self):
2314 """Test listing the files in an image"""
2315 self._CheckLz4()
2316 data = self._DoReadFile('127_list.dts')
2317 image = control.images['image']
2318 entries = image.BuildEntryList()
2319 self.assertEqual(7, len(entries))
2320
2321 ent = entries[0]
2322 self.assertEqual(0, ent.indent)
2323 self.assertEqual('main-section', ent.name)
2324 self.assertEqual('section', ent.etype)
2325 self.assertEqual(len(data), ent.size)
2326 self.assertEqual(0, ent.image_pos)
2327 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002328 self.assertEqual(0, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002329
2330 ent = entries[1]
2331 self.assertEqual(1, ent.indent)
2332 self.assertEqual('u-boot', ent.name)
2333 self.assertEqual('u-boot', ent.etype)
2334 self.assertEqual(len(U_BOOT_DATA), ent.size)
2335 self.assertEqual(0, ent.image_pos)
2336 self.assertEqual(None, ent.uncomp_size)
2337 self.assertEqual(0, ent.offset)
2338
2339 ent = entries[2]
2340 self.assertEqual(1, ent.indent)
2341 self.assertEqual('section', ent.name)
2342 self.assertEqual('section', ent.etype)
2343 section_size = ent.size
2344 self.assertEqual(0x100, ent.image_pos)
2345 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002346 self.assertEqual(0x100, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002347
2348 ent = entries[3]
2349 self.assertEqual(2, ent.indent)
2350 self.assertEqual('cbfs', ent.name)
2351 self.assertEqual('cbfs', ent.etype)
2352 self.assertEqual(0x400, ent.size)
2353 self.assertEqual(0x100, ent.image_pos)
2354 self.assertEqual(None, ent.uncomp_size)
2355 self.assertEqual(0, ent.offset)
2356
2357 ent = entries[4]
2358 self.assertEqual(3, ent.indent)
2359 self.assertEqual('u-boot', ent.name)
2360 self.assertEqual('u-boot', ent.etype)
2361 self.assertEqual(len(U_BOOT_DATA), ent.size)
2362 self.assertEqual(0x138, ent.image_pos)
2363 self.assertEqual(None, ent.uncomp_size)
2364 self.assertEqual(0x38, ent.offset)
2365
2366 ent = entries[5]
2367 self.assertEqual(3, ent.indent)
2368 self.assertEqual('u-boot-dtb', ent.name)
2369 self.assertEqual('text', ent.etype)
2370 self.assertGreater(len(COMPRESS_DATA), ent.size)
2371 self.assertEqual(0x178, ent.image_pos)
2372 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2373 self.assertEqual(0x78, ent.offset)
2374
2375 ent = entries[6]
2376 self.assertEqual(2, ent.indent)
2377 self.assertEqual('u-boot-dtb', ent.name)
2378 self.assertEqual('u-boot-dtb', ent.etype)
2379 self.assertEqual(0x500, ent.image_pos)
2380 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2381 dtb_size = ent.size
2382 # Compressing this data expands it since headers are added
2383 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2384 self.assertEqual(0x400, ent.offset)
2385
2386 self.assertEqual(len(data), 0x100 + section_size)
2387 self.assertEqual(section_size, 0x400 + dtb_size)
2388
Simon Glasse1925fa2019-07-08 14:25:44 -06002389 def testFindFdtmap(self):
2390 """Test locating an FDT map in an image"""
2391 self._CheckLz4()
2392 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2393 image = control.images['image']
2394 entries = image.GetEntries()
2395 entry = entries['fdtmap']
2396 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2397
2398 def testFindFdtmapMissing(self):
2399 """Test failing to locate an FDP map"""
2400 data = self._DoReadFile('005_simple.dts')
2401 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2402
Simon Glass2d260032019-07-08 14:25:45 -06002403 def testFindImageHeader(self):
2404 """Test locating a image header"""
2405 self._CheckLz4()
Simon Glassffded752019-07-08 14:25:46 -06002406 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002407 image = control.images['image']
2408 entries = image.GetEntries()
2409 entry = entries['fdtmap']
2410 # The header should point to the FDT map
2411 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2412
2413 def testFindImageHeaderStart(self):
2414 """Test locating a image header located at the start of an image"""
Simon Glassffded752019-07-08 14:25:46 -06002415 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002416 image = control.images['image']
2417 entries = image.GetEntries()
2418 entry = entries['fdtmap']
2419 # The header should point to the FDT map
2420 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2421
2422 def testFindImageHeaderMissing(self):
2423 """Test failing to locate an image header"""
2424 data = self._DoReadFile('005_simple.dts')
2425 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2426
Simon Glassffded752019-07-08 14:25:46 -06002427 def testReadImage(self):
2428 """Test reading an image and accessing its FDT map"""
2429 self._CheckLz4()
2430 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2431 image_fname = tools.GetOutputFilename('image.bin')
2432 orig_image = control.images['image']
2433 image = Image.FromFile(image_fname)
2434 self.assertEqual(orig_image.GetEntries().keys(),
2435 image.GetEntries().keys())
2436
2437 orig_entry = orig_image.GetEntries()['fdtmap']
2438 entry = image.GetEntries()['fdtmap']
2439 self.assertEquals(orig_entry.offset, entry.offset)
2440 self.assertEquals(orig_entry.size, entry.size)
2441 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2442
2443 def testReadImageNoHeader(self):
2444 """Test accessing an image's FDT map without an image header"""
2445 self._CheckLz4()
2446 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
2447 image_fname = tools.GetOutputFilename('image.bin')
2448 image = Image.FromFile(image_fname)
2449 self.assertTrue(isinstance(image, Image))
Simon Glass10f9d002019-07-20 12:23:50 -06002450 self.assertEqual('image', image.image_name[-5:])
Simon Glassffded752019-07-08 14:25:46 -06002451
2452 def testReadImageFail(self):
2453 """Test failing to read an image image's FDT map"""
2454 self._DoReadFile('005_simple.dts')
2455 image_fname = tools.GetOutputFilename('image.bin')
2456 with self.assertRaises(ValueError) as e:
2457 image = Image.FromFile(image_fname)
2458 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glasse073d4e2019-07-08 13:18:56 -06002459
Simon Glass61f564d2019-07-08 14:25:48 -06002460 def testListCmd(self):
2461 """Test listing the files in an image using an Fdtmap"""
2462 self._CheckLz4()
2463 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2464
2465 # lz4 compression size differs depending on the version
2466 image = control.images['image']
2467 entries = image.GetEntries()
2468 section_size = entries['section'].size
2469 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2470 fdtmap_offset = entries['fdtmap'].offset
2471
Simon Glassf86a7362019-07-20 12:24:10 -06002472 try:
2473 tmpdir, updated_fname = self._SetupImageInTmpdir()
2474 with test_util.capture_sys_output() as (stdout, stderr):
2475 self._DoBinman('ls', '-i', updated_fname)
2476 finally:
2477 shutil.rmtree(tmpdir)
Simon Glass61f564d2019-07-08 14:25:48 -06002478 lines = stdout.getvalue().splitlines()
2479 expected = [
2480'Name Image-pos Size Entry-type Offset Uncomp-size',
2481'----------------------------------------------------------------------',
2482'main-section 0 c00 section 0',
2483' u-boot 0 4 u-boot 0',
2484' section 100 %x section 100' % section_size,
2485' cbfs 100 400 cbfs 0',
2486' u-boot 138 4 u-boot 38',
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002487' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glass61f564d2019-07-08 14:25:48 -06002488' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002489' fdtmap %x 3bd fdtmap %x' %
Simon Glass61f564d2019-07-08 14:25:48 -06002490 (fdtmap_offset, fdtmap_offset),
2491' image-header bf8 8 image-header bf8',
2492 ]
2493 self.assertEqual(expected, lines)
2494
2495 def testListCmdFail(self):
2496 """Test failing to list an image"""
2497 self._DoReadFile('005_simple.dts')
Simon Glassf86a7362019-07-20 12:24:10 -06002498 try:
2499 tmpdir, updated_fname = self._SetupImageInTmpdir()
2500 with self.assertRaises(ValueError) as e:
2501 self._DoBinman('ls', '-i', updated_fname)
2502 finally:
2503 shutil.rmtree(tmpdir)
Simon Glass61f564d2019-07-08 14:25:48 -06002504 self.assertIn("Cannot find FDT map in image", str(e.exception))
2505
2506 def _RunListCmd(self, paths, expected):
2507 """List out entries and check the result
2508
2509 Args:
2510 paths: List of paths to pass to the list command
2511 expected: Expected list of filenames to be returned, in order
2512 """
2513 self._CheckLz4()
2514 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2515 image_fname = tools.GetOutputFilename('image.bin')
2516 image = Image.FromFile(image_fname)
2517 lines = image.GetListEntries(paths)[1]
2518 files = [line[0].strip() for line in lines[1:]]
2519 self.assertEqual(expected, files)
2520
2521 def testListCmdSection(self):
2522 """Test listing the files in a section"""
2523 self._RunListCmd(['section'],
2524 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2525
2526 def testListCmdFile(self):
2527 """Test listing a particular file"""
2528 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2529
2530 def testListCmdWildcard(self):
2531 """Test listing a wildcarded file"""
2532 self._RunListCmd(['*boot*'],
2533 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2534
2535 def testListCmdWildcardMulti(self):
2536 """Test listing a wildcarded file"""
2537 self._RunListCmd(['*cb*', '*head*'],
2538 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2539
2540 def testListCmdEmpty(self):
2541 """Test listing a wildcarded file"""
2542 self._RunListCmd(['nothing'], [])
2543
2544 def testListCmdPath(self):
2545 """Test listing the files in a sub-entry of a section"""
2546 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2547
Simon Glassf667e452019-07-08 14:25:50 -06002548 def _RunExtractCmd(self, entry_name, decomp=True):
2549 """Extract an entry from an image
2550
2551 Args:
2552 entry_name: Entry name to extract
2553 decomp: True to decompress the data if compressed, False to leave
2554 it in its raw uncompressed format
2555
2556 Returns:
2557 data from entry
2558 """
2559 self._CheckLz4()
2560 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2561 image_fname = tools.GetOutputFilename('image.bin')
2562 return control.ReadEntry(image_fname, entry_name, decomp)
2563
2564 def testExtractSimple(self):
2565 """Test extracting a single file"""
2566 data = self._RunExtractCmd('u-boot')
2567 self.assertEqual(U_BOOT_DATA, data)
2568
Simon Glass71ce0ba2019-07-08 14:25:52 -06002569 def testExtractSection(self):
2570 """Test extracting the files in a section"""
2571 data = self._RunExtractCmd('section')
2572 cbfs_data = data[:0x400]
2573 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002574 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass71ce0ba2019-07-08 14:25:52 -06002575 dtb_data = data[0x400:]
2576 dtb = self._decompress(dtb_data)
2577 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2578
2579 def testExtractCompressed(self):
2580 """Test extracting compressed data"""
2581 data = self._RunExtractCmd('section/u-boot-dtb')
2582 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2583
2584 def testExtractRaw(self):
2585 """Test extracting compressed data without decompressing it"""
2586 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2587 dtb = self._decompress(data)
2588 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2589
2590 def testExtractCbfs(self):
2591 """Test extracting CBFS data"""
2592 data = self._RunExtractCmd('section/cbfs/u-boot')
2593 self.assertEqual(U_BOOT_DATA, data)
2594
2595 def testExtractCbfsCompressed(self):
2596 """Test extracting CBFS compressed data"""
2597 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2598 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2599
2600 def testExtractCbfsRaw(self):
2601 """Test extracting CBFS compressed data without decompressing it"""
2602 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Simon Glasseb0f4a42019-07-20 12:24:06 -06002603 dtb = tools.Decompress(data, 'lzma', with_header=False)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002604 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2605
Simon Glassf667e452019-07-08 14:25:50 -06002606 def testExtractBadEntry(self):
2607 """Test extracting a bad section path"""
2608 with self.assertRaises(ValueError) as e:
2609 self._RunExtractCmd('section/does-not-exist')
2610 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2611 str(e.exception))
2612
2613 def testExtractMissingFile(self):
2614 """Test extracting file that does not exist"""
2615 with self.assertRaises(IOError) as e:
2616 control.ReadEntry('missing-file', 'name')
2617
2618 def testExtractBadFile(self):
2619 """Test extracting an invalid file"""
2620 fname = os.path.join(self._indir, 'badfile')
2621 tools.WriteFile(fname, b'')
2622 with self.assertRaises(ValueError) as e:
2623 control.ReadEntry(fname, 'name')
2624
Simon Glass71ce0ba2019-07-08 14:25:52 -06002625 def testExtractCmd(self):
2626 """Test extracting a file fron an image on the command line"""
2627 self._CheckLz4()
2628 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass71ce0ba2019-07-08 14:25:52 -06002629 fname = os.path.join(self._indir, 'output.extact')
Simon Glassf86a7362019-07-20 12:24:10 -06002630 try:
2631 tmpdir, updated_fname = self._SetupImageInTmpdir()
2632 with test_util.capture_sys_output() as (stdout, stderr):
2633 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2634 '-f', fname)
2635 finally:
2636 shutil.rmtree(tmpdir)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002637 data = tools.ReadFile(fname)
2638 self.assertEqual(U_BOOT_DATA, data)
2639
2640 def testExtractOneEntry(self):
2641 """Test extracting a single entry fron an image """
2642 self._CheckLz4()
2643 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2644 image_fname = tools.GetOutputFilename('image.bin')
2645 fname = os.path.join(self._indir, 'output.extact')
2646 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
2647 data = tools.ReadFile(fname)
2648 self.assertEqual(U_BOOT_DATA, data)
2649
2650 def _CheckExtractOutput(self, decomp):
2651 """Helper to test file output with and without decompression
2652
2653 Args:
2654 decomp: True to decompress entry data, False to output it raw
2655 """
2656 def _CheckPresent(entry_path, expect_data, expect_size=None):
2657 """Check and remove expected file
2658
2659 This checks the data/size of a file and removes the file both from
2660 the outfiles set and from the output directory. Once all files are
2661 processed, both the set and directory should be empty.
2662
2663 Args:
2664 entry_path: Entry path
2665 expect_data: Data to expect in file, or None to skip check
2666 expect_size: Size of data to expect in file, or None to skip
2667 """
2668 path = os.path.join(outdir, entry_path)
2669 data = tools.ReadFile(path)
2670 os.remove(path)
2671 if expect_data:
2672 self.assertEqual(expect_data, data)
2673 elif expect_size:
2674 self.assertEqual(expect_size, len(data))
2675 outfiles.remove(path)
2676
2677 def _CheckDirPresent(name):
2678 """Remove expected directory
2679
2680 This gives an error if the directory does not exist as expected
2681
2682 Args:
2683 name: Name of directory to remove
2684 """
2685 path = os.path.join(outdir, name)
2686 os.rmdir(path)
2687
2688 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2689 image_fname = tools.GetOutputFilename('image.bin')
2690 outdir = os.path.join(self._indir, 'extract')
2691 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2692
2693 # Create a set of all file that were output (should be 9)
2694 outfiles = set()
2695 for root, dirs, files in os.walk(outdir):
2696 outfiles |= set([os.path.join(root, fname) for fname in files])
2697 self.assertEqual(9, len(outfiles))
2698 self.assertEqual(9, len(einfos))
2699
2700 image = control.images['image']
2701 entries = image.GetEntries()
2702
2703 # Check the 9 files in various ways
2704 section = entries['section']
2705 section_entries = section.GetEntries()
2706 cbfs_entries = section_entries['cbfs'].GetEntries()
2707 _CheckPresent('u-boot', U_BOOT_DATA)
2708 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
2709 dtb_len = EXTRACT_DTB_SIZE
2710 if not decomp:
2711 dtb_len = cbfs_entries['u-boot-dtb'].size
2712 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
2713 if not decomp:
2714 dtb_len = section_entries['u-boot-dtb'].size
2715 _CheckPresent('section/u-boot-dtb', None, dtb_len)
2716
2717 fdtmap = entries['fdtmap']
2718 _CheckPresent('fdtmap', fdtmap.data)
2719 hdr = entries['image-header']
2720 _CheckPresent('image-header', hdr.data)
2721
2722 _CheckPresent('section/root', section.data)
2723 cbfs = section_entries['cbfs']
2724 _CheckPresent('section/cbfs/root', cbfs.data)
2725 data = tools.ReadFile(image_fname)
2726 _CheckPresent('root', data)
2727
2728 # There should be no files left. Remove all the directories to check.
2729 # If there are any files/dirs remaining, one of these checks will fail.
2730 self.assertEqual(0, len(outfiles))
2731 _CheckDirPresent('section/cbfs')
2732 _CheckDirPresent('section')
2733 _CheckDirPresent('')
2734 self.assertFalse(os.path.exists(outdir))
2735
2736 def testExtractAllEntries(self):
2737 """Test extracting all entries"""
2738 self._CheckLz4()
2739 self._CheckExtractOutput(decomp=True)
2740
2741 def testExtractAllEntriesRaw(self):
2742 """Test extracting all entries without decompressing them"""
2743 self._CheckLz4()
2744 self._CheckExtractOutput(decomp=False)
2745
2746 def testExtractSelectedEntries(self):
2747 """Test extracting some entries"""
2748 self._CheckLz4()
2749 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2750 image_fname = tools.GetOutputFilename('image.bin')
2751 outdir = os.path.join(self._indir, 'extract')
2752 einfos = control.ExtractEntries(image_fname, None, outdir,
2753 ['*cb*', '*head*'])
2754
2755 # File output is tested by testExtractAllEntries(), so just check that
2756 # the expected entries are selected
2757 names = [einfo.name for einfo in einfos]
2758 self.assertEqual(names,
2759 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2760
2761 def testExtractNoEntryPaths(self):
2762 """Test extracting some entries"""
2763 self._CheckLz4()
2764 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2765 image_fname = tools.GetOutputFilename('image.bin')
2766 with self.assertRaises(ValueError) as e:
2767 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassbb5edc12019-07-20 12:24:14 -06002768 self.assertIn('Must specify an entry path to write with -f',
Simon Glass71ce0ba2019-07-08 14:25:52 -06002769 str(e.exception))
2770
2771 def testExtractTooManyEntryPaths(self):
2772 """Test extracting some entries"""
2773 self._CheckLz4()
2774 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2775 image_fname = tools.GetOutputFilename('image.bin')
2776 with self.assertRaises(ValueError) as e:
2777 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassbb5edc12019-07-20 12:24:14 -06002778 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass71ce0ba2019-07-08 14:25:52 -06002779 str(e.exception))
2780
Simon Glasse2705fa2019-07-08 14:25:53 -06002781 def testPackAlignSection(self):
2782 """Test that sections can have alignment"""
2783 self._DoReadFile('131_pack_align_section.dts')
2784
2785 self.assertIn('image', control.images)
2786 image = control.images['image']
2787 entries = image.GetEntries()
2788 self.assertEqual(3, len(entries))
2789
2790 # First u-boot
2791 self.assertIn('u-boot', entries)
2792 entry = entries['u-boot']
2793 self.assertEqual(0, entry.offset)
2794 self.assertEqual(0, entry.image_pos)
2795 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2796 self.assertEqual(len(U_BOOT_DATA), entry.size)
2797
2798 # Section0
2799 self.assertIn('section0', entries)
2800 section0 = entries['section0']
2801 self.assertEqual(0x10, section0.offset)
2802 self.assertEqual(0x10, section0.image_pos)
2803 self.assertEqual(len(U_BOOT_DATA), section0.size)
2804
2805 # Second u-boot
2806 section_entries = section0.GetEntries()
2807 self.assertIn('u-boot', section_entries)
2808 entry = section_entries['u-boot']
2809 self.assertEqual(0, entry.offset)
2810 self.assertEqual(0x10, entry.image_pos)
2811 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2812 self.assertEqual(len(U_BOOT_DATA), entry.size)
2813
2814 # Section1
2815 self.assertIn('section1', entries)
2816 section1 = entries['section1']
2817 self.assertEqual(0x14, section1.offset)
2818 self.assertEqual(0x14, section1.image_pos)
2819 self.assertEqual(0x20, section1.size)
2820
2821 # Second u-boot
2822 section_entries = section1.GetEntries()
2823 self.assertIn('u-boot', section_entries)
2824 entry = section_entries['u-boot']
2825 self.assertEqual(0, entry.offset)
2826 self.assertEqual(0x14, entry.image_pos)
2827 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2828 self.assertEqual(len(U_BOOT_DATA), entry.size)
2829
2830 # Section2
2831 self.assertIn('section2', section_entries)
2832 section2 = section_entries['section2']
2833 self.assertEqual(0x4, section2.offset)
2834 self.assertEqual(0x18, section2.image_pos)
2835 self.assertEqual(4, section2.size)
2836
2837 # Third u-boot
2838 section_entries = section2.GetEntries()
2839 self.assertIn('u-boot', section_entries)
2840 entry = section_entries['u-boot']
2841 self.assertEqual(0, entry.offset)
2842 self.assertEqual(0x18, entry.image_pos)
2843 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2844 self.assertEqual(len(U_BOOT_DATA), entry.size)
2845
Simon Glass51014aa2019-07-20 12:23:56 -06002846 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
2847 dts='132_replace.dts'):
Simon Glass10f9d002019-07-20 12:23:50 -06002848 """Replace an entry in an image
2849
2850 This writes the entry data to update it, then opens the updated file and
2851 returns the value that it now finds there.
2852
2853 Args:
2854 entry_name: Entry name to replace
2855 data: Data to replace it with
2856 decomp: True to compress the data if needed, False if data is
2857 already compressed so should be used as is
Simon Glass51014aa2019-07-20 12:23:56 -06002858 allow_resize: True to allow entries to change size, False to raise
2859 an exception
Simon Glass10f9d002019-07-20 12:23:50 -06002860
2861 Returns:
2862 Tuple:
2863 data from entry
2864 data from fdtmap (excluding header)
Simon Glass51014aa2019-07-20 12:23:56 -06002865 Image object that was modified
Simon Glass10f9d002019-07-20 12:23:50 -06002866 """
Simon Glass51014aa2019-07-20 12:23:56 -06002867 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass10f9d002019-07-20 12:23:50 -06002868 update_dtb=True)[1]
2869
2870 self.assertIn('image', control.images)
2871 image = control.images['image']
2872 entries = image.GetEntries()
2873 orig_dtb_data = entries['u-boot-dtb'].data
2874 orig_fdtmap_data = entries['fdtmap'].data
2875
2876 image_fname = tools.GetOutputFilename('image.bin')
2877 updated_fname = tools.GetOutputFilename('image-updated.bin')
2878 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
Simon Glass51014aa2019-07-20 12:23:56 -06002879 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
2880 allow_resize)
Simon Glass10f9d002019-07-20 12:23:50 -06002881 data = control.ReadEntry(updated_fname, entry_name, decomp)
2882
Simon Glass51014aa2019-07-20 12:23:56 -06002883 # The DT data should not change unless resized:
2884 if not allow_resize:
2885 new_dtb_data = entries['u-boot-dtb'].data
2886 self.assertEqual(new_dtb_data, orig_dtb_data)
2887 new_fdtmap_data = entries['fdtmap'].data
2888 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass10f9d002019-07-20 12:23:50 -06002889
Simon Glass51014aa2019-07-20 12:23:56 -06002890 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass10f9d002019-07-20 12:23:50 -06002891
2892 def testReplaceSimple(self):
2893 """Test replacing a single file"""
2894 expected = b'x' * len(U_BOOT_DATA)
Simon Glass51014aa2019-07-20 12:23:56 -06002895 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
2896 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06002897 self.assertEqual(expected, data)
2898
2899 # Test that the state looks right. There should be an FDT for the fdtmap
2900 # that we jsut read back in, and it should match what we find in the
2901 # 'control' tables. Checking for an FDT that does not exist should
2902 # return None.
2903 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glass51014aa2019-07-20 12:23:56 -06002904 self.assertIsNotNone(path)
Simon Glass10f9d002019-07-20 12:23:50 -06002905 self.assertEqual(expected_fdtmap, fdtmap)
2906
2907 dtb = state.GetFdtForEtype('fdtmap')
2908 self.assertEqual(dtb.GetContents(), fdtmap)
2909
2910 missing_path, missing_fdtmap = state.GetFdtContents('missing')
2911 self.assertIsNone(missing_path)
2912 self.assertIsNone(missing_fdtmap)
2913
2914 missing_dtb = state.GetFdtForEtype('missing')
2915 self.assertIsNone(missing_dtb)
2916
2917 self.assertEqual('/binman', state.fdt_path_prefix)
2918
2919 def testReplaceResizeFail(self):
2920 """Test replacing a file by something larger"""
2921 expected = U_BOOT_DATA + b'x'
2922 with self.assertRaises(ValueError) as e:
Simon Glass51014aa2019-07-20 12:23:56 -06002923 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
2924 dts='139_replace_repack.dts')
Simon Glass10f9d002019-07-20 12:23:50 -06002925 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
2926 str(e.exception))
2927
2928 def testReplaceMulti(self):
2929 """Test replacing entry data where multiple images are generated"""
2930 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
2931 update_dtb=True)[0]
2932 expected = b'x' * len(U_BOOT_DATA)
2933 updated_fname = tools.GetOutputFilename('image-updated.bin')
2934 tools.WriteFile(updated_fname, data)
2935 entry_name = 'u-boot'
Simon Glass51014aa2019-07-20 12:23:56 -06002936 control.WriteEntry(updated_fname, entry_name, expected,
2937 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06002938 data = control.ReadEntry(updated_fname, entry_name)
2939 self.assertEqual(expected, data)
2940
2941 # Check the state looks right.
2942 self.assertEqual('/binman/image', state.fdt_path_prefix)
2943
2944 # Now check we can write the first image
2945 image_fname = tools.GetOutputFilename('first-image.bin')
2946 updated_fname = tools.GetOutputFilename('first-updated.bin')
2947 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
2948 entry_name = 'u-boot'
Simon Glass51014aa2019-07-20 12:23:56 -06002949 control.WriteEntry(updated_fname, entry_name, expected,
2950 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06002951 data = control.ReadEntry(updated_fname, entry_name)
2952 self.assertEqual(expected, data)
2953
2954 # Check the state looks right.
2955 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass8beb11e2019-07-08 14:25:47 -06002956
Simon Glass12bb1a92019-07-20 12:23:51 -06002957 def testUpdateFdtAllRepack(self):
2958 """Test that all device trees are updated with offset/size info"""
2959 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
2960 SECTION_SIZE = 0x300
2961 DTB_SIZE = 602
2962 FDTMAP_SIZE = 608
2963 base_expected = {
2964 'offset': 0,
2965 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
2966 'image-pos': 0,
2967 'section:offset': 0,
2968 'section:size': SECTION_SIZE,
2969 'section:image-pos': 0,
2970 'section/u-boot-dtb:offset': 4,
2971 'section/u-boot-dtb:size': 636,
2972 'section/u-boot-dtb:image-pos': 4,
2973 'u-boot-spl-dtb:offset': SECTION_SIZE,
2974 'u-boot-spl-dtb:size': DTB_SIZE,
2975 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
2976 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
2977 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
2978 'u-boot-tpl-dtb:size': DTB_SIZE,
2979 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
2980 'fdtmap:size': FDTMAP_SIZE,
2981 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
2982 }
2983 main_expected = {
2984 'section:orig-size': SECTION_SIZE,
2985 'section/u-boot-dtb:orig-offset': 4,
2986 }
2987
2988 # We expect three device-tree files in the output, with the first one
2989 # within a fixed-size section.
2990 # Read them in sequence. We look for an 'spl' property in the SPL tree,
2991 # and 'tpl' in the TPL tree, to make sure they are distinct from the
2992 # main U-Boot tree. All three should have the same positions and offset
2993 # except that the main tree should include the main_expected properties
2994 start = 4
2995 for item in ['', 'spl', 'tpl', None]:
2996 if item is None:
2997 start += 16 # Move past fdtmap header
2998 dtb = fdt.Fdt.FromData(data[start:])
2999 dtb.Scan()
3000 props = self._GetPropTree(dtb,
3001 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3002 prefix='/' if item is None else '/binman/')
3003 expected = dict(base_expected)
3004 if item:
3005 expected[item] = 0
3006 else:
3007 # Main DTB and fdtdec should include the 'orig-' properties
3008 expected.update(main_expected)
3009 # Helpful for debugging:
3010 #for prop in sorted(props):
3011 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3012 self.assertEqual(expected, props)
3013 if item == '':
3014 start = SECTION_SIZE
3015 else:
3016 start += dtb._fdt_obj.totalsize()
3017
Simon Glasseba1f0c2019-07-20 12:23:55 -06003018 def testFdtmapHeaderMiddle(self):
3019 """Test an FDT map in the middle of an image when it should be at end"""
3020 with self.assertRaises(ValueError) as e:
3021 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3022 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3023 str(e.exception))
3024
3025 def testFdtmapHeaderStartBad(self):
3026 """Test an FDT map in middle of an image when it should be at start"""
3027 with self.assertRaises(ValueError) as e:
3028 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3029 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3030 str(e.exception))
3031
3032 def testFdtmapHeaderEndBad(self):
3033 """Test an FDT map at the start of an image when it should be at end"""
3034 with self.assertRaises(ValueError) as e:
3035 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3036 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3037 str(e.exception))
3038
3039 def testFdtmapHeaderNoSize(self):
3040 """Test an image header at the end of an image with undefined size"""
3041 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3042
Simon Glass51014aa2019-07-20 12:23:56 -06003043 def testReplaceResize(self):
3044 """Test replacing a single file in an entry with a larger file"""
3045 expected = U_BOOT_DATA + b'x'
3046 data, _, image = self._RunReplaceCmd('u-boot', expected,
3047 dts='139_replace_repack.dts')
3048 self.assertEqual(expected, data)
3049
3050 entries = image.GetEntries()
3051 dtb_data = entries['u-boot-dtb'].data
3052 dtb = fdt.Fdt.FromData(dtb_data)
3053 dtb.Scan()
3054
3055 # The u-boot section should now be larger in the dtb
3056 node = dtb.GetNode('/binman/u-boot')
3057 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3058
3059 # Same for the fdtmap
3060 fdata = entries['fdtmap'].data
3061 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3062 fdtb.Scan()
3063 fnode = fdtb.GetNode('/u-boot')
3064 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3065
3066 def testReplaceResizeNoRepack(self):
3067 """Test replacing an entry with a larger file when not allowed"""
3068 expected = U_BOOT_DATA + b'x'
3069 with self.assertRaises(ValueError) as e:
3070 self._RunReplaceCmd('u-boot', expected)
3071 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3072 str(e.exception))
3073
Simon Glass61ec04f2019-07-20 12:23:58 -06003074 def testEntryShrink(self):
3075 """Test contracting an entry after it is packed"""
3076 try:
3077 state.SetAllowEntryContraction(True)
3078 data = self._DoReadFileDtb('140_entry_shrink.dts',
3079 update_dtb=True)[0]
3080 finally:
3081 state.SetAllowEntryContraction(False)
3082 self.assertEqual(b'a', data[:1])
3083 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3084 self.assertEqual(b'a', data[-1:])
3085
3086 def testEntryShrinkFail(self):
3087 """Test not being allowed to contract an entry after it is packed"""
3088 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3089
3090 # In this case there is a spare byte at the end of the data. The size of
3091 # the contents is only 1 byte but we still have the size before it
3092 # shrunk.
3093 self.assertEqual(b'a\0', data[:2])
3094 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3095 self.assertEqual(b'a\0', data[-2:])
3096
Simon Glass27145fd2019-07-20 12:24:01 -06003097 def testDescriptorOffset(self):
3098 """Test that the Intel descriptor is always placed at at the start"""
3099 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3100 image = control.images['image']
3101 entries = image.GetEntries()
3102 desc = entries['intel-descriptor']
3103 self.assertEqual(0xff800000, desc.offset);
3104 self.assertEqual(0xff800000, desc.image_pos);
3105
Simon Glasseb0f4a42019-07-20 12:24:06 -06003106 def testReplaceCbfs(self):
3107 """Test replacing a single file in CBFS without changing the size"""
3108 self._CheckLz4()
3109 expected = b'x' * len(U_BOOT_DATA)
3110 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3111 updated_fname = tools.GetOutputFilename('image-updated.bin')
3112 tools.WriteFile(updated_fname, data)
3113 entry_name = 'section/cbfs/u-boot'
3114 control.WriteEntry(updated_fname, entry_name, expected,
3115 allow_resize=True)
3116 data = control.ReadEntry(updated_fname, entry_name)
3117 self.assertEqual(expected, data)
3118
3119 def testReplaceResizeCbfs(self):
3120 """Test replacing a single file in CBFS with one of a different size"""
3121 self._CheckLz4()
3122 expected = U_BOOT_DATA + b'x'
3123 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3124 updated_fname = tools.GetOutputFilename('image-updated.bin')
3125 tools.WriteFile(updated_fname, data)
3126 entry_name = 'section/cbfs/u-boot'
3127 control.WriteEntry(updated_fname, entry_name, expected,
3128 allow_resize=True)
3129 data = control.ReadEntry(updated_fname, entry_name)
3130 self.assertEqual(expected, data)
3131
Simon Glassa6cb9952019-07-20 12:24:15 -06003132 def _SetupForReplace(self):
3133 """Set up some files to use to replace entries
3134
3135 This generates an image, copies it to a new file, extracts all the files
3136 in it and updates some of them
3137
3138 Returns:
3139 List
3140 Image filename
3141 Output directory
3142 Expected values for updated entries, each a string
3143 """
3144 data = self._DoReadFileRealDtb('143_replace_all.dts')
3145
3146 updated_fname = tools.GetOutputFilename('image-updated.bin')
3147 tools.WriteFile(updated_fname, data)
3148
3149 outdir = os.path.join(self._indir, 'extract')
3150 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3151
3152 expected1 = b'x' + U_BOOT_DATA + b'y'
3153 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3154 tools.WriteFile(u_boot_fname1, expected1)
3155
3156 expected2 = b'a' + U_BOOT_DATA + b'b'
3157 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
3158 tools.WriteFile(u_boot_fname2, expected2)
3159
3160 expected_text = b'not the same text'
3161 text_fname = os.path.join(outdir, 'text')
3162 tools.WriteFile(text_fname, expected_text)
3163
3164 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3165 dtb = fdt.FdtScan(dtb_fname)
3166 node = dtb.GetNode('/binman/text')
3167 node.AddString('my-property', 'the value')
3168 dtb.Sync(auto_resize=True)
3169 dtb.Flush()
3170
3171 return updated_fname, outdir, expected1, expected2, expected_text
3172
3173 def _CheckReplaceMultiple(self, entry_paths):
3174 """Handle replacing the contents of multiple entries
3175
3176 Args:
3177 entry_paths: List of entry paths to replace
3178
3179 Returns:
3180 List
3181 Dict of entries in the image:
3182 key: Entry name
3183 Value: Entry object
3184 Expected values for updated entries, each a string
3185 """
3186 updated_fname, outdir, expected1, expected2, expected_text = (
3187 self._SetupForReplace())
3188 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3189
3190 image = Image.FromFile(updated_fname)
3191 image.LoadData()
3192 return image.GetEntries(), expected1, expected2, expected_text
3193
3194 def testReplaceAll(self):
3195 """Test replacing the contents of all entries"""
3196 entries, expected1, expected2, expected_text = (
3197 self._CheckReplaceMultiple([]))
3198 data = entries['u-boot'].data
3199 self.assertEqual(expected1, data)
3200
3201 data = entries['u-boot2'].data
3202 self.assertEqual(expected2, data)
3203
3204 data = entries['text'].data
3205 self.assertEqual(expected_text, data)
3206
3207 # Check that the device tree is updated
3208 data = entries['u-boot-dtb'].data
3209 dtb = fdt.Fdt.FromData(data)
3210 dtb.Scan()
3211 node = dtb.GetNode('/binman/text')
3212 self.assertEqual('the value', node.props['my-property'].value)
3213
3214 def testReplaceSome(self):
3215 """Test replacing the contents of a few entries"""
3216 entries, expected1, expected2, expected_text = (
3217 self._CheckReplaceMultiple(['u-boot2', 'text']))
3218
3219 # This one should not change
3220 data = entries['u-boot'].data
3221 self.assertEqual(U_BOOT_DATA, data)
3222
3223 data = entries['u-boot2'].data
3224 self.assertEqual(expected2, data)
3225
3226 data = entries['text'].data
3227 self.assertEqual(expected_text, data)
3228
3229 def testReplaceCmd(self):
3230 """Test replacing a file fron an image on the command line"""
3231 self._DoReadFileRealDtb('143_replace_all.dts')
3232
3233 try:
3234 tmpdir, updated_fname = self._SetupImageInTmpdir()
3235
3236 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3237 expected = b'x' * len(U_BOOT_DATA)
3238 tools.WriteFile(fname, expected)
3239
3240 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
3241 data = tools.ReadFile(updated_fname)
3242 self.assertEqual(expected, data[:len(expected)])
3243 map_fname = os.path.join(tmpdir, 'image-updated.map')
3244 self.assertFalse(os.path.exists(map_fname))
3245 finally:
3246 shutil.rmtree(tmpdir)
3247
3248 def testReplaceCmdSome(self):
3249 """Test replacing some files fron an image on the command line"""
3250 updated_fname, outdir, expected1, expected2, expected_text = (
3251 self._SetupForReplace())
3252
3253 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3254 'u-boot2', 'text')
3255
3256 tools.PrepareOutputDir(None)
3257 image = Image.FromFile(updated_fname)
3258 image.LoadData()
3259 entries = image.GetEntries()
3260
3261 # This one should not change
3262 data = entries['u-boot'].data
3263 self.assertEqual(U_BOOT_DATA, data)
3264
3265 data = entries['u-boot2'].data
3266 self.assertEqual(expected2, data)
3267
3268 data = entries['text'].data
3269 self.assertEqual(expected_text, data)
3270
3271 def testReplaceMissing(self):
3272 """Test replacing entries where the file is missing"""
3273 updated_fname, outdir, expected1, expected2, expected_text = (
3274 self._SetupForReplace())
3275
3276 # Remove one of the files, to generate a warning
3277 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3278 os.remove(u_boot_fname1)
3279
3280 with test_util.capture_sys_output() as (stdout, stderr):
3281 control.ReplaceEntries(updated_fname, None, outdir, [])
3282 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass38fdb4c2020-07-09 18:39:39 -06003283 stderr.getvalue())
Simon Glassa6cb9952019-07-20 12:24:15 -06003284
3285 def testReplaceCmdMap(self):
3286 """Test replacing a file fron an image on the command line"""
3287 self._DoReadFileRealDtb('143_replace_all.dts')
3288
3289 try:
3290 tmpdir, updated_fname = self._SetupImageInTmpdir()
3291
3292 fname = os.path.join(self._indir, 'update-u-boot.bin')
3293 expected = b'x' * len(U_BOOT_DATA)
3294 tools.WriteFile(fname, expected)
3295
3296 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3297 '-f', fname, '-m')
3298 map_fname = os.path.join(tmpdir, 'image-updated.map')
3299 self.assertTrue(os.path.exists(map_fname))
3300 finally:
3301 shutil.rmtree(tmpdir)
3302
3303 def testReplaceNoEntryPaths(self):
3304 """Test replacing an entry without an entry path"""
3305 self._DoReadFileRealDtb('143_replace_all.dts')
3306 image_fname = tools.GetOutputFilename('image.bin')
3307 with self.assertRaises(ValueError) as e:
3308 control.ReplaceEntries(image_fname, 'fname', None, [])
3309 self.assertIn('Must specify an entry path to read with -f',
3310 str(e.exception))
3311
3312 def testReplaceTooManyEntryPaths(self):
3313 """Test extracting some entries"""
3314 self._DoReadFileRealDtb('143_replace_all.dts')
3315 image_fname = tools.GetOutputFilename('image.bin')
3316 with self.assertRaises(ValueError) as e:
3317 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3318 self.assertIn('Must specify exactly one entry path to write with -f',
3319 str(e.exception))
3320
Simon Glass2250ee62019-08-24 07:22:48 -06003321 def testPackReset16(self):
3322 """Test that an image with an x86 reset16 region can be created"""
3323 data = self._DoReadFile('144_x86_reset16.dts')
3324 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3325
3326 def testPackReset16Spl(self):
3327 """Test that an image with an x86 reset16-spl region can be created"""
3328 data = self._DoReadFile('145_x86_reset16_spl.dts')
3329 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3330
3331 def testPackReset16Tpl(self):
3332 """Test that an image with an x86 reset16-tpl region can be created"""
3333 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3334 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3335
Simon Glass5af12072019-08-24 07:22:50 -06003336 def testPackIntelFit(self):
3337 """Test that an image with an Intel FIT and pointer can be created"""
3338 data = self._DoReadFile('147_intel_fit.dts')
3339 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3340 fit = data[16:32];
3341 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3342 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3343
3344 image = control.images['image']
3345 entries = image.GetEntries()
3346 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3347 self.assertEqual(expected_ptr, ptr)
3348
3349 def testPackIntelFitMissing(self):
3350 """Test detection of a FIT pointer with not FIT region"""
3351 with self.assertRaises(ValueError) as e:
3352 self._DoReadFile('148_intel_fit_missing.dts')
3353 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3354 str(e.exception))
3355
Simon Glass7c150132019-11-06 17:22:44 -07003356 def _CheckSymbolsTplSection(self, dts, expected_vals):
3357 data = self._DoReadFile(dts)
3358 sym_values = struct.pack('<LQLL', *expected_vals)
Simon Glass2090f1e2019-08-24 07:23:00 -06003359 upto1 = 4 + len(U_BOOT_SPL_DATA)
Simon Glassb87064c2019-08-24 07:23:05 -06003360 expected1 = tools.GetBytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[20:]
Simon Glass2090f1e2019-08-24 07:23:00 -06003361 self.assertEqual(expected1, data[:upto1])
3362
3363 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Simon Glassb87064c2019-08-24 07:23:05 -06003364 expected2 = tools.GetBytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[20:]
Simon Glass2090f1e2019-08-24 07:23:00 -06003365 self.assertEqual(expected2, data[upto1:upto2])
3366
Simon Glasseb0086f2019-08-24 07:23:04 -06003367 upto3 = 0x34 + len(U_BOOT_DATA)
3368 expected3 = tools.GetBytes(0xff, 1) + U_BOOT_DATA
Simon Glass2090f1e2019-08-24 07:23:00 -06003369 self.assertEqual(expected3, data[upto2:upto3])
3370
Simon Glassb87064c2019-08-24 07:23:05 -06003371 expected4 = sym_values + U_BOOT_TPL_DATA[20:]
Simon Glass7c150132019-11-06 17:22:44 -07003372 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3373
3374 def testSymbolsTplSection(self):
3375 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3376 self._SetupSplElf('u_boot_binman_syms')
3377 self._SetupTplElf('u_boot_binman_syms')
3378 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
3379 [0x04, 0x1c, 0x10 + 0x34, 0x04])
3380
3381 def testSymbolsTplSectionX86(self):
3382 """Test binman can assign symbols in a section with end-at-4gb"""
3383 self._SetupSplElf('u_boot_binman_syms_x86')
3384 self._SetupTplElf('u_boot_binman_syms_x86')
3385 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
3386 [0xffffff04, 0xffffff1c, 0xffffff34,
3387 0x04])
Simon Glass2090f1e2019-08-24 07:23:00 -06003388
Simon Glassbf4d0e22019-08-24 07:23:03 -06003389 def testPackX86RomIfwiSectiom(self):
3390 """Test that a section can be placed in an IFWI region"""
3391 self._SetupIfwi('fitimage.bin')
3392 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3393 self._CheckIfwi(data)
3394
Simon Glassea0fff92019-08-24 07:23:07 -06003395 def testPackFspM(self):
3396 """Test that an image with a FSP memory-init binary can be created"""
3397 data = self._DoReadFile('152_intel_fsp_m.dts')
3398 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3399
Simon Glassbc6a88f2019-10-20 21:31:35 -06003400 def testPackFspS(self):
3401 """Test that an image with a FSP silicon-init binary can be created"""
3402 data = self._DoReadFile('153_intel_fsp_s.dts')
3403 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassea0fff92019-08-24 07:23:07 -06003404
Simon Glass998d1482019-10-20 21:31:36 -06003405 def testPackFspT(self):
3406 """Test that an image with a FSP temp-ram-init binary can be created"""
3407 data = self._DoReadFile('154_intel_fsp_t.dts')
3408 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3409
Simon Glass0dc706f2020-07-09 18:39:31 -06003410 def testMkimage(self):
3411 """Test using mkimage to build an image"""
3412 data = self._DoReadFile('156_mkimage.dts')
3413
3414 # Just check that the data appears in the file somewhere
3415 self.assertIn(U_BOOT_SPL_DATA, data)
3416
Simon Glassce867ad2020-07-09 18:39:36 -06003417 def testExtblob(self):
3418 """Test an image with an external blob"""
3419 data = self._DoReadFile('157_blob_ext.dts')
3420 self.assertEqual(REFCODE_DATA, data)
3421
3422 def testExtblobMissing(self):
3423 """Test an image with a missing external blob"""
3424 with self.assertRaises(ValueError) as e:
3425 self._DoReadFile('158_blob_ext_missing.dts')
3426 self.assertIn("Filename 'missing-file' not found in input path",
3427 str(e.exception))
3428
Simon Glass4f9f1052020-07-09 18:39:38 -06003429 def testExtblobMissingOk(self):
3430 """Test an image with an missing external blob that is allowed"""
Simon Glassb1cca952020-07-09 18:39:40 -06003431 with test_util.capture_sys_output() as (stdout, stderr):
3432 self._DoTestFile('158_blob_ext_missing.dts', allow_missing=True)
3433 err = stderr.getvalue()
3434 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
3435
3436 def testExtblobMissingOkSect(self):
3437 """Test an image with an missing external blob that is allowed"""
3438 with test_util.capture_sys_output() as (stdout, stderr):
3439 self._DoTestFile('159_blob_ext_missing_sect.dts',
3440 allow_missing=True)
3441 err = stderr.getvalue()
3442 self.assertRegex(err, "Image 'main-section'.*missing.*: "
3443 "blob-ext blob-ext2")
Simon Glass4f9f1052020-07-09 18:39:38 -06003444
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003445 def testPackX86RomMeMissingDesc(self):
3446 """Test that an missing Intel descriptor entry is allowed"""
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003447 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass52b10dd2020-07-25 15:11:19 -06003448 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003449 err = stderr.getvalue()
3450 self.assertRegex(err,
3451 "Image 'main-section'.*missing.*: intel-descriptor")
3452
3453 def testPackX86RomMissingIfwi(self):
3454 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3455 self._SetupIfwi('fitimage.bin')
3456 pathname = os.path.join(self._indir, 'fitimage.bin')
3457 os.remove(pathname)
3458 with test_util.capture_sys_output() as (stdout, stderr):
3459 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3460 err = stderr.getvalue()
3461 self.assertRegex(err, "Image 'main-section'.*missing.*: intel-ifwi")
3462
Simon Glassb3295fd2020-07-09 18:39:42 -06003463 def testPackOverlap(self):
3464 """Test that zero-size overlapping regions are ignored"""
3465 self._DoTestFile('160_pack_overlap_zero.dts')
3466
Simon Glassfdc34362020-07-09 18:39:45 -06003467 def testSimpleFit(self):
3468 """Test an image with a FIT inside"""
3469 data = self._DoReadFile('161_fit.dts')
3470 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3471 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3472 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3473
3474 # The data should be inside the FIT
3475 dtb = fdt.Fdt.FromData(fit_data)
3476 dtb.Scan()
3477 fnode = dtb.GetNode('/images/kernel')
3478 self.assertIn('data', fnode.props)
3479
3480 fname = os.path.join(self._indir, 'fit_data.fit')
3481 tools.WriteFile(fname, fit_data)
3482 out = tools.Run('dumpimage', '-l', fname)
3483
3484 # Check a few features to make sure the plumbing works. We don't need
3485 # to test the operation of mkimage or dumpimage here. First convert the
3486 # output into a dict where the keys are the fields printed by dumpimage
3487 # and the values are a list of values for each field
3488 lines = out.splitlines()
3489
3490 # Converts "Compression: gzip compressed" into two groups:
3491 # 'Compression' and 'gzip compressed'
3492 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3493 vals = collections.defaultdict(list)
3494 for line in lines:
3495 mat = re_line.match(line)
3496 vals[mat.group(1)].append(mat.group(2))
3497
3498 self.assertEquals('FIT description: test-desc', lines[0])
3499 self.assertIn('Created:', lines[1])
3500 self.assertIn('Image 0 (kernel)', vals)
3501 self.assertIn('Hash value', vals)
3502 data_sizes = vals.get('Data Size')
3503 self.assertIsNotNone(data_sizes)
3504 self.assertEqual(2, len(data_sizes))
3505 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
3506 self.assertEqual(len(U_BOOT_DATA), int(data_sizes[0].split()[0]))
3507 self.assertEqual(len(U_BOOT_SPL_DTB_DATA), int(data_sizes[1].split()[0]))
3508
3509 def testFitExternal(self):
Simon Glasse9d336d2020-09-01 05:13:55 -06003510 """Test an image with an FIT with external images"""
Simon Glassfdc34362020-07-09 18:39:45 -06003511 data = self._DoReadFile('162_fit_external.dts')
3512 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3513
3514 # The data should be outside the FIT
3515 dtb = fdt.Fdt.FromData(fit_data)
3516 dtb.Scan()
3517 fnode = dtb.GetNode('/images/kernel')
3518 self.assertNotIn('data', fnode.props)
Simon Glass12bb1a92019-07-20 12:23:51 -06003519
Alper Nebi Yasak8001d0b2020-08-31 12:58:18 +03003520 def testSectionIgnoreHashSignature(self):
3521 """Test that sections ignore hash, signature nodes for its data"""
3522 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
3523 expected = (U_BOOT_DATA + U_BOOT_DATA)
3524 self.assertEqual(expected, data)
3525
Alper Nebi Yasak3fdeb142020-08-31 12:58:19 +03003526 def testPadInSections(self):
3527 """Test pad-before, pad-after for entries in sections"""
3528 data = self._DoReadFile('166_pad_in_sections.dts')
3529 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
3530 U_BOOT_DATA + tools.GetBytes(ord('!'), 6) +
3531 U_BOOT_DATA)
3532 self.assertEqual(expected, data)
3533
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03003534 def testFitImageSubentryAlignment(self):
3535 """Test relative alignability of FIT image subentries"""
3536 entry_args = {
3537 'test-id': TEXT_DATA,
3538 }
3539 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
3540 entry_args=entry_args)
3541 dtb = fdt.Fdt.FromData(data)
3542 dtb.Scan()
3543
3544 node = dtb.GetNode('/images/kernel')
3545 data = dtb.GetProps(node)["data"].bytes
3546 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
3547 expected = (tools.GetBytes(0, 0x20) + U_BOOT_SPL_DATA +
3548 tools.GetBytes(0, align_pad) + U_BOOT_DATA)
3549 self.assertEqual(expected, data)
3550
3551 node = dtb.GetNode('/images/fdt-1')
3552 data = dtb.GetProps(node)["data"].bytes
3553 expected = (U_BOOT_SPL_DTB_DATA + tools.GetBytes(0, 20) +
3554 tools.ToBytes(TEXT_DATA) + tools.GetBytes(0, 30) +
3555 U_BOOT_DTB_DATA)
3556 self.assertEqual(expected, data)
3557
3558 def testFitExtblobMissingOk(self):
3559 """Test a FIT with a missing external blob that is allowed"""
3560 with test_util.capture_sys_output() as (stdout, stderr):
3561 self._DoTestFile('168_fit_missing_blob.dts',
3562 allow_missing=True)
3563 err = stderr.getvalue()
Simon Glassb2381432020-09-06 10:39:09 -06003564 self.assertRegex(err, "Image 'main-section'.*missing.*: atf-bl31")
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03003565
Simon Glass3decfa32020-09-01 05:13:54 -06003566 def testBlobNamedByArgMissing(self):
3567 """Test handling of a missing entry arg"""
3568 with self.assertRaises(ValueError) as e:
3569 self._DoReadFile('068_blob_named_by_arg.dts')
3570 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
3571 str(e.exception))
3572
Simon Glassdc2f81a2020-09-01 05:13:58 -06003573 def testPackBl31(self):
3574 """Test that an image with an ATF BL31 binary can be created"""
3575 data = self._DoReadFile('169_atf_bl31.dts')
3576 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
3577
Simon Glass6cf99532020-09-01 05:13:59 -06003578 def testFitFdt(self):
3579 """Test an image with an FIT with multiple FDT images"""
3580 def _CheckFdt(seq, expected_data):
3581 """Check the FDT nodes
3582
3583 Args:
3584 seq: Sequence number to check (0 or 1)
3585 expected_data: Expected contents of 'data' property
3586 """
3587 name = 'fdt-%d' % seq
3588 fnode = dtb.GetNode('/images/%s' % name)
3589 self.assertIsNotNone(fnode)
3590 self.assertEqual({'description','type', 'compression', 'data'},
3591 set(fnode.props.keys()))
3592 self.assertEqual(expected_data, fnode.props['data'].bytes)
3593 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
3594 fnode.props['description'].value)
3595
3596 def _CheckConfig(seq, expected_data):
3597 """Check the configuration nodes
3598
3599 Args:
3600 seq: Sequence number to check (0 or 1)
3601 expected_data: Expected contents of 'data' property
3602 """
3603 cnode = dtb.GetNode('/configurations')
3604 self.assertIn('default', cnode.props)
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003605 self.assertEqual('config-2', cnode.props['default'].value)
Simon Glass6cf99532020-09-01 05:13:59 -06003606
3607 name = 'config-%d' % seq
3608 fnode = dtb.GetNode('/configurations/%s' % name)
3609 self.assertIsNotNone(fnode)
3610 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
3611 set(fnode.props.keys()))
3612 self.assertEqual('conf-test-fdt%d.dtb' % seq,
3613 fnode.props['description'].value)
3614 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
3615
3616 entry_args = {
3617 'of-list': 'test-fdt1 test-fdt2',
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003618 'default-dt': 'test-fdt2',
Simon Glass6cf99532020-09-01 05:13:59 -06003619 }
3620 data = self._DoReadFileDtb(
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003621 '172_fit_fdt.dts',
Simon Glass6cf99532020-09-01 05:13:59 -06003622 entry_args=entry_args,
3623 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3624 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3625 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3626
3627 dtb = fdt.Fdt.FromData(fit_data)
3628 dtb.Scan()
3629 fnode = dtb.GetNode('/images/kernel')
3630 self.assertIn('data', fnode.props)
3631
3632 # Check all the properties in fdt-1 and fdt-2
3633 _CheckFdt(1, TEST_FDT1_DATA)
3634 _CheckFdt(2, TEST_FDT2_DATA)
3635
3636 # Check configurations
3637 _CheckConfig(1, TEST_FDT1_DATA)
3638 _CheckConfig(2, TEST_FDT2_DATA)
3639
3640 def testFitFdtMissingList(self):
3641 """Test handling of a missing 'of-list' entry arg"""
3642 with self.assertRaises(ValueError) as e:
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003643 self._DoReadFile('172_fit_fdt.dts')
Simon Glass6cf99532020-09-01 05:13:59 -06003644 self.assertIn("Generator node requires 'of-list' entry argument",
3645 str(e.exception))
3646
3647 def testFitFdtEmptyList(self):
3648 """Test handling of an empty 'of-list' entry arg"""
3649 entry_args = {
3650 'of-list': '',
3651 }
3652 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
3653
3654 def testFitFdtMissingProp(self):
3655 """Test handling of a missing 'fit,fdt-list' property"""
3656 with self.assertRaises(ValueError) as e:
3657 self._DoReadFile('171_fit_fdt_missing_prop.dts')
3658 self.assertIn("Generator node requires 'fit,fdt-list' property",
3659 str(e.exception))
Simon Glassdc2f81a2020-09-01 05:13:58 -06003660
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003661 def testFitFdtEmptyList(self):
3662 """Test handling of an empty 'of-list' entry arg"""
3663 entry_args = {
3664 'of-list': '',
3665 }
3666 data = self._DoReadFileDtb('172_fit_fdt.dts', entry_args=entry_args)[0]
3667
3668 def testFitFdtMissing(self):
3669 """Test handling of a missing 'default-dt' entry arg"""
3670 entry_args = {
3671 'of-list': 'test-fdt1 test-fdt2',
3672 }
3673 with self.assertRaises(ValueError) as e:
3674 self._DoReadFileDtb(
3675 '172_fit_fdt.dts',
3676 entry_args=entry_args,
3677 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3678 self.assertIn("Generated 'default' node requires default-dt entry argument",
3679 str(e.exception))
3680
3681 def testFitFdtNotInList(self):
3682 """Test handling of a default-dt that is not in the of-list"""
3683 entry_args = {
3684 'of-list': 'test-fdt1 test-fdt2',
3685 'default-dt': 'test-fdt3',
3686 }
3687 with self.assertRaises(ValueError) as e:
3688 self._DoReadFileDtb(
3689 '172_fit_fdt.dts',
3690 entry_args=entry_args,
3691 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3692 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
3693 str(e.exception))
3694
Simon Glassb2381432020-09-06 10:39:09 -06003695 def testFitExtblobMissingHelp(self):
3696 """Test display of help messages when an external blob is missing"""
3697 control.missing_blob_help = control._ReadMissingBlobHelp()
3698 control.missing_blob_help['wibble'] = 'Wibble test'
3699 control.missing_blob_help['another'] = 'Another test'
3700 with test_util.capture_sys_output() as (stdout, stderr):
3701 self._DoTestFile('168_fit_missing_blob.dts',
3702 allow_missing=True)
3703 err = stderr.getvalue()
3704
3705 # We can get the tag from the name, the type or the missing-msg
3706 # property. Check all three.
3707 self.assertIn('You may need to build ARM Trusted', err)
3708 self.assertIn('Wibble test', err)
3709 self.assertIn('Another test', err)
3710
Simon Glass204aa782020-09-06 10:35:32 -06003711 def testMissingBlob(self):
3712 """Test handling of a blob containing a missing file"""
3713 with self.assertRaises(ValueError) as e:
3714 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
3715 self.assertIn("Filename 'missing' not found in input path",
3716 str(e.exception))
3717
Simon Glass9fc60b42017-11-12 21:52:22 -07003718if __name__ == "__main__":
3719 unittest.main()