blob: b771b9d5df71c6cc6343bd1c5f1b5f1182801750 [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'
Simon Glassfb91d562020-09-06 10:35:33 -060080ENV_DATA = b'var1=1\nvar2="2"'
Simon Glass6cf99532020-09-01 05:13:59 -060081
82# Subdirectory of the input dir to use to put test FDTs
83TEST_FDT_SUBDIR = 'fdts'
Simon Glassec127af2018-07-17 13:25:39 -060084
Simon Glass6ccbfcd2019-07-20 12:23:47 -060085# The expected size for the device tree in some tests
Simon Glassf667e452019-07-08 14:25:50 -060086EXTRACT_DTB_SIZE = 0x3c9
87
Simon Glass6ccbfcd2019-07-20 12:23:47 -060088# Properties expected to be in the device tree when update_dtb is used
89BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
90
Simon Glass12bb1a92019-07-20 12:23:51 -060091# Extra properties expected to be in the device tree when allow-repack is used
92REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
93
Simon Glass4f443042016-11-25 20:15:52 -070094
95class TestFunctional(unittest.TestCase):
96 """Functional tests for binman
97
98 Most of these use a sample .dts file to build an image and then check
99 that it looks correct. The sample files are in the test/ subdirectory
100 and are numbered.
101
102 For each entry type a very small test file is created using fixed
103 string contents. This makes it easy to test that things look right, and
104 debug problems.
105
106 In some cases a 'real' file must be used - these are also supplied in
107 the test/ diurectory.
108 """
109 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600110 def setUpClass(cls):
Simon Glass4d5994f2017-11-12 21:52:20 -0700111 global entry
Simon Glass16287932020-04-17 18:09:03 -0600112 from binman import entry
Simon Glass4d5994f2017-11-12 21:52:20 -0700113
Simon Glass4f443042016-11-25 20:15:52 -0700114 # Handle the case where argv[0] is 'python'
Simon Glassb986b3b2019-08-24 07:22:43 -0600115 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
116 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
Simon Glass4f443042016-11-25 20:15:52 -0700117
118 # Create a temporary directory for input files
Simon Glassb986b3b2019-08-24 07:22:43 -0600119 cls._indir = tempfile.mkdtemp(prefix='binmant.')
Simon Glass4f443042016-11-25 20:15:52 -0700120
121 # Create some test files
122 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
123 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
124 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glassb8ef5b62018-07-17 13:25:48 -0600125 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700126 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -0700127 TestFunctional._MakeInputFile('me.bin', ME_DATA)
128 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glassb986b3b2019-08-24 07:22:43 -0600129 cls._ResetDtbs()
Simon Glass2250ee62019-08-24 07:22:48 -0600130
Jagdish Gediya9d368f32018-09-03 21:35:08 +0530131 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glass2250ee62019-08-24 07:22:48 -0600132
Simon Glass5e239182019-08-24 07:22:49 -0600133 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
134 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
Simon Glass87722132017-11-12 21:52:26 -0700135 X86_START16_SPL_DATA)
Simon Glass5e239182019-08-24 07:22:49 -0600136 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
Simon Glass35b384c2018-09-14 04:57:10 -0600137 X86_START16_TPL_DATA)
Simon Glass2250ee62019-08-24 07:22:48 -0600138
139 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
140 X86_RESET16_DATA)
141 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
142 X86_RESET16_SPL_DATA)
143 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
144 X86_RESET16_TPL_DATA)
145
Simon Glass4f443042016-11-25 20:15:52 -0700146 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass6b187df2017-11-12 21:52:27 -0700147 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
148 U_BOOT_SPL_NODTB_DATA)
Simon Glassf0253632018-09-14 04:57:32 -0600149 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
150 U_BOOT_TPL_NODTB_DATA)
Simon Glassda229092016-11-25 20:15:56 -0700151 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
152 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Meng59ea8c22017-08-15 22:41:54 -0700153 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassca4f4ff2017-11-12 21:52:28 -0700154 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassec127af2018-07-17 13:25:39 -0600155 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glass0ef87aa2018-07-17 13:25:44 -0600156 TestFunctional._MakeInputDir('devkeys')
157 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass3ae192c2018-10-01 12:22:31 -0600158 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glassea0fff92019-08-24 07:23:07 -0600159 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
Simon Glassbc6a88f2019-10-20 21:31:35 -0600160 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
Simon Glass998d1482019-10-20 21:31:36 -0600161 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700162
Simon Glass53e22bf2019-08-24 07:22:53 -0600163 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
164 elf_test.BuildElfTestFiles(cls._elf_testdir)
165
Simon Glasse0ff8552016-11-25 20:15:53 -0700166 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glassf514d8f2019-08-24 07:22:54 -0600167 TestFunctional._MakeInputFile('u-boot',
168 tools.ReadFile(cls.ElfTestFile('u_boot_ucode_ptr')))
Simon Glasse0ff8552016-11-25 20:15:53 -0700169
170 # Intel flash descriptor file
Simon Glass0ba4b3d2020-07-09 18:39:41 -0600171 cls._SetupDescriptor()
Simon Glasse0ff8552016-11-25 20:15:53 -0700172
Simon Glassb986b3b2019-08-24 07:22:43 -0600173 shutil.copytree(cls.TestFile('files'),
174 os.path.join(cls._indir, 'files'))
Simon Glass0a98b282018-09-14 04:57:28 -0600175
Simon Glass83d73c22018-09-14 04:57:26 -0600176 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
Simon Glassdc2f81a2020-09-01 05:13:58 -0600177 TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
Simon Glass83d73c22018-09-14 04:57:26 -0600178
Simon Glass6cf99532020-09-01 05:13:59 -0600179 # Add a few .dtb files for testing
180 TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR,
181 TEST_FDT1_DATA)
182 TestFunctional._MakeInputFile('%s/test-fdt2.dtb' % TEST_FDT_SUBDIR,
183 TEST_FDT2_DATA)
184
Simon Glassfb91d562020-09-06 10:35:33 -0600185 TestFunctional._MakeInputFile('env.txt', ENV_DATA)
186
Simon Glassac62fba2019-07-08 13:18:53 -0600187 # Travis-CI may have an old lz4
Simon Glassb986b3b2019-08-24 07:22:43 -0600188 cls.have_lz4 = True
Simon Glassac62fba2019-07-08 13:18:53 -0600189 try:
190 tools.Run('lz4', '--no-frame-crc', '-c',
Simon Glass3b3e3c02019-10-31 07:42:50 -0600191 os.path.join(cls._indir, 'u-boot.bin'), binary=True)
Simon Glassac62fba2019-07-08 13:18:53 -0600192 except:
Simon Glassb986b3b2019-08-24 07:22:43 -0600193 cls.have_lz4 = False
Simon Glassac62fba2019-07-08 13:18:53 -0600194
Simon Glass4f443042016-11-25 20:15:52 -0700195 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600196 def tearDownClass(cls):
Simon Glass4f443042016-11-25 20:15:52 -0700197 """Remove the temporary input directory and its contents"""
Simon Glassb986b3b2019-08-24 07:22:43 -0600198 if cls.preserve_indir:
199 print('Preserving input dir: %s' % cls._indir)
Simon Glassd5164a72019-07-08 13:18:49 -0600200 else:
Simon Glassb986b3b2019-08-24 07:22:43 -0600201 if cls._indir:
202 shutil.rmtree(cls._indir)
203 cls._indir = None
Simon Glass4f443042016-11-25 20:15:52 -0700204
Simon Glassd5164a72019-07-08 13:18:49 -0600205 @classmethod
Simon Glass8acce602019-07-08 13:18:50 -0600206 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
Simon Glass53cd5d92019-07-08 14:25:29 -0600207 toolpath=None, verbosity=None):
Simon Glassd5164a72019-07-08 13:18:49 -0600208 """Accept arguments controlling test execution
209
210 Args:
211 preserve_indir: Preserve the shared input directory used by all
212 tests in this class.
213 preserve_outdir: Preserve the output directories used by tests. Each
214 test has its own, so this is normally only useful when running a
215 single test.
Simon Glass8acce602019-07-08 13:18:50 -0600216 toolpath: ist of paths to use for tools
Simon Glassd5164a72019-07-08 13:18:49 -0600217 """
218 cls.preserve_indir = preserve_indir
219 cls.preserve_outdirs = preserve_outdirs
Simon Glass8acce602019-07-08 13:18:50 -0600220 cls.toolpath = toolpath
Simon Glass53cd5d92019-07-08 14:25:29 -0600221 cls.verbosity = verbosity
Simon Glassd5164a72019-07-08 13:18:49 -0600222
Simon Glassac62fba2019-07-08 13:18:53 -0600223 def _CheckLz4(self):
224 if not self.have_lz4:
225 self.skipTest('lz4 --no-frame-crc not available')
226
Simon Glassbf574f12019-07-20 12:24:09 -0600227 def _CleanupOutputDir(self):
228 """Remove the temporary output directory"""
229 if self.preserve_outdirs:
230 print('Preserving output dir: %s' % tools.outdir)
231 else:
232 tools._FinaliseForTest()
233
Simon Glass4f443042016-11-25 20:15:52 -0700234 def setUp(self):
235 # Enable this to turn on debugging output
236 # tout.Init(tout.DEBUG)
237 command.test_result = None
238
239 def tearDown(self):
240 """Remove the temporary output directory"""
Simon Glassbf574f12019-07-20 12:24:09 -0600241 self._CleanupOutputDir()
Simon Glass4f443042016-11-25 20:15:52 -0700242
Simon Glassf86a7362019-07-20 12:24:10 -0600243 def _SetupImageInTmpdir(self):
244 """Set up the output image in a new temporary directory
245
246 This is used when an image has been generated in the output directory,
247 but we want to run binman again. This will create a new output
248 directory and fail to delete the original one.
249
250 This creates a new temporary directory, copies the image to it (with a
251 new name) and removes the old output directory.
252
253 Returns:
254 Tuple:
255 Temporary directory to use
256 New image filename
257 """
258 image_fname = tools.GetOutputFilename('image.bin')
259 tmpdir = tempfile.mkdtemp(prefix='binman.')
260 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
261 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
262 self._CleanupOutputDir()
263 return tmpdir, updated_fname
264
Simon Glassb8ef5b62018-07-17 13:25:48 -0600265 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600266 def _ResetDtbs(cls):
Simon Glassb8ef5b62018-07-17 13:25:48 -0600267 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
268 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
269 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
270
Simon Glass4f443042016-11-25 20:15:52 -0700271 def _RunBinman(self, *args, **kwargs):
272 """Run binman using the command line
273
274 Args:
275 Arguments to pass, as a list of strings
276 kwargs: Arguments to pass to Command.RunPipe()
277 """
278 result = command.RunPipe([[self._binman_pathname] + list(args)],
279 capture=True, capture_stderr=True, raise_on_error=False)
280 if result.return_code and kwargs.get('raise_on_error', True):
281 raise Exception("Error running '%s': %s" % (' '.join(args),
282 result.stdout + result.stderr))
283 return result
284
Simon Glass53cd5d92019-07-08 14:25:29 -0600285 def _DoBinman(self, *argv):
Simon Glass4f443042016-11-25 20:15:52 -0700286 """Run binman using directly (in the same process)
287
288 Args:
289 Arguments to pass, as a list of strings
290 Returns:
291 Return value (0 for success)
292 """
Simon Glass53cd5d92019-07-08 14:25:29 -0600293 argv = list(argv)
294 args = cmdline.ParseArgs(argv)
295 args.pager = 'binman-invalid-pager'
296 args.build_dir = self._indir
Simon Glass4f443042016-11-25 20:15:52 -0700297
298 # For testing, you can force an increase in verbosity here
Simon Glass53cd5d92019-07-08 14:25:29 -0600299 # args.verbosity = tout.DEBUG
300 return control.Binman(args)
Simon Glass4f443042016-11-25 20:15:52 -0700301
Simon Glass53af22a2018-07-17 13:25:32 -0600302 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glasseb833d82019-04-25 21:58:34 -0600303 entry_args=None, images=None, use_real_dtb=False,
Simon Glass6cf99532020-09-01 05:13:59 -0600304 verbosity=None, allow_missing=False, extra_indirs=None):
Simon Glass4f443042016-11-25 20:15:52 -0700305 """Run binman with a given test file
306
307 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600308 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600309 debug: True to enable debugging output
Simon Glass3b0c3822018-06-01 09:38:20 -0600310 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600311 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600312 tree before packing it into the image
Simon Glass0bfa7b02018-09-14 04:57:12 -0600313 entry_args: Dict of entry args to supply to binman
314 key: arg name
315 value: value of that arg
316 images: List of image names to build
Simon Glasse9d336d2020-09-01 05:13:55 -0600317 use_real_dtb: True to use the test file as the contents of
318 the u-boot-dtb entry. Normally this is not needed and the
319 test contents (the U_BOOT_DTB_DATA string) can be used.
320 But in some test we need the real contents.
321 verbosity: Verbosity level to use (0-3, None=don't set it)
322 allow_missing: Set the '--allow-missing' flag so that missing
323 external binaries just produce a warning instead of an error
Simon Glass6cf99532020-09-01 05:13:59 -0600324 extra_indirs: Extra input directories to add using -I
Simon Glass4f443042016-11-25 20:15:52 -0700325 """
Simon Glass53cd5d92019-07-08 14:25:29 -0600326 args = []
Simon Glass7fe91732017-11-13 18:55:00 -0700327 if debug:
328 args.append('-D')
Simon Glass53cd5d92019-07-08 14:25:29 -0600329 if verbosity is not None:
330 args.append('-v%d' % verbosity)
331 elif self.verbosity:
332 args.append('-v%d' % self.verbosity)
333 if self.toolpath:
334 for path in self.toolpath:
335 args += ['--toolpath', path]
336 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass3b0c3822018-06-01 09:38:20 -0600337 if map:
338 args.append('-m')
Simon Glass16b8d6b2018-07-06 10:27:42 -0600339 if update_dtb:
Simon Glass2569e102019-07-08 13:18:47 -0600340 args.append('-u')
Simon Glass93d17412018-09-14 04:57:23 -0600341 if not use_real_dtb:
342 args.append('--fake-dtb')
Simon Glass53af22a2018-07-17 13:25:32 -0600343 if entry_args:
Simon Glass50979152019-05-14 15:53:41 -0600344 for arg, value in entry_args.items():
Simon Glass53af22a2018-07-17 13:25:32 -0600345 args.append('-a%s=%s' % (arg, value))
Simon Glass4f9f1052020-07-09 18:39:38 -0600346 if allow_missing:
347 args.append('-M')
Simon Glass0bfa7b02018-09-14 04:57:12 -0600348 if images:
349 for image in images:
350 args += ['-i', image]
Simon Glass6cf99532020-09-01 05:13:59 -0600351 if extra_indirs:
352 for indir in extra_indirs:
353 args += ['-I', indir]
Simon Glass7fe91732017-11-13 18:55:00 -0700354 return self._DoBinman(*args)
Simon Glass4f443042016-11-25 20:15:52 -0700355
356 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glasse0ff8552016-11-25 20:15:53 -0700357 """Set up a new test device-tree file
358
359 The given file is compiled and set up as the device tree to be used
360 for ths test.
361
362 Args:
363 fname: Filename of .dts file to read
Simon Glass7ae5f312018-06-01 09:38:19 -0600364 outfile: Output filename for compiled device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700365
366 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600367 Contents of device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700368 """
Simon Glassa004f292019-07-20 12:23:49 -0600369 tmpdir = tempfile.mkdtemp(prefix='binmant.')
370 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
Simon Glass1d0ebf72019-05-14 15:53:42 -0600371 with open(dtb, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700372 data = fd.read()
373 TestFunctional._MakeInputFile(outfile, data)
Simon Glassa004f292019-07-20 12:23:49 -0600374 shutil.rmtree(tmpdir)
Simon Glasse0e62752018-10-01 21:12:41 -0600375 return data
Simon Glass4f443042016-11-25 20:15:52 -0700376
Simon Glass6ed45ba2018-09-14 04:57:24 -0600377 def _GetDtbContentsForSplTpl(self, dtb_data, name):
378 """Create a version of the main DTB for SPL or SPL
379
380 For testing we don't actually have different versions of the DTB. With
381 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
382 we don't normally have any unwanted nodes.
383
384 We still want the DTBs for SPL and TPL to be different though, since
385 otherwise it is confusing to know which one we are looking at. So add
386 an 'spl' or 'tpl' property to the top-level node.
Simon Glasse9d336d2020-09-01 05:13:55 -0600387
388 Args:
389 dtb_data: dtb data to modify (this should be a value devicetree)
390 name: Name of a new property to add
391
392 Returns:
393 New dtb data with the property added
Simon Glass6ed45ba2018-09-14 04:57:24 -0600394 """
395 dtb = fdt.Fdt.FromData(dtb_data)
396 dtb.Scan()
397 dtb.GetNode('/binman').AddZeroProp(name)
398 dtb.Sync(auto_resize=True)
399 dtb.Pack()
400 return dtb.GetContents()
401
Simon Glass16b8d6b2018-07-06 10:27:42 -0600402 def _DoReadFileDtb(self, fname, use_real_dtb=False, map=False,
Simon Glass6cf99532020-09-01 05:13:59 -0600403 update_dtb=False, entry_args=None, reset_dtbs=True,
404 extra_indirs=None):
Simon Glass4f443042016-11-25 20:15:52 -0700405 """Run binman and return the resulting image
406
407 This runs binman with a given test file and then reads the resulting
408 output file. It is a shortcut function since most tests need to do
409 these steps.
410
411 Raises an assertion failure if binman returns a non-zero exit code.
412
413 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600414 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass4f443042016-11-25 20:15:52 -0700415 use_real_dtb: True to use the test file as the contents of
416 the u-boot-dtb entry. Normally this is not needed and the
417 test contents (the U_BOOT_DTB_DATA string) can be used.
418 But in some test we need the real contents.
Simon Glass3b0c3822018-06-01 09:38:20 -0600419 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600420 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600421 tree before packing it into the image
Simon Glasse9d336d2020-09-01 05:13:55 -0600422 entry_args: Dict of entry args to supply to binman
423 key: arg name
424 value: value of that arg
425 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
426 function. If reset_dtbs is True, then the original test dtb
427 is written back before this function finishes
Simon Glass6cf99532020-09-01 05:13:59 -0600428 extra_indirs: Extra input directories to add using -I
Simon Glasse0ff8552016-11-25 20:15:53 -0700429
430 Returns:
431 Tuple:
432 Resulting image contents
433 Device tree contents
Simon Glass3b0c3822018-06-01 09:38:20 -0600434 Map data showing contents of image (or None if none)
Simon Glassea6922e2018-07-17 13:25:27 -0600435 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass4f443042016-11-25 20:15:52 -0700436 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700437 dtb_data = None
Simon Glass4f443042016-11-25 20:15:52 -0700438 # Use the compiled test file as the u-boot-dtb input
439 if use_real_dtb:
Simon Glasse0ff8552016-11-25 20:15:53 -0700440 dtb_data = self._SetupDtb(fname)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600441
442 # For testing purposes, make a copy of the DT for SPL and TPL. Add
443 # a node indicating which it is, so aid verification.
444 for name in ['spl', 'tpl']:
445 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
446 outfile = os.path.join(self._indir, dtb_fname)
447 TestFunctional._MakeInputFile(dtb_fname,
448 self._GetDtbContentsForSplTpl(dtb_data, name))
Simon Glass4f443042016-11-25 20:15:52 -0700449
450 try:
Simon Glass53af22a2018-07-17 13:25:32 -0600451 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glass6cf99532020-09-01 05:13:59 -0600452 entry_args=entry_args, use_real_dtb=use_real_dtb,
453 extra_indirs=extra_indirs)
Simon Glass4f443042016-11-25 20:15:52 -0700454 self.assertEqual(0, retcode)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600455 out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
Simon Glass4f443042016-11-25 20:15:52 -0700456
457 # Find the (only) image, read it and return its contents
458 image = control.images['image']
Simon Glass16b8d6b2018-07-06 10:27:42 -0600459 image_fname = tools.GetOutputFilename('image.bin')
460 self.assertTrue(os.path.exists(image_fname))
Simon Glass3b0c3822018-06-01 09:38:20 -0600461 if map:
462 map_fname = tools.GetOutputFilename('image.map')
463 with open(map_fname) as fd:
464 map_data = fd.read()
465 else:
466 map_data = None
Simon Glass1d0ebf72019-05-14 15:53:42 -0600467 with open(image_fname, 'rb') as fd:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600468 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass4f443042016-11-25 20:15:52 -0700469 finally:
470 # Put the test file back
Simon Glass6ed45ba2018-09-14 04:57:24 -0600471 if reset_dtbs and use_real_dtb:
Simon Glassb8ef5b62018-07-17 13:25:48 -0600472 self._ResetDtbs()
Simon Glass4f443042016-11-25 20:15:52 -0700473
Simon Glass3c081312019-07-08 14:25:26 -0600474 def _DoReadFileRealDtb(self, fname):
475 """Run binman with a real .dtb file and return the resulting data
476
477 Args:
478 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
479
480 Returns:
481 Resulting image contents
482 """
483 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
484
Simon Glasse0ff8552016-11-25 20:15:53 -0700485 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass7ae5f312018-06-01 09:38:19 -0600486 """Helper function which discards the device-tree binary
487
488 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600489 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600490 use_real_dtb: True to use the test file as the contents of
491 the u-boot-dtb entry. Normally this is not needed and the
492 test contents (the U_BOOT_DTB_DATA string) can be used.
493 But in some test we need the real contents.
Simon Glassea6922e2018-07-17 13:25:27 -0600494
495 Returns:
496 Resulting image contents
Simon Glass7ae5f312018-06-01 09:38:19 -0600497 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700498 return self._DoReadFileDtb(fname, use_real_dtb)[0]
499
Simon Glass4f443042016-11-25 20:15:52 -0700500 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600501 def _MakeInputFile(cls, fname, contents):
Simon Glass4f443042016-11-25 20:15:52 -0700502 """Create a new test input file, creating directories as needed
503
504 Args:
Simon Glass3ab95982018-08-01 15:22:37 -0600505 fname: Filename to create
Simon Glass4f443042016-11-25 20:15:52 -0700506 contents: File contents to write in to the file
507 Returns:
508 Full pathname of file created
509 """
Simon Glassb986b3b2019-08-24 07:22:43 -0600510 pathname = os.path.join(cls._indir, fname)
Simon Glass4f443042016-11-25 20:15:52 -0700511 dirname = os.path.dirname(pathname)
512 if dirname and not os.path.exists(dirname):
513 os.makedirs(dirname)
514 with open(pathname, 'wb') as fd:
515 fd.write(contents)
516 return pathname
517
518 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600519 def _MakeInputDir(cls, dirname):
Simon Glass0ef87aa2018-07-17 13:25:44 -0600520 """Create a new test input directory, creating directories as needed
521
522 Args:
523 dirname: Directory name to create
524
525 Returns:
526 Full pathname of directory created
527 """
Simon Glassb986b3b2019-08-24 07:22:43 -0600528 pathname = os.path.join(cls._indir, dirname)
Simon Glass0ef87aa2018-07-17 13:25:44 -0600529 if not os.path.exists(pathname):
530 os.makedirs(pathname)
531 return pathname
532
533 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600534 def _SetupSplElf(cls, src_fname='bss_data'):
Simon Glass11ae93e2018-10-01 21:12:47 -0600535 """Set up an ELF file with a '_dt_ucode_base_size' symbol
536
537 Args:
538 Filename of ELF file to use as SPL
539 """
Simon Glassc9a0b272019-08-24 07:22:59 -0600540 TestFunctional._MakeInputFile('spl/u-boot-spl',
541 tools.ReadFile(cls.ElfTestFile(src_fname)))
Simon Glass11ae93e2018-10-01 21:12:47 -0600542
543 @classmethod
Simon Glass2090f1e2019-08-24 07:23:00 -0600544 def _SetupTplElf(cls, src_fname='bss_data'):
545 """Set up an ELF file with a '_dt_ucode_base_size' symbol
546
547 Args:
548 Filename of ELF file to use as TPL
549 """
550 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
551 tools.ReadFile(cls.ElfTestFile(src_fname)))
552
553 @classmethod
Simon Glass0ba4b3d2020-07-09 18:39:41 -0600554 def _SetupDescriptor(cls):
555 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
556 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
557
558 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600559 def TestFile(cls, fname):
560 return os.path.join(cls._binman_dir, 'test', fname)
Simon Glass4f443042016-11-25 20:15:52 -0700561
Simon Glass53e22bf2019-08-24 07:22:53 -0600562 @classmethod
563 def ElfTestFile(cls, fname):
564 return os.path.join(cls._elf_testdir, fname)
565
Simon Glass4f443042016-11-25 20:15:52 -0700566 def AssertInList(self, grep_list, target):
567 """Assert that at least one of a list of things is in a target
568
569 Args:
570 grep_list: List of strings to check
571 target: Target string
572 """
573 for grep in grep_list:
574 if grep in target:
575 return
Simon Glass1fc62de2019-05-17 22:00:50 -0600576 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass4f443042016-11-25 20:15:52 -0700577
578 def CheckNoGaps(self, entries):
579 """Check that all entries fit together without gaps
580
581 Args:
582 entries: List of entries to check
583 """
Simon Glass3ab95982018-08-01 15:22:37 -0600584 offset = 0
Simon Glass4f443042016-11-25 20:15:52 -0700585 for entry in entries.values():
Simon Glass3ab95982018-08-01 15:22:37 -0600586 self.assertEqual(offset, entry.offset)
587 offset += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700588
Simon Glasse0ff8552016-11-25 20:15:53 -0700589 def GetFdtLen(self, dtb):
Simon Glass7ae5f312018-06-01 09:38:19 -0600590 """Get the totalsize field from a device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700591
592 Args:
Simon Glass7ae5f312018-06-01 09:38:19 -0600593 dtb: Device-tree binary contents
Simon Glasse0ff8552016-11-25 20:15:53 -0700594
595 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600596 Total size of device-tree binary, from the header
Simon Glasse0ff8552016-11-25 20:15:53 -0700597 """
598 return struct.unpack('>L', dtb[4:8])[0]
599
Simon Glass086cec92019-07-08 14:25:27 -0600600 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glass16b8d6b2018-07-06 10:27:42 -0600601 def AddNode(node, path):
602 if node.name != '/':
603 path += '/' + node.name
Simon Glass086cec92019-07-08 14:25:27 -0600604 for prop in node.props.values():
605 if prop.name in prop_names:
606 prop_path = path + ':' + prop.name
607 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
608 prop.value)
Simon Glass16b8d6b2018-07-06 10:27:42 -0600609 for subnode in node.subnodes:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600610 AddNode(subnode, path)
611
612 tree = {}
Simon Glass16b8d6b2018-07-06 10:27:42 -0600613 AddNode(dtb.GetRoot(), '')
614 return tree
615
Simon Glass4f443042016-11-25 20:15:52 -0700616 def testRun(self):
617 """Test a basic run with valid args"""
618 result = self._RunBinman('-h')
619
620 def testFullHelp(self):
621 """Test that the full help is displayed with -H"""
622 result = self._RunBinman('-H')
623 help_file = os.path.join(self._binman_dir, 'README')
Tom Rini3759df02018-01-16 15:29:50 -0500624 # Remove possible extraneous strings
625 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
626 gothelp = result.stdout.replace(extra, '')
627 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass4f443042016-11-25 20:15:52 -0700628 self.assertEqual(0, len(result.stderr))
629 self.assertEqual(0, result.return_code)
630
631 def testFullHelpInternal(self):
632 """Test that the full help is displayed with -H"""
633 try:
634 command.test_result = command.CommandResult()
635 result = self._DoBinman('-H')
636 help_file = os.path.join(self._binman_dir, 'README')
637 finally:
638 command.test_result = None
639
640 def testHelp(self):
641 """Test that the basic help is displayed with -h"""
642 result = self._RunBinman('-h')
643 self.assertTrue(len(result.stdout) > 200)
644 self.assertEqual(0, len(result.stderr))
645 self.assertEqual(0, result.return_code)
646
Simon Glass4f443042016-11-25 20:15:52 -0700647 def testBoard(self):
648 """Test that we can run it with a specific board"""
Simon Glass741f2d62018-10-01 12:22:30 -0600649 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass4f443042016-11-25 20:15:52 -0700650 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glass53cd5d92019-07-08 14:25:29 -0600651 result = self._DoBinman('build', '-b', 'sandbox')
Simon Glass4f443042016-11-25 20:15:52 -0700652 self.assertEqual(0, result)
653
654 def testNeedBoard(self):
655 """Test that we get an error when no board ius supplied"""
656 with self.assertRaises(ValueError) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600657 result = self._DoBinman('build')
Simon Glass4f443042016-11-25 20:15:52 -0700658 self.assertIn("Must provide a board to process (use -b <board>)",
659 str(e.exception))
660
661 def testMissingDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600662 """Test that an invalid device-tree file generates an error"""
Simon Glass4f443042016-11-25 20:15:52 -0700663 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600664 self._RunBinman('build', '-d', 'missing_file')
Simon Glass4f443042016-11-25 20:15:52 -0700665 # We get one error from libfdt, and a different one from fdtget.
666 self.AssertInList(["Couldn't open blob from 'missing_file'",
667 'No such file or directory'], str(e.exception))
668
669 def testBrokenDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600670 """Test that an invalid device-tree source file generates an error
Simon Glass4f443042016-11-25 20:15:52 -0700671
672 Since this is a source file it should be compiled and the error
673 will come from the device-tree compiler (dtc).
674 """
675 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600676 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700677 self.assertIn("FATAL ERROR: Unable to parse input tree",
678 str(e.exception))
679
680 def testMissingNode(self):
681 """Test that a device tree without a 'binman' node generates an error"""
682 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600683 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700684 self.assertIn("does not have a 'binman' node", str(e.exception))
685
686 def testEmpty(self):
687 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glass53cd5d92019-07-08 14:25:29 -0600688 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700689 self.assertEqual(0, len(result.stderr))
690 self.assertEqual(0, result.return_code)
691
692 def testInvalidEntry(self):
693 """Test that an invalid entry is flagged"""
694 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600695 result = self._RunBinman('build', '-d',
Simon Glass741f2d62018-10-01 12:22:30 -0600696 self.TestFile('004_invalid_entry.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700697 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
698 "'/binman/not-a-valid-type'", str(e.exception))
699
700 def testSimple(self):
701 """Test a simple binman with a single file"""
Simon Glass741f2d62018-10-01 12:22:30 -0600702 data = self._DoReadFile('005_simple.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700703 self.assertEqual(U_BOOT_DATA, data)
704
Simon Glass7fe91732017-11-13 18:55:00 -0700705 def testSimpleDebug(self):
706 """Test a simple binman run with debugging enabled"""
Simon Glasse2705fa2019-07-08 14:25:53 -0600707 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass7fe91732017-11-13 18:55:00 -0700708
Simon Glass4f443042016-11-25 20:15:52 -0700709 def testDual(self):
710 """Test that we can handle creating two images
711
712 This also tests image padding.
713 """
Simon Glass741f2d62018-10-01 12:22:30 -0600714 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700715 self.assertEqual(0, retcode)
716
717 image = control.images['image1']
Simon Glass8beb11e2019-07-08 14:25:47 -0600718 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700719 fname = tools.GetOutputFilename('image1.bin')
720 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600721 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700722 data = fd.read()
723 self.assertEqual(U_BOOT_DATA, data)
724
725 image = control.images['image2']
Simon Glass8beb11e2019-07-08 14:25:47 -0600726 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700727 fname = tools.GetOutputFilename('image2.bin')
728 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600729 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700730 data = fd.read()
731 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glasse6d85ff2019-05-14 15:53:47 -0600732 self.assertEqual(tools.GetBytes(0, 3), data[:3])
733 self.assertEqual(tools.GetBytes(0, 5), data[7:])
Simon Glass4f443042016-11-25 20:15:52 -0700734
735 def testBadAlign(self):
736 """Test that an invalid alignment value is detected"""
737 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600738 self._DoTestFile('007_bad_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700739 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
740 "of two", str(e.exception))
741
742 def testPackSimple(self):
743 """Test that packing works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600744 retcode = self._DoTestFile('008_pack.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700745 self.assertEqual(0, retcode)
746 self.assertIn('image', control.images)
747 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600748 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700749 self.assertEqual(5, len(entries))
750
751 # First u-boot
752 self.assertIn('u-boot', entries)
753 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600754 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700755 self.assertEqual(len(U_BOOT_DATA), entry.size)
756
757 # Second u-boot, aligned to 16-byte boundary
758 self.assertIn('u-boot-align', entries)
759 entry = entries['u-boot-align']
Simon Glass3ab95982018-08-01 15:22:37 -0600760 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700761 self.assertEqual(len(U_BOOT_DATA), entry.size)
762
763 # Third u-boot, size 23 bytes
764 self.assertIn('u-boot-size', entries)
765 entry = entries['u-boot-size']
Simon Glass3ab95982018-08-01 15:22:37 -0600766 self.assertEqual(20, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700767 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
768 self.assertEqual(23, entry.size)
769
770 # Fourth u-boot, placed immediate after the above
771 self.assertIn('u-boot-next', entries)
772 entry = entries['u-boot-next']
Simon Glass3ab95982018-08-01 15:22:37 -0600773 self.assertEqual(43, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700774 self.assertEqual(len(U_BOOT_DATA), entry.size)
775
Simon Glass3ab95982018-08-01 15:22:37 -0600776 # Fifth u-boot, placed at a fixed offset
Simon Glass4f443042016-11-25 20:15:52 -0700777 self.assertIn('u-boot-fixed', entries)
778 entry = entries['u-boot-fixed']
Simon Glass3ab95982018-08-01 15:22:37 -0600779 self.assertEqual(61, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700780 self.assertEqual(len(U_BOOT_DATA), entry.size)
781
Simon Glass8beb11e2019-07-08 14:25:47 -0600782 self.assertEqual(65, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700783
784 def testPackExtra(self):
785 """Test that extra packing feature works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600786 retcode = self._DoTestFile('009_pack_extra.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700787
788 self.assertEqual(0, retcode)
789 self.assertIn('image', control.images)
790 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600791 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700792 self.assertEqual(5, len(entries))
793
794 # First u-boot with padding before and after
795 self.assertIn('u-boot', entries)
796 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600797 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700798 self.assertEqual(3, entry.pad_before)
799 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
800
801 # Second u-boot has an aligned size, but it has no effect
802 self.assertIn('u-boot-align-size-nop', entries)
803 entry = entries['u-boot-align-size-nop']
Simon Glass3ab95982018-08-01 15:22:37 -0600804 self.assertEqual(12, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700805 self.assertEqual(4, entry.size)
806
807 # Third u-boot has an aligned size too
808 self.assertIn('u-boot-align-size', entries)
809 entry = entries['u-boot-align-size']
Simon Glass3ab95982018-08-01 15:22:37 -0600810 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700811 self.assertEqual(32, entry.size)
812
813 # Fourth u-boot has an aligned end
814 self.assertIn('u-boot-align-end', entries)
815 entry = entries['u-boot-align-end']
Simon Glass3ab95982018-08-01 15:22:37 -0600816 self.assertEqual(48, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700817 self.assertEqual(16, entry.size)
818
819 # Fifth u-boot immediately afterwards
820 self.assertIn('u-boot-align-both', entries)
821 entry = entries['u-boot-align-both']
Simon Glass3ab95982018-08-01 15:22:37 -0600822 self.assertEqual(64, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700823 self.assertEqual(64, entry.size)
824
825 self.CheckNoGaps(entries)
Simon Glass8beb11e2019-07-08 14:25:47 -0600826 self.assertEqual(128, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700827
828 def testPackAlignPowerOf2(self):
829 """Test that invalid entry alignment is detected"""
830 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600831 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700832 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
833 "of two", str(e.exception))
834
835 def testPackAlignSizePowerOf2(self):
836 """Test that invalid entry size alignment is detected"""
837 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600838 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700839 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
840 "power of two", str(e.exception))
841
842 def testPackInvalidAlign(self):
Simon Glass3ab95982018-08-01 15:22:37 -0600843 """Test detection of an offset that does not match its alignment"""
Simon Glass4f443042016-11-25 20:15:52 -0700844 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600845 self._DoTestFile('012_pack_inv_align.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600846 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700847 "align 0x4 (4)", str(e.exception))
848
849 def testPackInvalidSizeAlign(self):
850 """Test that invalid entry size alignment is detected"""
851 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600852 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700853 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
854 "align-size 0x4 (4)", str(e.exception))
855
856 def testPackOverlap(self):
857 """Test that overlapping regions are detected"""
858 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600859 self._DoTestFile('014_pack_overlap.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600860 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -0700861 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
862 str(e.exception))
863
864 def testPackEntryOverflow(self):
865 """Test that entries that overflow their size are detected"""
866 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600867 self._DoTestFile('015_pack_overflow.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700868 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
869 "but entry size is 0x3 (3)", str(e.exception))
870
871 def testPackImageOverflow(self):
872 """Test that entries which overflow the image size are detected"""
873 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600874 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600875 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass4f443042016-11-25 20:15:52 -0700876 "size 0x3 (3)", str(e.exception))
877
878 def testPackImageSize(self):
879 """Test that the image size can be set"""
Simon Glass741f2d62018-10-01 12:22:30 -0600880 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700881 self.assertEqual(0, retcode)
882 self.assertIn('image', control.images)
883 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -0600884 self.assertEqual(7, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700885
886 def testPackImageSizeAlign(self):
887 """Test that image size alignemnt works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600888 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700889 self.assertEqual(0, retcode)
890 self.assertIn('image', control.images)
891 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -0600892 self.assertEqual(16, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700893
894 def testPackInvalidImageAlign(self):
895 """Test that invalid image alignment is detected"""
896 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600897 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600898 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700899 "align-size 0x8 (8)", str(e.exception))
900
901 def testPackAlignPowerOf2(self):
902 """Test that invalid image alignment is detected"""
903 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600904 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -0600905 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass4f443042016-11-25 20:15:52 -0700906 "two", str(e.exception))
907
908 def testImagePadByte(self):
909 """Test that the image pad byte can be specified"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600910 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600911 data = self._DoReadFile('021_image_pad.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -0600912 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0xff, 1) +
913 U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -0700914
915 def testImageName(self):
916 """Test that image files can be named"""
Simon Glass741f2d62018-10-01 12:22:30 -0600917 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700918 self.assertEqual(0, retcode)
919 image = control.images['image1']
920 fname = tools.GetOutputFilename('test-name')
921 self.assertTrue(os.path.exists(fname))
922
923 image = control.images['image2']
924 fname = tools.GetOutputFilename('test-name.xx')
925 self.assertTrue(os.path.exists(fname))
926
927 def testBlobFilename(self):
928 """Test that generic blobs can be provided by filename"""
Simon Glass741f2d62018-10-01 12:22:30 -0600929 data = self._DoReadFile('023_blob.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700930 self.assertEqual(BLOB_DATA, data)
931
932 def testPackSorted(self):
933 """Test that entries can be sorted"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600934 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600935 data = self._DoReadFile('024_sorted.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -0600936 self.assertEqual(tools.GetBytes(0, 1) + U_BOOT_SPL_DATA +
937 tools.GetBytes(0, 2) + U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -0700938
Simon Glass3ab95982018-08-01 15:22:37 -0600939 def testPackZeroOffset(self):
940 """Test that an entry at offset 0 is not given a new offset"""
Simon Glass4f443042016-11-25 20:15:52 -0700941 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600942 self._DoTestFile('025_pack_zero_size.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600943 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -0700944 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
945 str(e.exception))
946
947 def testPackUbootDtb(self):
948 """Test that a device tree can be added to U-Boot"""
Simon Glass741f2d62018-10-01 12:22:30 -0600949 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700950 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glasse0ff8552016-11-25 20:15:53 -0700951
952 def testPackX86RomNoSize(self):
953 """Test that the end-at-4gb property requires a size property"""
954 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600955 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -0600956 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glasse0ff8552016-11-25 20:15:53 -0700957 "using end-at-4gb", str(e.exception))
958
Jagdish Gediya94b57db2018-09-03 21:35:07 +0530959 def test4gbAndSkipAtStartTogether(self):
960 """Test that the end-at-4gb and skip-at-size property can't be used
961 together"""
962 with self.assertRaises(ValueError) as e:
Simon Glassdfdd2b62019-08-24 07:23:02 -0600963 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -0600964 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya94b57db2018-09-03 21:35:07 +0530965 "'skip-at-start'", str(e.exception))
966
Simon Glasse0ff8552016-11-25 20:15:53 -0700967 def testPackX86RomOutside(self):
Simon Glass3ab95982018-08-01 15:22:37 -0600968 """Test that the end-at-4gb property checks for offset boundaries"""
Simon Glasse0ff8552016-11-25 20:15:53 -0700969 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600970 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600971 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) is outside "
Simon Glass8f1da502018-06-01 09:38:12 -0600972 "the section starting at 0xffffffe0 (4294967264)",
Simon Glasse0ff8552016-11-25 20:15:53 -0700973 str(e.exception))
974
975 def testPackX86Rom(self):
976 """Test that a basic x86 ROM can be created"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600977 self._SetupSplElf()
Simon Glass9255f3c2019-08-24 07:23:01 -0600978 data = self._DoReadFile('029_x86_rom.dts')
Simon Glasseb0086f2019-08-24 07:23:04 -0600979 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 3) + U_BOOT_SPL_DATA +
Simon Glasse6d85ff2019-05-14 15:53:47 -0600980 tools.GetBytes(0, 2), data)
Simon Glasse0ff8552016-11-25 20:15:53 -0700981
982 def testPackX86RomMeNoDesc(self):
983 """Test that an invalid Intel descriptor entry is detected"""
Simon Glass0ba4b3d2020-07-09 18:39:41 -0600984 try:
Simon Glass52b10dd2020-07-25 15:11:19 -0600985 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
Simon Glass0ba4b3d2020-07-09 18:39:41 -0600986 with self.assertRaises(ValueError) as e:
Simon Glass52b10dd2020-07-25 15:11:19 -0600987 self._DoTestFile('163_x86_rom_me_empty.dts')
Simon Glass0ba4b3d2020-07-09 18:39:41 -0600988 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
989 str(e.exception))
990 finally:
991 self._SetupDescriptor()
Simon Glasse0ff8552016-11-25 20:15:53 -0700992
993 def testPackX86RomBadDesc(self):
994 """Test that the Intel requires a descriptor entry"""
995 with self.assertRaises(ValueError) as e:
Simon Glass9255f3c2019-08-24 07:23:01 -0600996 self._DoTestFile('030_x86_rom_me_no_desc.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600997 self.assertIn("Node '/binman/intel-me': No offset set with "
998 "offset-unset: should another entry provide this correct "
999 "offset?", str(e.exception))
Simon Glasse0ff8552016-11-25 20:15:53 -07001000
1001 def testPackX86RomMe(self):
1002 """Test that an x86 ROM with an ME region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001003 data = self._DoReadFile('031_x86_rom_me.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06001004 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
1005 if data[:0x1000] != expected_desc:
1006 self.fail('Expected descriptor binary at start of image')
Simon Glasse0ff8552016-11-25 20:15:53 -07001007 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1008
1009 def testPackVga(self):
1010 """Test that an image with a VGA binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001011 data = self._DoReadFile('032_intel_vga.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -07001012 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1013
1014 def testPackStart16(self):
1015 """Test that an image with an x86 start16 region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001016 data = self._DoReadFile('033_x86_start16.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -07001017 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1018
Jagdish Gediya9d368f32018-09-03 21:35:08 +05301019 def testPackPowerpcMpc85xxBootpgResetvec(self):
1020 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1021 created"""
Simon Glassdfdd2b62019-08-24 07:23:02 -06001022 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
Jagdish Gediya9d368f32018-09-03 21:35:08 +05301023 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1024
Simon Glass736bb0a2018-07-06 10:27:17 -06001025 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glassadc57012018-07-06 10:27:16 -06001026 """Handle running a test for insertion of microcode
1027
1028 Args:
1029 dts_fname: Name of test .dts file
1030 nodtb_data: Data that we expect in the first section
Simon Glass736bb0a2018-07-06 10:27:17 -06001031 ucode_second: True if the microsecond entry is second instead of
1032 third
Simon Glassadc57012018-07-06 10:27:16 -06001033
1034 Returns:
1035 Tuple:
1036 Contents of first region (U-Boot or SPL)
Simon Glass3ab95982018-08-01 15:22:37 -06001037 Offset and size components of microcode pointer, as inserted
Simon Glassadc57012018-07-06 10:27:16 -06001038 in the above (two 4-byte words)
1039 """
Simon Glass6b187df2017-11-12 21:52:27 -07001040 data = self._DoReadFile(dts_fname, True)
Simon Glasse0ff8552016-11-25 20:15:53 -07001041
1042 # Now check the device tree has no microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001043 if ucode_second:
1044 ucode_content = data[len(nodtb_data):]
1045 ucode_pos = len(nodtb_data)
1046 dtb_with_ucode = ucode_content[16:]
1047 fdt_len = self.GetFdtLen(dtb_with_ucode)
1048 else:
1049 dtb_with_ucode = data[len(nodtb_data):]
1050 fdt_len = self.GetFdtLen(dtb_with_ucode)
1051 ucode_content = dtb_with_ucode[fdt_len:]
1052 ucode_pos = len(nodtb_data) + fdt_len
Simon Glasse0ff8552016-11-25 20:15:53 -07001053 fname = tools.GetOutputFilename('test.dtb')
1054 with open(fname, 'wb') as fd:
Simon Glassadc57012018-07-06 10:27:16 -06001055 fd.write(dtb_with_ucode)
Simon Glassec3f3782017-05-27 07:38:29 -06001056 dtb = fdt.FdtScan(fname)
1057 ucode = dtb.GetNode('/microcode')
Simon Glasse0ff8552016-11-25 20:15:53 -07001058 self.assertTrue(ucode)
1059 for node in ucode.subnodes:
1060 self.assertFalse(node.props.get('data'))
1061
Simon Glasse0ff8552016-11-25 20:15:53 -07001062 # Check that the microcode appears immediately after the Fdt
1063 # This matches the concatenation of the data properties in
Simon Glass87722132017-11-12 21:52:26 -07001064 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glasse0ff8552016-11-25 20:15:53 -07001065 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1066 0x78235609)
Simon Glassadc57012018-07-06 10:27:16 -06001067 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glasse0ff8552016-11-25 20:15:53 -07001068
1069 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -06001070 # expected offset and size
Simon Glasse0ff8552016-11-25 20:15:53 -07001071 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1072 len(ucode_data))
Simon Glass736bb0a2018-07-06 10:27:17 -06001073 u_boot = data[:len(nodtb_data)]
1074 return u_boot, pos_and_size
Simon Glass6b187df2017-11-12 21:52:27 -07001075
1076 def testPackUbootMicrocode(self):
1077 """Test that x86 microcode can be handled correctly
1078
1079 We expect to see the following in the image, in order:
1080 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1081 place
1082 u-boot.dtb with the microcode removed
1083 the microcode
1084 """
Simon Glass741f2d62018-10-01 12:22:30 -06001085 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass6b187df2017-11-12 21:52:27 -07001086 U_BOOT_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001087 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1088 b' somewhere in here', first)
Simon Glasse0ff8552016-11-25 20:15:53 -07001089
Simon Glass160a7662017-05-27 07:38:26 -06001090 def _RunPackUbootSingleMicrocode(self):
Simon Glasse0ff8552016-11-25 20:15:53 -07001091 """Test that x86 microcode can be handled correctly
1092
1093 We expect to see the following in the image, in order:
1094 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1095 place
1096 u-boot.dtb with the microcode
1097 an empty microcode region
1098 """
1099 # We need the libfdt library to run this test since only that allows
1100 # finding the offset of a property. This is required by
1101 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass741f2d62018-10-01 12:22:30 -06001102 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glasse0ff8552016-11-25 20:15:53 -07001103
1104 second = data[len(U_BOOT_NODTB_DATA):]
1105
1106 fdt_len = self.GetFdtLen(second)
1107 third = second[fdt_len:]
1108 second = second[:fdt_len]
1109
Simon Glass160a7662017-05-27 07:38:26 -06001110 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1111 self.assertIn(ucode_data, second)
1112 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -07001113
Simon Glass160a7662017-05-27 07:38:26 -06001114 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -06001115 # expected offset and size
Simon Glass160a7662017-05-27 07:38:26 -06001116 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1117 len(ucode_data))
1118 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glassc6c10e72019-05-17 22:00:46 -06001119 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1120 b' somewhere in here', first)
Simon Glassc49deb82016-11-25 20:15:54 -07001121
Simon Glass75db0862016-11-25 20:15:55 -07001122 def testPackUbootSingleMicrocode(self):
1123 """Test that x86 microcode can be handled correctly with fdt_normal.
1124 """
Simon Glass160a7662017-05-27 07:38:26 -06001125 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001126
Simon Glassc49deb82016-11-25 20:15:54 -07001127 def testUBootImg(self):
1128 """Test that u-boot.img can be put in a file"""
Simon Glass741f2d62018-10-01 12:22:30 -06001129 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glassc49deb82016-11-25 20:15:54 -07001130 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glass75db0862016-11-25 20:15:55 -07001131
1132 def testNoMicrocode(self):
1133 """Test that a missing microcode region is detected"""
1134 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001135 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001136 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1137 "node found in ", str(e.exception))
1138
1139 def testMicrocodeWithoutNode(self):
1140 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1141 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001142 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001143 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1144 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1145
1146 def testMicrocodeWithoutNode2(self):
1147 """Test that a missing u-boot-ucode node is detected"""
1148 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001149 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001150 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1151 "microcode region u-boot-ucode", str(e.exception))
1152
1153 def testMicrocodeWithoutPtrInElf(self):
1154 """Test that a U-Boot binary without the microcode symbol is detected"""
1155 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glass75db0862016-11-25 20:15:55 -07001156 try:
Simon Glassbccd91d2019-08-24 07:22:55 -06001157 TestFunctional._MakeInputFile('u-boot',
1158 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass75db0862016-11-25 20:15:55 -07001159
1160 with self.assertRaises(ValueError) as e:
Simon Glass160a7662017-05-27 07:38:26 -06001161 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001162 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1163 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1164
1165 finally:
1166 # Put the original file back
Simon Glassf514d8f2019-08-24 07:22:54 -06001167 TestFunctional._MakeInputFile('u-boot',
1168 tools.ReadFile(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glass75db0862016-11-25 20:15:55 -07001169
1170 def testMicrocodeNotInImage(self):
1171 """Test that microcode must be placed within the image"""
1172 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001173 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001174 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1175 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glass25ac0e62018-06-01 09:38:14 -06001176 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glass75db0862016-11-25 20:15:55 -07001177
1178 def testWithoutMicrocode(self):
1179 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glassbccd91d2019-08-24 07:22:55 -06001180 TestFunctional._MakeInputFile('u-boot',
1181 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass741f2d62018-10-01 12:22:30 -06001182 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001183
1184 # Now check the device tree has no microcode
1185 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1186 second = data[len(U_BOOT_NODTB_DATA):]
1187
1188 fdt_len = self.GetFdtLen(second)
1189 self.assertEqual(dtb, second[:fdt_len])
1190
1191 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1192 third = data[used_len:]
Simon Glasse6d85ff2019-05-14 15:53:47 -06001193 self.assertEqual(tools.GetBytes(0, 0x200 - used_len), third)
Simon Glass75db0862016-11-25 20:15:55 -07001194
1195 def testUnknownPosSize(self):
1196 """Test that microcode must be placed within the image"""
1197 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001198 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glass3ab95982018-08-01 15:22:37 -06001199 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glass75db0862016-11-25 20:15:55 -07001200 "entry 'invalid-entry'", str(e.exception))
Simon Glassda229092016-11-25 20:15:56 -07001201
1202 def testPackFsp(self):
1203 """Test that an image with a FSP binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001204 data = self._DoReadFile('042_intel_fsp.dts')
Simon Glassda229092016-11-25 20:15:56 -07001205 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1206
1207 def testPackCmc(self):
Bin Meng59ea8c22017-08-15 22:41:54 -07001208 """Test that an image with a CMC binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001209 data = self._DoReadFile('043_intel_cmc.dts')
Simon Glassda229092016-11-25 20:15:56 -07001210 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Meng59ea8c22017-08-15 22:41:54 -07001211
1212 def testPackVbt(self):
1213 """Test that an image with a VBT binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001214 data = self._DoReadFile('046_intel_vbt.dts')
Bin Meng59ea8c22017-08-15 22:41:54 -07001215 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glass9fc60b42017-11-12 21:52:22 -07001216
Simon Glass56509842017-11-12 21:52:25 -07001217 def testSplBssPad(self):
1218 """Test that we can pad SPL's BSS with zeros"""
Simon Glass6b187df2017-11-12 21:52:27 -07001219 # ELF file with a '__bss_size' symbol
Simon Glass11ae93e2018-10-01 21:12:47 -06001220 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001221 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001222 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
1223 data)
Simon Glass56509842017-11-12 21:52:25 -07001224
Simon Glass86af5112018-10-01 21:12:42 -06001225 def testSplBssPadMissing(self):
1226 """Test that a missing symbol is detected"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001227 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glassb50e5612017-11-13 18:54:54 -07001228 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001229 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassb50e5612017-11-13 18:54:54 -07001230 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1231 str(e.exception))
1232
Simon Glass87722132017-11-12 21:52:26 -07001233 def testPackStart16Spl(self):
Simon Glass35b384c2018-09-14 04:57:10 -06001234 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001235 data = self._DoReadFile('048_x86_start16_spl.dts')
Simon Glass87722132017-11-12 21:52:26 -07001236 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1237
Simon Glass736bb0a2018-07-06 10:27:17 -06001238 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1239 """Helper function for microcode tests
Simon Glass6b187df2017-11-12 21:52:27 -07001240
1241 We expect to see the following in the image, in order:
1242 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1243 correct place
1244 u-boot.dtb with the microcode removed
1245 the microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001246
1247 Args:
1248 dts: Device tree file to use for test
1249 ucode_second: True if the microsecond entry is second instead of
1250 third
Simon Glass6b187df2017-11-12 21:52:27 -07001251 """
Simon Glass11ae93e2018-10-01 21:12:47 -06001252 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass736bb0a2018-07-06 10:27:17 -06001253 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1254 ucode_second=ucode_second)
Simon Glassc6c10e72019-05-17 22:00:46 -06001255 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1256 b'ter somewhere in here', first)
Simon Glass6b187df2017-11-12 21:52:27 -07001257
Simon Glass736bb0a2018-07-06 10:27:17 -06001258 def testPackUbootSplMicrocode(self):
1259 """Test that x86 microcode can be handled correctly in SPL"""
Simon Glass741f2d62018-10-01 12:22:30 -06001260 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass736bb0a2018-07-06 10:27:17 -06001261
1262 def testPackUbootSplMicrocodeReorder(self):
1263 """Test that order doesn't matter for microcode entries
1264
1265 This is the same as testPackUbootSplMicrocode but when we process the
1266 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1267 entry, so we reply on binman to try later.
1268 """
Simon Glass741f2d62018-10-01 12:22:30 -06001269 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass736bb0a2018-07-06 10:27:17 -06001270 ucode_second=True)
1271
Simon Glassca4f4ff2017-11-12 21:52:28 -07001272 def testPackMrc(self):
1273 """Test that an image with an MRC binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001274 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassca4f4ff2017-11-12 21:52:28 -07001275 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1276
Simon Glass47419ea2017-11-13 18:54:55 -07001277 def testSplDtb(self):
1278 """Test that an image with spl/u-boot-spl.dtb can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001279 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass47419ea2017-11-13 18:54:55 -07001280 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1281
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001282 def testSplNoDtb(self):
1283 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001284 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001285 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1286
Simon Glass19790632017-11-13 18:55:01 -07001287 def testSymbols(self):
1288 """Test binman can assign symbols embedded in U-Boot"""
Simon Glass1542c8b2019-08-24 07:22:56 -06001289 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass19790632017-11-13 18:55:01 -07001290 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1291 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Simon Glass3ab95982018-08-01 15:22:37 -06001292 self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr)
Simon Glass19790632017-11-13 18:55:01 -07001293
Simon Glass11ae93e2018-10-01 21:12:47 -06001294 self._SetupSplElf('u_boot_binman_syms')
Simon Glass741f2d62018-10-01 12:22:30 -06001295 data = self._DoReadFile('053_symbols.dts')
Simon Glass7c150132019-11-06 17:22:44 -07001296 sym_values = struct.pack('<LQLL', 0x00, 0x1c, 0x28, 0x04)
Simon Glassb87064c2019-08-24 07:23:05 -06001297 expected = (sym_values + U_BOOT_SPL_DATA[20:] +
Simon Glasse6d85ff2019-05-14 15:53:47 -06001298 tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
Simon Glassb87064c2019-08-24 07:23:05 -06001299 U_BOOT_SPL_DATA[20:])
Simon Glass19790632017-11-13 18:55:01 -07001300 self.assertEqual(expected, data)
1301
Simon Glassdd57c132018-06-01 09:38:11 -06001302 def testPackUnitAddress(self):
1303 """Test that we support multiple binaries with the same name"""
Simon Glass741f2d62018-10-01 12:22:30 -06001304 data = self._DoReadFile('054_unit_address.dts')
Simon Glassdd57c132018-06-01 09:38:11 -06001305 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1306
Simon Glass18546952018-06-01 09:38:16 -06001307 def testSections(self):
1308 """Basic test of sections"""
Simon Glass741f2d62018-10-01 12:22:30 -06001309 data = self._DoReadFile('055_sections.dts')
Simon Glassc6c10e72019-05-17 22:00:46 -06001310 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1311 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
1312 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
Simon Glass18546952018-06-01 09:38:16 -06001313 self.assertEqual(expected, data)
Simon Glass9fc60b42017-11-12 21:52:22 -07001314
Simon Glass3b0c3822018-06-01 09:38:20 -06001315 def testMap(self):
1316 """Tests outputting a map of the images"""
Simon Glass741f2d62018-10-01 12:22:30 -06001317 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001318 self.assertEqual('''ImagePos Offset Size Name
131900000000 00000000 00000028 main-section
132000000000 00000000 00000010 section@0
132100000000 00000000 00000004 u-boot
132200000010 00000010 00000010 section@1
132300000010 00000000 00000004 u-boot
132400000020 00000020 00000004 section@2
132500000020 00000000 00000004 u-boot
Simon Glass3b0c3822018-06-01 09:38:20 -06001326''', map_data)
1327
Simon Glassc8d48ef2018-06-01 09:38:21 -06001328 def testNamePrefix(self):
1329 """Tests that name prefixes are used"""
Simon Glass741f2d62018-10-01 12:22:30 -06001330 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001331 self.assertEqual('''ImagePos Offset Size Name
133200000000 00000000 00000028 main-section
133300000000 00000000 00000010 section@0
133400000000 00000000 00000004 ro-u-boot
133500000010 00000010 00000010 section@1
133600000010 00000000 00000004 rw-u-boot
Simon Glassc8d48ef2018-06-01 09:38:21 -06001337''', map_data)
1338
Simon Glass736bb0a2018-07-06 10:27:17 -06001339 def testUnknownContents(self):
1340 """Test that obtaining the contents works as expected"""
1341 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001342 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass8beb11e2019-07-08 14:25:47 -06001343 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glass16287932020-04-17 18:09:03 -06001344 "processing of contents: remaining ["
1345 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass736bb0a2018-07-06 10:27:17 -06001346
Simon Glass5c890232018-07-06 10:27:19 -06001347 def testBadChangeSize(self):
1348 """Test that trying to change the size of an entry fails"""
Simon Glassc52c9e72019-07-08 14:25:37 -06001349 try:
1350 state.SetAllowEntryExpansion(False)
1351 with self.assertRaises(ValueError) as e:
1352 self._DoReadFile('059_change_size.dts', True)
Simon Glass79d3c582019-07-20 12:23:57 -06001353 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glassc52c9e72019-07-08 14:25:37 -06001354 str(e.exception))
1355 finally:
1356 state.SetAllowEntryExpansion(True)
Simon Glass5c890232018-07-06 10:27:19 -06001357
Simon Glass16b8d6b2018-07-06 10:27:42 -06001358 def testUpdateFdt(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001359 """Test that we can update the device tree with offset/size info"""
Simon Glass741f2d62018-10-01 12:22:30 -06001360 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glass16b8d6b2018-07-06 10:27:42 -06001361 update_dtb=True)
Simon Glasscee02e62018-07-17 13:25:52 -06001362 dtb = fdt.Fdt(out_dtb_fname)
1363 dtb.Scan()
Simon Glass12bb1a92019-07-20 12:23:51 -06001364 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001365 self.assertEqual({
Simon Glassdbf6be92018-08-01 15:22:42 -06001366 'image-pos': 0,
Simon Glass8122f392018-07-17 13:25:28 -06001367 'offset': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001368 '_testing:offset': 32,
Simon Glass79d3c582019-07-20 12:23:57 -06001369 '_testing:size': 2,
Simon Glassdbf6be92018-08-01 15:22:42 -06001370 '_testing:image-pos': 32,
Simon Glass3ab95982018-08-01 15:22:37 -06001371 'section@0/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001372 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001373 'section@0/u-boot:image-pos': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001374 'section@0:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001375 'section@0:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001376 'section@0:image-pos': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001377
Simon Glass3ab95982018-08-01 15:22:37 -06001378 'section@1/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001379 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001380 'section@1/u-boot:image-pos': 16,
Simon Glass3ab95982018-08-01 15:22:37 -06001381 'section@1:offset': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001382 'section@1:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001383 'section@1:image-pos': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001384 'size': 40
1385 }, props)
1386
1387 def testUpdateFdtBad(self):
1388 """Test that we detect when ProcessFdt never completes"""
1389 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001390 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001391 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glass16287932020-04-17 18:09:03 -06001392 '[<binman.etype._testing.Entry__testing',
1393 str(e.exception))
Simon Glass5c890232018-07-06 10:27:19 -06001394
Simon Glass53af22a2018-07-17 13:25:32 -06001395 def testEntryArgs(self):
1396 """Test passing arguments to entries from the command line"""
1397 entry_args = {
1398 'test-str-arg': 'test1',
1399 'test-int-arg': '456',
1400 }
Simon Glass741f2d62018-10-01 12:22:30 -06001401 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001402 self.assertIn('image', control.images)
1403 entry = control.images['image'].GetEntries()['_testing']
1404 self.assertEqual('test0', entry.test_str_fdt)
1405 self.assertEqual('test1', entry.test_str_arg)
1406 self.assertEqual(123, entry.test_int_fdt)
1407 self.assertEqual(456, entry.test_int_arg)
1408
1409 def testEntryArgsMissing(self):
1410 """Test missing arguments and properties"""
1411 entry_args = {
1412 'test-int-arg': '456',
1413 }
Simon Glass741f2d62018-10-01 12:22:30 -06001414 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001415 entry = control.images['image'].GetEntries()['_testing']
1416 self.assertEqual('test0', entry.test_str_fdt)
1417 self.assertEqual(None, entry.test_str_arg)
1418 self.assertEqual(None, entry.test_int_fdt)
1419 self.assertEqual(456, entry.test_int_arg)
1420
1421 def testEntryArgsRequired(self):
1422 """Test missing arguments and properties"""
1423 entry_args = {
1424 'test-int-arg': '456',
1425 }
1426 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001427 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass3decfa32020-09-01 05:13:54 -06001428 self.assertIn("Node '/binman/_testing': "
1429 'Missing required properties/entry args: test-str-arg, '
1430 'test-int-fdt, test-int-arg',
Simon Glass53af22a2018-07-17 13:25:32 -06001431 str(e.exception))
1432
1433 def testEntryArgsInvalidFormat(self):
1434 """Test that an invalid entry-argument format is detected"""
Simon Glass53cd5d92019-07-08 14:25:29 -06001435 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1436 '-ano-value']
Simon Glass53af22a2018-07-17 13:25:32 -06001437 with self.assertRaises(ValueError) as e:
1438 self._DoBinman(*args)
1439 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1440
1441 def testEntryArgsInvalidInteger(self):
1442 """Test that an invalid entry-argument integer is detected"""
1443 entry_args = {
1444 'test-int-arg': 'abc',
1445 }
1446 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001447 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001448 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1449 "'test-int-arg' (value 'abc') to integer",
1450 str(e.exception))
1451
1452 def testEntryArgsInvalidDatatype(self):
1453 """Test that an invalid entry-argument datatype is detected
1454
1455 This test could be written in entry_test.py except that it needs
1456 access to control.entry_args, which seems more than that module should
1457 be able to see.
1458 """
1459 entry_args = {
1460 'test-bad-datatype-arg': '12',
1461 }
1462 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001463 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass53af22a2018-07-17 13:25:32 -06001464 entry_args=entry_args)
1465 self.assertIn('GetArg() internal error: Unknown data type ',
1466 str(e.exception))
1467
Simon Glassbb748372018-07-17 13:25:33 -06001468 def testText(self):
1469 """Test for a text entry type"""
1470 entry_args = {
1471 'test-id': TEXT_DATA,
1472 'test-id2': TEXT_DATA2,
1473 'test-id3': TEXT_DATA3,
1474 }
Simon Glass741f2d62018-10-01 12:22:30 -06001475 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glassbb748372018-07-17 13:25:33 -06001476 entry_args=entry_args)
Simon Glassc6c10e72019-05-17 22:00:46 -06001477 expected = (tools.ToBytes(TEXT_DATA) +
1478 tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1479 tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
Simon Glassaa88b502019-07-08 13:18:40 -06001480 b'some text' + b'more text')
Simon Glassbb748372018-07-17 13:25:33 -06001481 self.assertEqual(expected, data)
1482
Simon Glassfd8d1f72018-07-17 13:25:36 -06001483 def testEntryDocs(self):
1484 """Test for creation of entry documentation"""
1485 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass87d43322020-08-05 13:27:46 -06001486 control.WriteEntryDocs(control.GetEntryModules())
Simon Glassfd8d1f72018-07-17 13:25:36 -06001487 self.assertTrue(len(stdout.getvalue()) > 0)
1488
1489 def testEntryDocsMissing(self):
1490 """Test handling of missing entry documentation"""
1491 with self.assertRaises(ValueError) as e:
1492 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass87d43322020-08-05 13:27:46 -06001493 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glassfd8d1f72018-07-17 13:25:36 -06001494 self.assertIn('Documentation is missing for modules: u_boot',
1495 str(e.exception))
1496
Simon Glass11e36cc2018-07-17 13:25:38 -06001497 def testFmap(self):
1498 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001499 data = self._DoReadFile('067_fmap.dts')
Simon Glass11e36cc2018-07-17 13:25:38 -06001500 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc6c10e72019-05-17 22:00:46 -06001501 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1502 U_BOOT_DATA + tools.GetBytes(ord('a'), 12))
Simon Glass11e36cc2018-07-17 13:25:38 -06001503 self.assertEqual(expected, data[:32])
Simon Glassc6c10e72019-05-17 22:00:46 -06001504 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass11e36cc2018-07-17 13:25:38 -06001505 self.assertEqual(1, fhdr.ver_major)
1506 self.assertEqual(0, fhdr.ver_minor)
1507 self.assertEqual(0, fhdr.base)
1508 self.assertEqual(16 + 16 +
1509 fmap_util.FMAP_HEADER_LEN +
1510 fmap_util.FMAP_AREA_LEN * 3, fhdr.image_size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001511 self.assertEqual(b'FMAP', fhdr.name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001512 self.assertEqual(3, fhdr.nareas)
1513 for fentry in fentries:
1514 self.assertEqual(0, fentry.flags)
1515
1516 self.assertEqual(0, fentries[0].offset)
1517 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001518 self.assertEqual(b'RO_U_BOOT', fentries[0].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001519
1520 self.assertEqual(16, fentries[1].offset)
1521 self.assertEqual(4, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001522 self.assertEqual(b'RW_U_BOOT', fentries[1].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001523
1524 self.assertEqual(32, fentries[2].offset)
1525 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1526 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001527 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001528
Simon Glassec127af2018-07-17 13:25:39 -06001529 def testBlobNamedByArg(self):
1530 """Test we can add a blob with the filename coming from an entry arg"""
1531 entry_args = {
1532 'cros-ec-rw-path': 'ecrw.bin',
1533 }
Simon Glass3decfa32020-09-01 05:13:54 -06001534 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassec127af2018-07-17 13:25:39 -06001535
Simon Glass3af8e492018-07-17 13:25:40 -06001536 def testFill(self):
1537 """Test for an fill entry type"""
Simon Glass741f2d62018-10-01 12:22:30 -06001538 data = self._DoReadFile('069_fill.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001539 expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
Simon Glass3af8e492018-07-17 13:25:40 -06001540 self.assertEqual(expected, data)
1541
1542 def testFillNoSize(self):
1543 """Test for an fill entry type with no size"""
1544 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001545 self._DoReadFile('070_fill_no_size.dts')
Simon Glass3af8e492018-07-17 13:25:40 -06001546 self.assertIn("'fill' entry must have a size property",
1547 str(e.exception))
1548
Simon Glass0ef87aa2018-07-17 13:25:44 -06001549 def _HandleGbbCommand(self, pipe_list):
1550 """Fake calls to the futility utility"""
1551 if pipe_list[0][0] == 'futility':
1552 fname = pipe_list[0][-1]
1553 # Append our GBB data to the file, which will happen every time the
1554 # futility command is called.
Simon Glass1d0ebf72019-05-14 15:53:42 -06001555 with open(fname, 'ab') as fd:
Simon Glass0ef87aa2018-07-17 13:25:44 -06001556 fd.write(GBB_DATA)
1557 return command.CommandResult()
1558
1559 def testGbb(self):
1560 """Test for the Chromium OS Google Binary Block"""
1561 command.test_result = self._HandleGbbCommand
1562 entry_args = {
1563 'keydir': 'devkeys',
1564 'bmpblk': 'bmpblk.bin',
1565 }
Simon Glass741f2d62018-10-01 12:22:30 -06001566 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glass0ef87aa2018-07-17 13:25:44 -06001567
1568 # Since futility
Simon Glasse6d85ff2019-05-14 15:53:47 -06001569 expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1570 tools.GetBytes(0, 0x2180 - 16))
Simon Glass0ef87aa2018-07-17 13:25:44 -06001571 self.assertEqual(expected, data)
1572
1573 def testGbbTooSmall(self):
1574 """Test for the Chromium OS Google Binary Block being large enough"""
1575 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001576 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001577 self.assertIn("Node '/binman/gbb': GBB is too small",
1578 str(e.exception))
1579
1580 def testGbbNoSize(self):
1581 """Test for the Chromium OS Google Binary Block having a size"""
1582 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001583 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001584 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1585 str(e.exception))
1586
Simon Glass24d0d3c2018-07-17 13:25:47 -06001587 def _HandleVblockCommand(self, pipe_list):
1588 """Fake calls to the futility utility"""
1589 if pipe_list[0][0] == 'futility':
1590 fname = pipe_list[0][3]
Simon Glassa326b492018-09-14 04:57:11 -06001591 with open(fname, 'wb') as fd:
Simon Glass24d0d3c2018-07-17 13:25:47 -06001592 fd.write(VBLOCK_DATA)
1593 return command.CommandResult()
1594
1595 def testVblock(self):
1596 """Test for the Chromium OS Verified Boot Block"""
1597 command.test_result = self._HandleVblockCommand
1598 entry_args = {
1599 'keydir': 'devkeys',
1600 }
Simon Glass741f2d62018-10-01 12:22:30 -06001601 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass24d0d3c2018-07-17 13:25:47 -06001602 entry_args=entry_args)
1603 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1604 self.assertEqual(expected, data)
1605
1606 def testVblockNoContent(self):
1607 """Test we detect a vblock which has no content to sign"""
1608 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001609 self._DoReadFile('075_vblock_no_content.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001610 self.assertIn("Node '/binman/vblock': Vblock must have a 'content' "
1611 'property', str(e.exception))
1612
1613 def testVblockBadPhandle(self):
1614 """Test that we detect a vblock with an invalid phandle in contents"""
1615 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001616 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001617 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1618 '1000', str(e.exception))
1619
1620 def testVblockBadEntry(self):
1621 """Test that we detect an entry that points to a non-entry"""
1622 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001623 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001624 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1625 "'other'", str(e.exception))
1626
Simon Glassb8ef5b62018-07-17 13:25:48 -06001627 def testTpl(self):
Simon Glass2090f1e2019-08-24 07:23:00 -06001628 """Test that an image with TPL and its device tree can be created"""
Simon Glassb8ef5b62018-07-17 13:25:48 -06001629 # ELF file with a '__bss_size' symbol
Simon Glass2090f1e2019-08-24 07:23:00 -06001630 self._SetupTplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001631 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glassb8ef5b62018-07-17 13:25:48 -06001632 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1633
Simon Glass15a587c2018-07-17 13:25:51 -06001634 def testUsesPos(self):
1635 """Test that the 'pos' property cannot be used anymore"""
1636 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001637 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass15a587c2018-07-17 13:25:51 -06001638 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1639 "'pos'", str(e.exception))
1640
Simon Glassd178eab2018-09-14 04:57:08 -06001641 def testFillZero(self):
1642 """Test for an fill entry type with a size of 0"""
Simon Glass741f2d62018-10-01 12:22:30 -06001643 data = self._DoReadFile('080_fill_empty.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001644 self.assertEqual(tools.GetBytes(0, 16), data)
Simon Glassd178eab2018-09-14 04:57:08 -06001645
Simon Glass0b489362018-09-14 04:57:09 -06001646 def testTextMissing(self):
1647 """Test for a text entry type where there is no text"""
1648 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001649 self._DoReadFileDtb('066_text.dts',)
Simon Glass0b489362018-09-14 04:57:09 -06001650 self.assertIn("Node '/binman/text': No value provided for text label "
1651 "'test-id'", str(e.exception))
1652
Simon Glass35b384c2018-09-14 04:57:10 -06001653 def testPackStart16Tpl(self):
1654 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001655 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glass35b384c2018-09-14 04:57:10 -06001656 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1657
Simon Glass0bfa7b02018-09-14 04:57:12 -06001658 def testSelectImage(self):
1659 """Test that we can select which images to build"""
Simon Glasseb833d82019-04-25 21:58:34 -06001660 expected = 'Skipping images: image1'
Simon Glass0bfa7b02018-09-14 04:57:12 -06001661
Simon Glasseb833d82019-04-25 21:58:34 -06001662 # We should only get the expected message in verbose mode
Simon Glassee0c9a72019-07-08 13:18:48 -06001663 for verbosity in (0, 2):
Simon Glasseb833d82019-04-25 21:58:34 -06001664 with test_util.capture_sys_output() as (stdout, stderr):
1665 retcode = self._DoTestFile('006_dual_image.dts',
1666 verbosity=verbosity,
1667 images=['image2'])
1668 self.assertEqual(0, retcode)
1669 if verbosity:
1670 self.assertIn(expected, stdout.getvalue())
1671 else:
1672 self.assertNotIn(expected, stdout.getvalue())
1673
1674 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1675 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
Simon Glassf86a7362019-07-20 12:24:10 -06001676 self._CleanupOutputDir()
Simon Glass0bfa7b02018-09-14 04:57:12 -06001677
Simon Glass6ed45ba2018-09-14 04:57:24 -06001678 def testUpdateFdtAll(self):
1679 """Test that all device trees are updated with offset/size info"""
Simon Glass3c081312019-07-08 14:25:26 -06001680 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glass6ed45ba2018-09-14 04:57:24 -06001681
1682 base_expected = {
1683 'section:image-pos': 0,
1684 'u-boot-tpl-dtb:size': 513,
1685 'u-boot-spl-dtb:size': 513,
1686 'u-boot-spl-dtb:offset': 493,
1687 'image-pos': 0,
1688 'section/u-boot-dtb:image-pos': 0,
1689 'u-boot-spl-dtb:image-pos': 493,
1690 'section/u-boot-dtb:size': 493,
1691 'u-boot-tpl-dtb:image-pos': 1006,
1692 'section/u-boot-dtb:offset': 0,
1693 'section:size': 493,
1694 'offset': 0,
1695 'section:offset': 0,
1696 'u-boot-tpl-dtb:offset': 1006,
1697 'size': 1519
1698 }
1699
1700 # We expect three device-tree files in the output, one after the other.
1701 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1702 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1703 # main U-Boot tree. All three should have the same postions and offset.
1704 start = 0
1705 for item in ['', 'spl', 'tpl']:
1706 dtb = fdt.Fdt.FromData(data[start:])
1707 dtb.Scan()
Simon Glass12bb1a92019-07-20 12:23:51 -06001708 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
1709 ['spl', 'tpl'])
Simon Glass6ed45ba2018-09-14 04:57:24 -06001710 expected = dict(base_expected)
1711 if item:
1712 expected[item] = 0
1713 self.assertEqual(expected, props)
1714 start += dtb._fdt_obj.totalsize()
1715
1716 def testUpdateFdtOutput(self):
1717 """Test that output DTB files are updated"""
1718 try:
Simon Glass741f2d62018-10-01 12:22:30 -06001719 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glass6ed45ba2018-09-14 04:57:24 -06001720 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1721
1722 # Unfortunately, compiling a source file always results in a file
1723 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass741f2d62018-10-01 12:22:30 -06001724 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glass6ed45ba2018-09-14 04:57:24 -06001725 # binman as a file called u-boot.dtb. To fix this, copy the file
1726 # over to the expected place.
Simon Glass6ed45ba2018-09-14 04:57:24 -06001727 start = 0
1728 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1729 'tpl/u-boot-tpl.dtb.out']:
1730 dtb = fdt.Fdt.FromData(data[start:])
1731 size = dtb._fdt_obj.totalsize()
1732 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1733 outdata = tools.ReadFile(pathname)
1734 name = os.path.split(fname)[0]
1735
1736 if name:
1737 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1738 else:
1739 orig_indata = dtb_data
1740 self.assertNotEqual(outdata, orig_indata,
1741 "Expected output file '%s' be updated" % pathname)
1742 self.assertEqual(outdata, data[start:start + size],
1743 "Expected output file '%s' to match output image" %
1744 pathname)
1745 start += size
1746 finally:
1747 self._ResetDtbs()
1748
Simon Glass83d73c22018-09-14 04:57:26 -06001749 def _decompress(self, data):
Simon Glassff5c7e32019-07-08 13:18:42 -06001750 return tools.Decompress(data, 'lz4')
Simon Glass83d73c22018-09-14 04:57:26 -06001751
1752 def testCompress(self):
1753 """Test compression of blobs"""
Simon Glassac62fba2019-07-08 13:18:53 -06001754 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06001755 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass83d73c22018-09-14 04:57:26 -06001756 use_real_dtb=True, update_dtb=True)
1757 dtb = fdt.Fdt(out_dtb_fname)
1758 dtb.Scan()
1759 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1760 orig = self._decompress(data)
1761 self.assertEquals(COMPRESS_DATA, orig)
1762 expected = {
1763 'blob:uncomp-size': len(COMPRESS_DATA),
1764 'blob:size': len(data),
1765 'size': len(data),
1766 }
1767 self.assertEqual(expected, props)
1768
Simon Glass0a98b282018-09-14 04:57:28 -06001769 def testFiles(self):
1770 """Test bringing in multiple files"""
Simon Glass741f2d62018-10-01 12:22:30 -06001771 data = self._DoReadFile('084_files.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001772 self.assertEqual(FILES_DATA, data)
1773
1774 def testFilesCompress(self):
1775 """Test bringing in multiple files and compressing them"""
Simon Glassac62fba2019-07-08 13:18:53 -06001776 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06001777 data = self._DoReadFile('085_files_compress.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001778
1779 image = control.images['image']
1780 entries = image.GetEntries()
1781 files = entries['files']
Simon Glass8beb11e2019-07-08 14:25:47 -06001782 entries = files._entries
Simon Glass0a98b282018-09-14 04:57:28 -06001783
Simon Glassc6c10e72019-05-17 22:00:46 -06001784 orig = b''
Simon Glass0a98b282018-09-14 04:57:28 -06001785 for i in range(1, 3):
1786 key = '%d.dat' % i
1787 start = entries[key].image_pos
1788 len = entries[key].size
1789 chunk = data[start:start + len]
1790 orig += self._decompress(chunk)
1791
1792 self.assertEqual(FILES_DATA, orig)
1793
1794 def testFilesMissing(self):
1795 """Test missing files"""
1796 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001797 data = self._DoReadFile('086_files_none.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001798 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1799 'no files', str(e.exception))
1800
1801 def testFilesNoPattern(self):
1802 """Test missing files"""
1803 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001804 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001805 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1806 str(e.exception))
1807
Simon Glassba64a0b2018-09-14 04:57:29 -06001808 def testExpandSize(self):
1809 """Test an expanding entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001810 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
Simon Glassba64a0b2018-09-14 04:57:29 -06001811 map=True)
Simon Glassc6c10e72019-05-17 22:00:46 -06001812 expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA +
1813 MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA +
1814 tools.GetBytes(ord('c'), 8) + U_BOOT_DATA +
1815 tools.GetBytes(ord('d'), 8))
Simon Glassba64a0b2018-09-14 04:57:29 -06001816 self.assertEqual(expect, data)
1817 self.assertEqual('''ImagePos Offset Size Name
181800000000 00000000 00000028 main-section
181900000000 00000000 00000008 fill
182000000008 00000008 00000004 u-boot
18210000000c 0000000c 00000004 section
18220000000c 00000000 00000003 intel-mrc
182300000010 00000010 00000004 u-boot2
182400000014 00000014 0000000c section2
182500000014 00000000 00000008 fill
18260000001c 00000008 00000004 u-boot
182700000020 00000020 00000008 fill2
1828''', map_data)
1829
1830 def testExpandSizeBad(self):
1831 """Test an expanding entry which fails to provide contents"""
Simon Glass163ed6c2018-09-14 04:57:36 -06001832 with test_util.capture_sys_output() as (stdout, stderr):
1833 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001834 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
Simon Glassba64a0b2018-09-14 04:57:29 -06001835 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
1836 'expanding entry', str(e.exception))
1837
Simon Glasse0e5df92018-09-14 04:57:31 -06001838 def testHash(self):
1839 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001840 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06001841 use_real_dtb=True, update_dtb=True)
1842 dtb = fdt.Fdt(out_dtb_fname)
1843 dtb.Scan()
1844 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
1845 m = hashlib.sha256()
1846 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001847 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06001848
1849 def testHashNoAlgo(self):
1850 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001851 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06001852 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
1853 'hash node', str(e.exception))
1854
1855 def testHashBadAlgo(self):
1856 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001857 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06001858 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
1859 str(e.exception))
1860
1861 def testHashSection(self):
1862 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001863 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06001864 use_real_dtb=True, update_dtb=True)
1865 dtb = fdt.Fdt(out_dtb_fname)
1866 dtb.Scan()
1867 hash_node = dtb.GetNode('/binman/section/hash').props['value']
1868 m = hashlib.sha256()
1869 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001870 m.update(tools.GetBytes(ord('a'), 16))
1871 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06001872
Simon Glassf0253632018-09-14 04:57:32 -06001873 def testPackUBootTplMicrocode(self):
1874 """Test that x86 microcode can be handled correctly in TPL
1875
1876 We expect to see the following in the image, in order:
1877 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
1878 place
1879 u-boot-tpl.dtb with the microcode removed
1880 the microcode
1881 """
Simon Glass2090f1e2019-08-24 07:23:00 -06001882 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass741f2d62018-10-01 12:22:30 -06001883 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glassf0253632018-09-14 04:57:32 -06001884 U_BOOT_TPL_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001885 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
1886 b'ter somewhere in here', first)
Simon Glassf0253632018-09-14 04:57:32 -06001887
Simon Glassf8f8df62018-09-14 04:57:34 -06001888 def testFmapX86(self):
1889 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001890 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassf8f8df62018-09-14 04:57:34 -06001891 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc6c10e72019-05-17 22:00:46 -06001892 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06001893 self.assertEqual(expected, data[:32])
1894 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1895
1896 self.assertEqual(0x100, fhdr.image_size)
1897
1898 self.assertEqual(0, fentries[0].offset)
1899 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001900 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001901
1902 self.assertEqual(4, fentries[1].offset)
1903 self.assertEqual(3, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001904 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001905
1906 self.assertEqual(32, fentries[2].offset)
1907 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1908 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001909 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001910
1911 def testFmapX86Section(self):
1912 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001913 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glassc6c10e72019-05-17 22:00:46 -06001914 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06001915 self.assertEqual(expected, data[:32])
1916 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
1917
1918 self.assertEqual(0x100, fhdr.image_size)
1919
1920 self.assertEqual(0, fentries[0].offset)
1921 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001922 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001923
1924 self.assertEqual(4, fentries[1].offset)
1925 self.assertEqual(3, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001926 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001927
1928 self.assertEqual(36, fentries[2].offset)
1929 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1930 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001931 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001932
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001933 def testElf(self):
1934 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001935 self._SetupSplElf()
Simon Glass2090f1e2019-08-24 07:23:00 -06001936 self._SetupTplElf()
Simon Glass53e22bf2019-08-24 07:22:53 -06001937 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001938 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001939 data = self._DoReadFile('096_elf.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001940
Simon Glass093d1682019-07-08 13:18:25 -06001941 def testElfStrip(self):
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001942 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001943 self._SetupSplElf()
Simon Glass53e22bf2019-08-24 07:22:53 -06001944 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001945 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001946 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001947
Simon Glass163ed6c2018-09-14 04:57:36 -06001948 def testPackOverlapMap(self):
1949 """Test that overlapping regions are detected"""
1950 with test_util.capture_sys_output() as (stdout, stderr):
1951 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001952 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glass163ed6c2018-09-14 04:57:36 -06001953 map_fname = tools.GetOutputFilename('image.map')
1954 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
1955 stdout.getvalue())
1956
1957 # We should not get an inmage, but there should be a map file
1958 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
1959 self.assertTrue(os.path.exists(map_fname))
Simon Glasseb546ac2019-05-17 22:00:51 -06001960 map_data = tools.ReadFile(map_fname, binary=False)
Simon Glass163ed6c2018-09-14 04:57:36 -06001961 self.assertEqual('''ImagePos Offset Size Name
1962<none> 00000000 00000007 main-section
1963<none> 00000000 00000004 u-boot
1964<none> 00000003 00000004 u-boot-align
1965''', map_data)
1966
Simon Glass093d1682019-07-08 13:18:25 -06001967 def testPackRefCode(self):
Simon Glass3ae192c2018-10-01 12:22:31 -06001968 """Test that an image with an Intel Reference code binary works"""
1969 data = self._DoReadFile('100_intel_refcode.dts')
1970 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
1971
Simon Glass9481c802019-04-25 21:58:39 -06001972 def testSectionOffset(self):
1973 """Tests use of a section with an offset"""
1974 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
1975 map=True)
1976 self.assertEqual('''ImagePos Offset Size Name
197700000000 00000000 00000038 main-section
197800000004 00000004 00000010 section@0
197900000004 00000000 00000004 u-boot
198000000018 00000018 00000010 section@1
198100000018 00000000 00000004 u-boot
19820000002c 0000002c 00000004 section@2
19830000002c 00000000 00000004 u-boot
1984''', map_data)
1985 self.assertEqual(data,
Simon Glasse6d85ff2019-05-14 15:53:47 -06001986 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1987 tools.GetBytes(0x21, 12) +
1988 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1989 tools.GetBytes(0x61, 12) +
1990 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1991 tools.GetBytes(0x26, 8))
Simon Glass9481c802019-04-25 21:58:39 -06001992
Simon Glassac62fba2019-07-08 13:18:53 -06001993 def testCbfsRaw(self):
1994 """Test base handling of a Coreboot Filesystem (CBFS)
1995
1996 The exact contents of the CBFS is verified by similar tests in
1997 cbfs_util_test.py. The tests here merely check that the files added to
1998 the CBFS can be found in the final image.
1999 """
2000 data = self._DoReadFile('102_cbfs_raw.dts')
2001 size = 0xb0
2002
2003 cbfs = cbfs_util.CbfsReader(data)
2004 self.assertEqual(size, cbfs.rom_size)
2005
2006 self.assertIn('u-boot-dtb', cbfs.files)
2007 cfile = cbfs.files['u-boot-dtb']
2008 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2009
2010 def testCbfsArch(self):
2011 """Test on non-x86 architecture"""
2012 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2013 size = 0x100
2014
2015 cbfs = cbfs_util.CbfsReader(data)
2016 self.assertEqual(size, cbfs.rom_size)
2017
2018 self.assertIn('u-boot-dtb', cbfs.files)
2019 cfile = cbfs.files['u-boot-dtb']
2020 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2021
2022 def testCbfsStage(self):
2023 """Tests handling of a Coreboot Filesystem (CBFS)"""
2024 if not elf.ELF_TOOLS:
2025 self.skipTest('Python elftools not available')
2026 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2027 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2028 size = 0xb0
2029
2030 data = self._DoReadFile('104_cbfs_stage.dts')
2031 cbfs = cbfs_util.CbfsReader(data)
2032 self.assertEqual(size, cbfs.rom_size)
2033
2034 self.assertIn('u-boot', cbfs.files)
2035 cfile = cbfs.files['u-boot']
2036 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2037
2038 def testCbfsRawCompress(self):
2039 """Test handling of compressing raw files"""
2040 self._CheckLz4()
2041 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2042 size = 0x140
2043
2044 cbfs = cbfs_util.CbfsReader(data)
2045 self.assertIn('u-boot', cbfs.files)
2046 cfile = cbfs.files['u-boot']
2047 self.assertEqual(COMPRESS_DATA, cfile.data)
2048
2049 def testCbfsBadArch(self):
2050 """Test handling of a bad architecture"""
2051 with self.assertRaises(ValueError) as e:
2052 self._DoReadFile('106_cbfs_bad_arch.dts')
2053 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2054
2055 def testCbfsNoSize(self):
2056 """Test handling of a missing size property"""
2057 with self.assertRaises(ValueError) as e:
2058 self._DoReadFile('107_cbfs_no_size.dts')
2059 self.assertIn('entry must have a size property', str(e.exception))
2060
2061 def testCbfsNoCOntents(self):
2062 """Test handling of a CBFS entry which does not provide contentsy"""
2063 with self.assertRaises(ValueError) as e:
2064 self._DoReadFile('108_cbfs_no_contents.dts')
2065 self.assertIn('Could not complete processing of contents',
2066 str(e.exception))
2067
2068 def testCbfsBadCompress(self):
2069 """Test handling of a bad architecture"""
2070 with self.assertRaises(ValueError) as e:
2071 self._DoReadFile('109_cbfs_bad_compress.dts')
2072 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2073 str(e.exception))
2074
2075 def testCbfsNamedEntries(self):
2076 """Test handling of named entries"""
2077 data = self._DoReadFile('110_cbfs_name.dts')
2078
2079 cbfs = cbfs_util.CbfsReader(data)
2080 self.assertIn('FRED', cbfs.files)
2081 cfile1 = cbfs.files['FRED']
2082 self.assertEqual(U_BOOT_DATA, cfile1.data)
2083
2084 self.assertIn('hello', cbfs.files)
2085 cfile2 = cbfs.files['hello']
2086 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2087
Simon Glassc5ac1382019-07-08 13:18:54 -06002088 def _SetupIfwi(self, fname):
2089 """Set up to run an IFWI test
2090
2091 Args:
2092 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2093 """
2094 self._SetupSplElf()
Simon Glass2090f1e2019-08-24 07:23:00 -06002095 self._SetupTplElf()
Simon Glassc5ac1382019-07-08 13:18:54 -06002096
2097 # Intel Integrated Firmware Image (IFWI) file
2098 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2099 data = fd.read()
2100 TestFunctional._MakeInputFile(fname,data)
2101
2102 def _CheckIfwi(self, data):
2103 """Check that an image with an IFWI contains the correct output
2104
2105 Args:
2106 data: Conents of output file
2107 """
2108 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
2109 if data[:0x1000] != expected_desc:
2110 self.fail('Expected descriptor binary at start of image')
2111
2112 # We expect to find the TPL wil in subpart IBBP entry IBBL
2113 image_fname = tools.GetOutputFilename('image.bin')
2114 tpl_fname = tools.GetOutputFilename('tpl.out')
2115 tools.RunIfwiTool(image_fname, tools.CMD_EXTRACT, fname=tpl_fname,
2116 subpart='IBBP', entry_name='IBBL')
2117
2118 tpl_data = tools.ReadFile(tpl_fname)
Simon Glasse95be632019-08-24 07:22:51 -06002119 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glassc5ac1382019-07-08 13:18:54 -06002120
2121 def testPackX86RomIfwi(self):
2122 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2123 self._SetupIfwi('fitimage.bin')
Simon Glass9255f3c2019-08-24 07:23:01 -06002124 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002125 self._CheckIfwi(data)
2126
2127 def testPackX86RomIfwiNoDesc(self):
2128 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2129 self._SetupIfwi('ifwi.bin')
Simon Glass9255f3c2019-08-24 07:23:01 -06002130 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002131 self._CheckIfwi(data)
2132
2133 def testPackX86RomIfwiNoData(self):
2134 """Test that an x86 ROM with IFWI handles missing data"""
2135 self._SetupIfwi('ifwi.bin')
2136 with self.assertRaises(ValueError) as e:
Simon Glass9255f3c2019-08-24 07:23:01 -06002137 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002138 self.assertIn('Could not complete processing of contents',
2139 str(e.exception))
Simon Glass53af22a2018-07-17 13:25:32 -06002140
Simon Glasse073d4e2019-07-08 13:18:56 -06002141 def testCbfsOffset(self):
2142 """Test a CBFS with files at particular offsets
2143
2144 Like all CFBS tests, this is just checking the logic that calls
2145 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2146 """
2147 data = self._DoReadFile('114_cbfs_offset.dts')
2148 size = 0x200
2149
2150 cbfs = cbfs_util.CbfsReader(data)
2151 self.assertEqual(size, cbfs.rom_size)
2152
2153 self.assertIn('u-boot', cbfs.files)
2154 cfile = cbfs.files['u-boot']
2155 self.assertEqual(U_BOOT_DATA, cfile.data)
2156 self.assertEqual(0x40, cfile.cbfs_offset)
2157
2158 self.assertIn('u-boot-dtb', cbfs.files)
2159 cfile2 = cbfs.files['u-boot-dtb']
2160 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2161 self.assertEqual(0x140, cfile2.cbfs_offset)
2162
Simon Glass086cec92019-07-08 14:25:27 -06002163 def testFdtmap(self):
2164 """Test an FDT map can be inserted in the image"""
2165 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2166 fdtmap_data = data[len(U_BOOT_DATA):]
2167 magic = fdtmap_data[:8]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002168 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass086cec92019-07-08 14:25:27 -06002169 self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
2170
2171 fdt_data = fdtmap_data[16:]
2172 dtb = fdt.Fdt.FromData(fdt_data)
2173 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002174 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass086cec92019-07-08 14:25:27 -06002175 self.assertEqual({
2176 'image-pos': 0,
2177 'offset': 0,
2178 'u-boot:offset': 0,
2179 'u-boot:size': len(U_BOOT_DATA),
2180 'u-boot:image-pos': 0,
2181 'fdtmap:image-pos': 4,
2182 'fdtmap:offset': 4,
2183 'fdtmap:size': len(fdtmap_data),
2184 'size': len(data),
2185 }, props)
2186
2187 def testFdtmapNoMatch(self):
2188 """Check handling of an FDT map when the section cannot be found"""
2189 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2190
2191 # Mangle the section name, which should cause a mismatch between the
2192 # correct FDT path and the one expected by the section
2193 image = control.images['image']
Simon Glasscf228942019-07-08 14:25:28 -06002194 image._node.path += '-suffix'
Simon Glass086cec92019-07-08 14:25:27 -06002195 entries = image.GetEntries()
2196 fdtmap = entries['fdtmap']
2197 with self.assertRaises(ValueError) as e:
2198 fdtmap._GetFdtmap()
2199 self.assertIn("Cannot locate node for path '/binman-suffix'",
2200 str(e.exception))
2201
Simon Glasscf228942019-07-08 14:25:28 -06002202 def testFdtmapHeader(self):
2203 """Test an FDT map and image header can be inserted in the image"""
2204 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2205 fdtmap_pos = len(U_BOOT_DATA)
2206 fdtmap_data = data[fdtmap_pos:]
2207 fdt_data = fdtmap_data[16:]
2208 dtb = fdt.Fdt.FromData(fdt_data)
2209 fdt_size = dtb.GetFdtObj().totalsize()
2210 hdr_data = data[-8:]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002211 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002212 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2213 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2214
2215 def testFdtmapHeaderStart(self):
2216 """Test an image header can be inserted at the image start"""
2217 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2218 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2219 hdr_data = data[:8]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002220 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002221 offset = struct.unpack('<I', hdr_data[4:])[0]
2222 self.assertEqual(fdtmap_pos, offset)
2223
2224 def testFdtmapHeaderPos(self):
2225 """Test an image header can be inserted at a chosen position"""
2226 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2227 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2228 hdr_data = data[0x80:0x88]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002229 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002230 offset = struct.unpack('<I', hdr_data[4:])[0]
2231 self.assertEqual(fdtmap_pos, offset)
2232
2233 def testHeaderMissingFdtmap(self):
2234 """Test an image header requires an fdtmap"""
2235 with self.assertRaises(ValueError) as e:
2236 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2237 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2238 str(e.exception))
2239
2240 def testHeaderNoLocation(self):
2241 """Test an image header with a no specified location is detected"""
2242 with self.assertRaises(ValueError) as e:
2243 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2244 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2245 str(e.exception))
2246
Simon Glassc52c9e72019-07-08 14:25:37 -06002247 def testEntryExpand(self):
2248 """Test expanding an entry after it is packed"""
2249 data = self._DoReadFile('121_entry_expand.dts')
Simon Glass79d3c582019-07-20 12:23:57 -06002250 self.assertEqual(b'aaa', data[:3])
2251 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2252 self.assertEqual(b'aaa', data[-3:])
Simon Glassc52c9e72019-07-08 14:25:37 -06002253
2254 def testEntryExpandBad(self):
2255 """Test expanding an entry after it is packed, twice"""
2256 with self.assertRaises(ValueError) as e:
2257 self._DoReadFile('122_entry_expand_twice.dts')
Simon Glass61ec04f2019-07-20 12:23:58 -06002258 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glassc52c9e72019-07-08 14:25:37 -06002259 str(e.exception))
2260
2261 def testEntryExpandSection(self):
2262 """Test expanding an entry within a section after it is packed"""
2263 data = self._DoReadFile('123_entry_expand_section.dts')
Simon Glass79d3c582019-07-20 12:23:57 -06002264 self.assertEqual(b'aaa', data[:3])
2265 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2266 self.assertEqual(b'aaa', data[-3:])
Simon Glassc52c9e72019-07-08 14:25:37 -06002267
Simon Glass6c223fd2019-07-08 14:25:38 -06002268 def testCompressDtb(self):
2269 """Test that compress of device-tree files is supported"""
2270 self._CheckLz4()
2271 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2272 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2273 comp_data = data[len(U_BOOT_DATA):]
2274 orig = self._decompress(comp_data)
2275 dtb = fdt.Fdt.FromData(orig)
2276 dtb.Scan()
2277 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2278 expected = {
2279 'u-boot:size': len(U_BOOT_DATA),
2280 'u-boot-dtb:uncomp-size': len(orig),
2281 'u-boot-dtb:size': len(comp_data),
2282 'size': len(data),
2283 }
2284 self.assertEqual(expected, props)
2285
Simon Glass69f7cb32019-07-08 14:25:41 -06002286 def testCbfsUpdateFdt(self):
2287 """Test that we can update the device tree with CBFS offset/size info"""
2288 self._CheckLz4()
2289 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2290 update_dtb=True)
2291 dtb = fdt.Fdt(out_dtb_fname)
2292 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002293 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass69f7cb32019-07-08 14:25:41 -06002294 del props['cbfs/u-boot:size']
2295 self.assertEqual({
2296 'offset': 0,
2297 'size': len(data),
2298 'image-pos': 0,
2299 'cbfs:offset': 0,
2300 'cbfs:size': len(data),
2301 'cbfs:image-pos': 0,
2302 'cbfs/u-boot:offset': 0x38,
2303 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2304 'cbfs/u-boot:image-pos': 0x38,
2305 'cbfs/u-boot-dtb:offset': 0xb8,
2306 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2307 'cbfs/u-boot-dtb:image-pos': 0xb8,
2308 }, props)
2309
Simon Glass8a1ad062019-07-08 14:25:42 -06002310 def testCbfsBadType(self):
2311 """Test an image header with a no specified location is detected"""
2312 with self.assertRaises(ValueError) as e:
2313 self._DoReadFile('126_cbfs_bad_type.dts')
2314 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2315
Simon Glass41b8ba02019-07-08 14:25:43 -06002316 def testList(self):
2317 """Test listing the files in an image"""
2318 self._CheckLz4()
2319 data = self._DoReadFile('127_list.dts')
2320 image = control.images['image']
2321 entries = image.BuildEntryList()
2322 self.assertEqual(7, len(entries))
2323
2324 ent = entries[0]
2325 self.assertEqual(0, ent.indent)
2326 self.assertEqual('main-section', ent.name)
2327 self.assertEqual('section', ent.etype)
2328 self.assertEqual(len(data), ent.size)
2329 self.assertEqual(0, ent.image_pos)
2330 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002331 self.assertEqual(0, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002332
2333 ent = entries[1]
2334 self.assertEqual(1, ent.indent)
2335 self.assertEqual('u-boot', ent.name)
2336 self.assertEqual('u-boot', ent.etype)
2337 self.assertEqual(len(U_BOOT_DATA), ent.size)
2338 self.assertEqual(0, ent.image_pos)
2339 self.assertEqual(None, ent.uncomp_size)
2340 self.assertEqual(0, ent.offset)
2341
2342 ent = entries[2]
2343 self.assertEqual(1, ent.indent)
2344 self.assertEqual('section', ent.name)
2345 self.assertEqual('section', ent.etype)
2346 section_size = ent.size
2347 self.assertEqual(0x100, ent.image_pos)
2348 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002349 self.assertEqual(0x100, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002350
2351 ent = entries[3]
2352 self.assertEqual(2, ent.indent)
2353 self.assertEqual('cbfs', ent.name)
2354 self.assertEqual('cbfs', ent.etype)
2355 self.assertEqual(0x400, ent.size)
2356 self.assertEqual(0x100, ent.image_pos)
2357 self.assertEqual(None, ent.uncomp_size)
2358 self.assertEqual(0, ent.offset)
2359
2360 ent = entries[4]
2361 self.assertEqual(3, ent.indent)
2362 self.assertEqual('u-boot', ent.name)
2363 self.assertEqual('u-boot', ent.etype)
2364 self.assertEqual(len(U_BOOT_DATA), ent.size)
2365 self.assertEqual(0x138, ent.image_pos)
2366 self.assertEqual(None, ent.uncomp_size)
2367 self.assertEqual(0x38, ent.offset)
2368
2369 ent = entries[5]
2370 self.assertEqual(3, ent.indent)
2371 self.assertEqual('u-boot-dtb', ent.name)
2372 self.assertEqual('text', ent.etype)
2373 self.assertGreater(len(COMPRESS_DATA), ent.size)
2374 self.assertEqual(0x178, ent.image_pos)
2375 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2376 self.assertEqual(0x78, ent.offset)
2377
2378 ent = entries[6]
2379 self.assertEqual(2, ent.indent)
2380 self.assertEqual('u-boot-dtb', ent.name)
2381 self.assertEqual('u-boot-dtb', ent.etype)
2382 self.assertEqual(0x500, ent.image_pos)
2383 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2384 dtb_size = ent.size
2385 # Compressing this data expands it since headers are added
2386 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2387 self.assertEqual(0x400, ent.offset)
2388
2389 self.assertEqual(len(data), 0x100 + section_size)
2390 self.assertEqual(section_size, 0x400 + dtb_size)
2391
Simon Glasse1925fa2019-07-08 14:25:44 -06002392 def testFindFdtmap(self):
2393 """Test locating an FDT map in an image"""
2394 self._CheckLz4()
2395 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2396 image = control.images['image']
2397 entries = image.GetEntries()
2398 entry = entries['fdtmap']
2399 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2400
2401 def testFindFdtmapMissing(self):
2402 """Test failing to locate an FDP map"""
2403 data = self._DoReadFile('005_simple.dts')
2404 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2405
Simon Glass2d260032019-07-08 14:25:45 -06002406 def testFindImageHeader(self):
2407 """Test locating a image header"""
2408 self._CheckLz4()
Simon Glassffded752019-07-08 14:25:46 -06002409 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002410 image = control.images['image']
2411 entries = image.GetEntries()
2412 entry = entries['fdtmap']
2413 # The header should point to the FDT map
2414 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2415
2416 def testFindImageHeaderStart(self):
2417 """Test locating a image header located at the start of an image"""
Simon Glassffded752019-07-08 14:25:46 -06002418 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002419 image = control.images['image']
2420 entries = image.GetEntries()
2421 entry = entries['fdtmap']
2422 # The header should point to the FDT map
2423 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2424
2425 def testFindImageHeaderMissing(self):
2426 """Test failing to locate an image header"""
2427 data = self._DoReadFile('005_simple.dts')
2428 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2429
Simon Glassffded752019-07-08 14:25:46 -06002430 def testReadImage(self):
2431 """Test reading an image and accessing its FDT map"""
2432 self._CheckLz4()
2433 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2434 image_fname = tools.GetOutputFilename('image.bin')
2435 orig_image = control.images['image']
2436 image = Image.FromFile(image_fname)
2437 self.assertEqual(orig_image.GetEntries().keys(),
2438 image.GetEntries().keys())
2439
2440 orig_entry = orig_image.GetEntries()['fdtmap']
2441 entry = image.GetEntries()['fdtmap']
2442 self.assertEquals(orig_entry.offset, entry.offset)
2443 self.assertEquals(orig_entry.size, entry.size)
2444 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2445
2446 def testReadImageNoHeader(self):
2447 """Test accessing an image's FDT map without an image header"""
2448 self._CheckLz4()
2449 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
2450 image_fname = tools.GetOutputFilename('image.bin')
2451 image = Image.FromFile(image_fname)
2452 self.assertTrue(isinstance(image, Image))
Simon Glass10f9d002019-07-20 12:23:50 -06002453 self.assertEqual('image', image.image_name[-5:])
Simon Glassffded752019-07-08 14:25:46 -06002454
2455 def testReadImageFail(self):
2456 """Test failing to read an image image's FDT map"""
2457 self._DoReadFile('005_simple.dts')
2458 image_fname = tools.GetOutputFilename('image.bin')
2459 with self.assertRaises(ValueError) as e:
2460 image = Image.FromFile(image_fname)
2461 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glasse073d4e2019-07-08 13:18:56 -06002462
Simon Glass61f564d2019-07-08 14:25:48 -06002463 def testListCmd(self):
2464 """Test listing the files in an image using an Fdtmap"""
2465 self._CheckLz4()
2466 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2467
2468 # lz4 compression size differs depending on the version
2469 image = control.images['image']
2470 entries = image.GetEntries()
2471 section_size = entries['section'].size
2472 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2473 fdtmap_offset = entries['fdtmap'].offset
2474
Simon Glassf86a7362019-07-20 12:24:10 -06002475 try:
2476 tmpdir, updated_fname = self._SetupImageInTmpdir()
2477 with test_util.capture_sys_output() as (stdout, stderr):
2478 self._DoBinman('ls', '-i', updated_fname)
2479 finally:
2480 shutil.rmtree(tmpdir)
Simon Glass61f564d2019-07-08 14:25:48 -06002481 lines = stdout.getvalue().splitlines()
2482 expected = [
2483'Name Image-pos Size Entry-type Offset Uncomp-size',
2484'----------------------------------------------------------------------',
2485'main-section 0 c00 section 0',
2486' u-boot 0 4 u-boot 0',
2487' section 100 %x section 100' % section_size,
2488' cbfs 100 400 cbfs 0',
2489' u-boot 138 4 u-boot 38',
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002490' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glass61f564d2019-07-08 14:25:48 -06002491' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002492' fdtmap %x 3bd fdtmap %x' %
Simon Glass61f564d2019-07-08 14:25:48 -06002493 (fdtmap_offset, fdtmap_offset),
2494' image-header bf8 8 image-header bf8',
2495 ]
2496 self.assertEqual(expected, lines)
2497
2498 def testListCmdFail(self):
2499 """Test failing to list an image"""
2500 self._DoReadFile('005_simple.dts')
Simon Glassf86a7362019-07-20 12:24:10 -06002501 try:
2502 tmpdir, updated_fname = self._SetupImageInTmpdir()
2503 with self.assertRaises(ValueError) as e:
2504 self._DoBinman('ls', '-i', updated_fname)
2505 finally:
2506 shutil.rmtree(tmpdir)
Simon Glass61f564d2019-07-08 14:25:48 -06002507 self.assertIn("Cannot find FDT map in image", str(e.exception))
2508
2509 def _RunListCmd(self, paths, expected):
2510 """List out entries and check the result
2511
2512 Args:
2513 paths: List of paths to pass to the list command
2514 expected: Expected list of filenames to be returned, in order
2515 """
2516 self._CheckLz4()
2517 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2518 image_fname = tools.GetOutputFilename('image.bin')
2519 image = Image.FromFile(image_fname)
2520 lines = image.GetListEntries(paths)[1]
2521 files = [line[0].strip() for line in lines[1:]]
2522 self.assertEqual(expected, files)
2523
2524 def testListCmdSection(self):
2525 """Test listing the files in a section"""
2526 self._RunListCmd(['section'],
2527 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2528
2529 def testListCmdFile(self):
2530 """Test listing a particular file"""
2531 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2532
2533 def testListCmdWildcard(self):
2534 """Test listing a wildcarded file"""
2535 self._RunListCmd(['*boot*'],
2536 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2537
2538 def testListCmdWildcardMulti(self):
2539 """Test listing a wildcarded file"""
2540 self._RunListCmd(['*cb*', '*head*'],
2541 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2542
2543 def testListCmdEmpty(self):
2544 """Test listing a wildcarded file"""
2545 self._RunListCmd(['nothing'], [])
2546
2547 def testListCmdPath(self):
2548 """Test listing the files in a sub-entry of a section"""
2549 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2550
Simon Glassf667e452019-07-08 14:25:50 -06002551 def _RunExtractCmd(self, entry_name, decomp=True):
2552 """Extract an entry from an image
2553
2554 Args:
2555 entry_name: Entry name to extract
2556 decomp: True to decompress the data if compressed, False to leave
2557 it in its raw uncompressed format
2558
2559 Returns:
2560 data from entry
2561 """
2562 self._CheckLz4()
2563 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2564 image_fname = tools.GetOutputFilename('image.bin')
2565 return control.ReadEntry(image_fname, entry_name, decomp)
2566
2567 def testExtractSimple(self):
2568 """Test extracting a single file"""
2569 data = self._RunExtractCmd('u-boot')
2570 self.assertEqual(U_BOOT_DATA, data)
2571
Simon Glass71ce0ba2019-07-08 14:25:52 -06002572 def testExtractSection(self):
2573 """Test extracting the files in a section"""
2574 data = self._RunExtractCmd('section')
2575 cbfs_data = data[:0x400]
2576 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002577 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass71ce0ba2019-07-08 14:25:52 -06002578 dtb_data = data[0x400:]
2579 dtb = self._decompress(dtb_data)
2580 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2581
2582 def testExtractCompressed(self):
2583 """Test extracting compressed data"""
2584 data = self._RunExtractCmd('section/u-boot-dtb')
2585 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2586
2587 def testExtractRaw(self):
2588 """Test extracting compressed data without decompressing it"""
2589 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2590 dtb = self._decompress(data)
2591 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2592
2593 def testExtractCbfs(self):
2594 """Test extracting CBFS data"""
2595 data = self._RunExtractCmd('section/cbfs/u-boot')
2596 self.assertEqual(U_BOOT_DATA, data)
2597
2598 def testExtractCbfsCompressed(self):
2599 """Test extracting CBFS compressed data"""
2600 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2601 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2602
2603 def testExtractCbfsRaw(self):
2604 """Test extracting CBFS compressed data without decompressing it"""
2605 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Simon Glasseb0f4a42019-07-20 12:24:06 -06002606 dtb = tools.Decompress(data, 'lzma', with_header=False)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002607 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2608
Simon Glassf667e452019-07-08 14:25:50 -06002609 def testExtractBadEntry(self):
2610 """Test extracting a bad section path"""
2611 with self.assertRaises(ValueError) as e:
2612 self._RunExtractCmd('section/does-not-exist')
2613 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2614 str(e.exception))
2615
2616 def testExtractMissingFile(self):
2617 """Test extracting file that does not exist"""
2618 with self.assertRaises(IOError) as e:
2619 control.ReadEntry('missing-file', 'name')
2620
2621 def testExtractBadFile(self):
2622 """Test extracting an invalid file"""
2623 fname = os.path.join(self._indir, 'badfile')
2624 tools.WriteFile(fname, b'')
2625 with self.assertRaises(ValueError) as e:
2626 control.ReadEntry(fname, 'name')
2627
Simon Glass71ce0ba2019-07-08 14:25:52 -06002628 def testExtractCmd(self):
2629 """Test extracting a file fron an image on the command line"""
2630 self._CheckLz4()
2631 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass71ce0ba2019-07-08 14:25:52 -06002632 fname = os.path.join(self._indir, 'output.extact')
Simon Glassf86a7362019-07-20 12:24:10 -06002633 try:
2634 tmpdir, updated_fname = self._SetupImageInTmpdir()
2635 with test_util.capture_sys_output() as (stdout, stderr):
2636 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2637 '-f', fname)
2638 finally:
2639 shutil.rmtree(tmpdir)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002640 data = tools.ReadFile(fname)
2641 self.assertEqual(U_BOOT_DATA, data)
2642
2643 def testExtractOneEntry(self):
2644 """Test extracting a single entry fron an image """
2645 self._CheckLz4()
2646 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2647 image_fname = tools.GetOutputFilename('image.bin')
2648 fname = os.path.join(self._indir, 'output.extact')
2649 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
2650 data = tools.ReadFile(fname)
2651 self.assertEqual(U_BOOT_DATA, data)
2652
2653 def _CheckExtractOutput(self, decomp):
2654 """Helper to test file output with and without decompression
2655
2656 Args:
2657 decomp: True to decompress entry data, False to output it raw
2658 """
2659 def _CheckPresent(entry_path, expect_data, expect_size=None):
2660 """Check and remove expected file
2661
2662 This checks the data/size of a file and removes the file both from
2663 the outfiles set and from the output directory. Once all files are
2664 processed, both the set and directory should be empty.
2665
2666 Args:
2667 entry_path: Entry path
2668 expect_data: Data to expect in file, or None to skip check
2669 expect_size: Size of data to expect in file, or None to skip
2670 """
2671 path = os.path.join(outdir, entry_path)
2672 data = tools.ReadFile(path)
2673 os.remove(path)
2674 if expect_data:
2675 self.assertEqual(expect_data, data)
2676 elif expect_size:
2677 self.assertEqual(expect_size, len(data))
2678 outfiles.remove(path)
2679
2680 def _CheckDirPresent(name):
2681 """Remove expected directory
2682
2683 This gives an error if the directory does not exist as expected
2684
2685 Args:
2686 name: Name of directory to remove
2687 """
2688 path = os.path.join(outdir, name)
2689 os.rmdir(path)
2690
2691 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2692 image_fname = tools.GetOutputFilename('image.bin')
2693 outdir = os.path.join(self._indir, 'extract')
2694 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2695
2696 # Create a set of all file that were output (should be 9)
2697 outfiles = set()
2698 for root, dirs, files in os.walk(outdir):
2699 outfiles |= set([os.path.join(root, fname) for fname in files])
2700 self.assertEqual(9, len(outfiles))
2701 self.assertEqual(9, len(einfos))
2702
2703 image = control.images['image']
2704 entries = image.GetEntries()
2705
2706 # Check the 9 files in various ways
2707 section = entries['section']
2708 section_entries = section.GetEntries()
2709 cbfs_entries = section_entries['cbfs'].GetEntries()
2710 _CheckPresent('u-boot', U_BOOT_DATA)
2711 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
2712 dtb_len = EXTRACT_DTB_SIZE
2713 if not decomp:
2714 dtb_len = cbfs_entries['u-boot-dtb'].size
2715 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
2716 if not decomp:
2717 dtb_len = section_entries['u-boot-dtb'].size
2718 _CheckPresent('section/u-boot-dtb', None, dtb_len)
2719
2720 fdtmap = entries['fdtmap']
2721 _CheckPresent('fdtmap', fdtmap.data)
2722 hdr = entries['image-header']
2723 _CheckPresent('image-header', hdr.data)
2724
2725 _CheckPresent('section/root', section.data)
2726 cbfs = section_entries['cbfs']
2727 _CheckPresent('section/cbfs/root', cbfs.data)
2728 data = tools.ReadFile(image_fname)
2729 _CheckPresent('root', data)
2730
2731 # There should be no files left. Remove all the directories to check.
2732 # If there are any files/dirs remaining, one of these checks will fail.
2733 self.assertEqual(0, len(outfiles))
2734 _CheckDirPresent('section/cbfs')
2735 _CheckDirPresent('section')
2736 _CheckDirPresent('')
2737 self.assertFalse(os.path.exists(outdir))
2738
2739 def testExtractAllEntries(self):
2740 """Test extracting all entries"""
2741 self._CheckLz4()
2742 self._CheckExtractOutput(decomp=True)
2743
2744 def testExtractAllEntriesRaw(self):
2745 """Test extracting all entries without decompressing them"""
2746 self._CheckLz4()
2747 self._CheckExtractOutput(decomp=False)
2748
2749 def testExtractSelectedEntries(self):
2750 """Test extracting some entries"""
2751 self._CheckLz4()
2752 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2753 image_fname = tools.GetOutputFilename('image.bin')
2754 outdir = os.path.join(self._indir, 'extract')
2755 einfos = control.ExtractEntries(image_fname, None, outdir,
2756 ['*cb*', '*head*'])
2757
2758 # File output is tested by testExtractAllEntries(), so just check that
2759 # the expected entries are selected
2760 names = [einfo.name for einfo in einfos]
2761 self.assertEqual(names,
2762 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2763
2764 def testExtractNoEntryPaths(self):
2765 """Test extracting some entries"""
2766 self._CheckLz4()
2767 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2768 image_fname = tools.GetOutputFilename('image.bin')
2769 with self.assertRaises(ValueError) as e:
2770 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassbb5edc12019-07-20 12:24:14 -06002771 self.assertIn('Must specify an entry path to write with -f',
Simon Glass71ce0ba2019-07-08 14:25:52 -06002772 str(e.exception))
2773
2774 def testExtractTooManyEntryPaths(self):
2775 """Test extracting some entries"""
2776 self._CheckLz4()
2777 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2778 image_fname = tools.GetOutputFilename('image.bin')
2779 with self.assertRaises(ValueError) as e:
2780 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassbb5edc12019-07-20 12:24:14 -06002781 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass71ce0ba2019-07-08 14:25:52 -06002782 str(e.exception))
2783
Simon Glasse2705fa2019-07-08 14:25:53 -06002784 def testPackAlignSection(self):
2785 """Test that sections can have alignment"""
2786 self._DoReadFile('131_pack_align_section.dts')
2787
2788 self.assertIn('image', control.images)
2789 image = control.images['image']
2790 entries = image.GetEntries()
2791 self.assertEqual(3, len(entries))
2792
2793 # First u-boot
2794 self.assertIn('u-boot', entries)
2795 entry = entries['u-boot']
2796 self.assertEqual(0, entry.offset)
2797 self.assertEqual(0, entry.image_pos)
2798 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2799 self.assertEqual(len(U_BOOT_DATA), entry.size)
2800
2801 # Section0
2802 self.assertIn('section0', entries)
2803 section0 = entries['section0']
2804 self.assertEqual(0x10, section0.offset)
2805 self.assertEqual(0x10, section0.image_pos)
2806 self.assertEqual(len(U_BOOT_DATA), section0.size)
2807
2808 # Second u-boot
2809 section_entries = section0.GetEntries()
2810 self.assertIn('u-boot', section_entries)
2811 entry = section_entries['u-boot']
2812 self.assertEqual(0, entry.offset)
2813 self.assertEqual(0x10, entry.image_pos)
2814 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2815 self.assertEqual(len(U_BOOT_DATA), entry.size)
2816
2817 # Section1
2818 self.assertIn('section1', entries)
2819 section1 = entries['section1']
2820 self.assertEqual(0x14, section1.offset)
2821 self.assertEqual(0x14, section1.image_pos)
2822 self.assertEqual(0x20, section1.size)
2823
2824 # Second u-boot
2825 section_entries = section1.GetEntries()
2826 self.assertIn('u-boot', section_entries)
2827 entry = section_entries['u-boot']
2828 self.assertEqual(0, entry.offset)
2829 self.assertEqual(0x14, entry.image_pos)
2830 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2831 self.assertEqual(len(U_BOOT_DATA), entry.size)
2832
2833 # Section2
2834 self.assertIn('section2', section_entries)
2835 section2 = section_entries['section2']
2836 self.assertEqual(0x4, section2.offset)
2837 self.assertEqual(0x18, section2.image_pos)
2838 self.assertEqual(4, section2.size)
2839
2840 # Third u-boot
2841 section_entries = section2.GetEntries()
2842 self.assertIn('u-boot', section_entries)
2843 entry = section_entries['u-boot']
2844 self.assertEqual(0, entry.offset)
2845 self.assertEqual(0x18, entry.image_pos)
2846 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2847 self.assertEqual(len(U_BOOT_DATA), entry.size)
2848
Simon Glass51014aa2019-07-20 12:23:56 -06002849 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
2850 dts='132_replace.dts'):
Simon Glass10f9d002019-07-20 12:23:50 -06002851 """Replace an entry in an image
2852
2853 This writes the entry data to update it, then opens the updated file and
2854 returns the value that it now finds there.
2855
2856 Args:
2857 entry_name: Entry name to replace
2858 data: Data to replace it with
2859 decomp: True to compress the data if needed, False if data is
2860 already compressed so should be used as is
Simon Glass51014aa2019-07-20 12:23:56 -06002861 allow_resize: True to allow entries to change size, False to raise
2862 an exception
Simon Glass10f9d002019-07-20 12:23:50 -06002863
2864 Returns:
2865 Tuple:
2866 data from entry
2867 data from fdtmap (excluding header)
Simon Glass51014aa2019-07-20 12:23:56 -06002868 Image object that was modified
Simon Glass10f9d002019-07-20 12:23:50 -06002869 """
Simon Glass51014aa2019-07-20 12:23:56 -06002870 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass10f9d002019-07-20 12:23:50 -06002871 update_dtb=True)[1]
2872
2873 self.assertIn('image', control.images)
2874 image = control.images['image']
2875 entries = image.GetEntries()
2876 orig_dtb_data = entries['u-boot-dtb'].data
2877 orig_fdtmap_data = entries['fdtmap'].data
2878
2879 image_fname = tools.GetOutputFilename('image.bin')
2880 updated_fname = tools.GetOutputFilename('image-updated.bin')
2881 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
Simon Glass51014aa2019-07-20 12:23:56 -06002882 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
2883 allow_resize)
Simon Glass10f9d002019-07-20 12:23:50 -06002884 data = control.ReadEntry(updated_fname, entry_name, decomp)
2885
Simon Glass51014aa2019-07-20 12:23:56 -06002886 # The DT data should not change unless resized:
2887 if not allow_resize:
2888 new_dtb_data = entries['u-boot-dtb'].data
2889 self.assertEqual(new_dtb_data, orig_dtb_data)
2890 new_fdtmap_data = entries['fdtmap'].data
2891 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass10f9d002019-07-20 12:23:50 -06002892
Simon Glass51014aa2019-07-20 12:23:56 -06002893 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass10f9d002019-07-20 12:23:50 -06002894
2895 def testReplaceSimple(self):
2896 """Test replacing a single file"""
2897 expected = b'x' * len(U_BOOT_DATA)
Simon Glass51014aa2019-07-20 12:23:56 -06002898 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
2899 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06002900 self.assertEqual(expected, data)
2901
2902 # Test that the state looks right. There should be an FDT for the fdtmap
2903 # that we jsut read back in, and it should match what we find in the
2904 # 'control' tables. Checking for an FDT that does not exist should
2905 # return None.
2906 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glass51014aa2019-07-20 12:23:56 -06002907 self.assertIsNotNone(path)
Simon Glass10f9d002019-07-20 12:23:50 -06002908 self.assertEqual(expected_fdtmap, fdtmap)
2909
2910 dtb = state.GetFdtForEtype('fdtmap')
2911 self.assertEqual(dtb.GetContents(), fdtmap)
2912
2913 missing_path, missing_fdtmap = state.GetFdtContents('missing')
2914 self.assertIsNone(missing_path)
2915 self.assertIsNone(missing_fdtmap)
2916
2917 missing_dtb = state.GetFdtForEtype('missing')
2918 self.assertIsNone(missing_dtb)
2919
2920 self.assertEqual('/binman', state.fdt_path_prefix)
2921
2922 def testReplaceResizeFail(self):
2923 """Test replacing a file by something larger"""
2924 expected = U_BOOT_DATA + b'x'
2925 with self.assertRaises(ValueError) as e:
Simon Glass51014aa2019-07-20 12:23:56 -06002926 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
2927 dts='139_replace_repack.dts')
Simon Glass10f9d002019-07-20 12:23:50 -06002928 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
2929 str(e.exception))
2930
2931 def testReplaceMulti(self):
2932 """Test replacing entry data where multiple images are generated"""
2933 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
2934 update_dtb=True)[0]
2935 expected = b'x' * len(U_BOOT_DATA)
2936 updated_fname = tools.GetOutputFilename('image-updated.bin')
2937 tools.WriteFile(updated_fname, data)
2938 entry_name = 'u-boot'
Simon Glass51014aa2019-07-20 12:23:56 -06002939 control.WriteEntry(updated_fname, entry_name, expected,
2940 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06002941 data = control.ReadEntry(updated_fname, entry_name)
2942 self.assertEqual(expected, data)
2943
2944 # Check the state looks right.
2945 self.assertEqual('/binman/image', state.fdt_path_prefix)
2946
2947 # Now check we can write the first image
2948 image_fname = tools.GetOutputFilename('first-image.bin')
2949 updated_fname = tools.GetOutputFilename('first-updated.bin')
2950 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
2951 entry_name = 'u-boot'
Simon Glass51014aa2019-07-20 12:23:56 -06002952 control.WriteEntry(updated_fname, entry_name, expected,
2953 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06002954 data = control.ReadEntry(updated_fname, entry_name)
2955 self.assertEqual(expected, data)
2956
2957 # Check the state looks right.
2958 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass8beb11e2019-07-08 14:25:47 -06002959
Simon Glass12bb1a92019-07-20 12:23:51 -06002960 def testUpdateFdtAllRepack(self):
2961 """Test that all device trees are updated with offset/size info"""
2962 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
2963 SECTION_SIZE = 0x300
2964 DTB_SIZE = 602
2965 FDTMAP_SIZE = 608
2966 base_expected = {
2967 'offset': 0,
2968 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
2969 'image-pos': 0,
2970 'section:offset': 0,
2971 'section:size': SECTION_SIZE,
2972 'section:image-pos': 0,
2973 'section/u-boot-dtb:offset': 4,
2974 'section/u-boot-dtb:size': 636,
2975 'section/u-boot-dtb:image-pos': 4,
2976 'u-boot-spl-dtb:offset': SECTION_SIZE,
2977 'u-boot-spl-dtb:size': DTB_SIZE,
2978 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
2979 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
2980 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
2981 'u-boot-tpl-dtb:size': DTB_SIZE,
2982 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
2983 'fdtmap:size': FDTMAP_SIZE,
2984 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
2985 }
2986 main_expected = {
2987 'section:orig-size': SECTION_SIZE,
2988 'section/u-boot-dtb:orig-offset': 4,
2989 }
2990
2991 # We expect three device-tree files in the output, with the first one
2992 # within a fixed-size section.
2993 # Read them in sequence. We look for an 'spl' property in the SPL tree,
2994 # and 'tpl' in the TPL tree, to make sure they are distinct from the
2995 # main U-Boot tree. All three should have the same positions and offset
2996 # except that the main tree should include the main_expected properties
2997 start = 4
2998 for item in ['', 'spl', 'tpl', None]:
2999 if item is None:
3000 start += 16 # Move past fdtmap header
3001 dtb = fdt.Fdt.FromData(data[start:])
3002 dtb.Scan()
3003 props = self._GetPropTree(dtb,
3004 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3005 prefix='/' if item is None else '/binman/')
3006 expected = dict(base_expected)
3007 if item:
3008 expected[item] = 0
3009 else:
3010 # Main DTB and fdtdec should include the 'orig-' properties
3011 expected.update(main_expected)
3012 # Helpful for debugging:
3013 #for prop in sorted(props):
3014 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3015 self.assertEqual(expected, props)
3016 if item == '':
3017 start = SECTION_SIZE
3018 else:
3019 start += dtb._fdt_obj.totalsize()
3020
Simon Glasseba1f0c2019-07-20 12:23:55 -06003021 def testFdtmapHeaderMiddle(self):
3022 """Test an FDT map in the middle of an image when it should be at end"""
3023 with self.assertRaises(ValueError) as e:
3024 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3025 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3026 str(e.exception))
3027
3028 def testFdtmapHeaderStartBad(self):
3029 """Test an FDT map in middle of an image when it should be at start"""
3030 with self.assertRaises(ValueError) as e:
3031 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3032 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3033 str(e.exception))
3034
3035 def testFdtmapHeaderEndBad(self):
3036 """Test an FDT map at the start of an image when it should be at end"""
3037 with self.assertRaises(ValueError) as e:
3038 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3039 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3040 str(e.exception))
3041
3042 def testFdtmapHeaderNoSize(self):
3043 """Test an image header at the end of an image with undefined size"""
3044 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3045
Simon Glass51014aa2019-07-20 12:23:56 -06003046 def testReplaceResize(self):
3047 """Test replacing a single file in an entry with a larger file"""
3048 expected = U_BOOT_DATA + b'x'
3049 data, _, image = self._RunReplaceCmd('u-boot', expected,
3050 dts='139_replace_repack.dts')
3051 self.assertEqual(expected, data)
3052
3053 entries = image.GetEntries()
3054 dtb_data = entries['u-boot-dtb'].data
3055 dtb = fdt.Fdt.FromData(dtb_data)
3056 dtb.Scan()
3057
3058 # The u-boot section should now be larger in the dtb
3059 node = dtb.GetNode('/binman/u-boot')
3060 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3061
3062 # Same for the fdtmap
3063 fdata = entries['fdtmap'].data
3064 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3065 fdtb.Scan()
3066 fnode = fdtb.GetNode('/u-boot')
3067 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3068
3069 def testReplaceResizeNoRepack(self):
3070 """Test replacing an entry with a larger file when not allowed"""
3071 expected = U_BOOT_DATA + b'x'
3072 with self.assertRaises(ValueError) as e:
3073 self._RunReplaceCmd('u-boot', expected)
3074 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3075 str(e.exception))
3076
Simon Glass61ec04f2019-07-20 12:23:58 -06003077 def testEntryShrink(self):
3078 """Test contracting an entry after it is packed"""
3079 try:
3080 state.SetAllowEntryContraction(True)
3081 data = self._DoReadFileDtb('140_entry_shrink.dts',
3082 update_dtb=True)[0]
3083 finally:
3084 state.SetAllowEntryContraction(False)
3085 self.assertEqual(b'a', data[:1])
3086 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3087 self.assertEqual(b'a', data[-1:])
3088
3089 def testEntryShrinkFail(self):
3090 """Test not being allowed to contract an entry after it is packed"""
3091 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3092
3093 # In this case there is a spare byte at the end of the data. The size of
3094 # the contents is only 1 byte but we still have the size before it
3095 # shrunk.
3096 self.assertEqual(b'a\0', data[:2])
3097 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3098 self.assertEqual(b'a\0', data[-2:])
3099
Simon Glass27145fd2019-07-20 12:24:01 -06003100 def testDescriptorOffset(self):
3101 """Test that the Intel descriptor is always placed at at the start"""
3102 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3103 image = control.images['image']
3104 entries = image.GetEntries()
3105 desc = entries['intel-descriptor']
3106 self.assertEqual(0xff800000, desc.offset);
3107 self.assertEqual(0xff800000, desc.image_pos);
3108
Simon Glasseb0f4a42019-07-20 12:24:06 -06003109 def testReplaceCbfs(self):
3110 """Test replacing a single file in CBFS without changing the size"""
3111 self._CheckLz4()
3112 expected = b'x' * len(U_BOOT_DATA)
3113 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3114 updated_fname = tools.GetOutputFilename('image-updated.bin')
3115 tools.WriteFile(updated_fname, data)
3116 entry_name = 'section/cbfs/u-boot'
3117 control.WriteEntry(updated_fname, entry_name, expected,
3118 allow_resize=True)
3119 data = control.ReadEntry(updated_fname, entry_name)
3120 self.assertEqual(expected, data)
3121
3122 def testReplaceResizeCbfs(self):
3123 """Test replacing a single file in CBFS with one of a different size"""
3124 self._CheckLz4()
3125 expected = U_BOOT_DATA + b'x'
3126 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3127 updated_fname = tools.GetOutputFilename('image-updated.bin')
3128 tools.WriteFile(updated_fname, data)
3129 entry_name = 'section/cbfs/u-boot'
3130 control.WriteEntry(updated_fname, entry_name, expected,
3131 allow_resize=True)
3132 data = control.ReadEntry(updated_fname, entry_name)
3133 self.assertEqual(expected, data)
3134
Simon Glassa6cb9952019-07-20 12:24:15 -06003135 def _SetupForReplace(self):
3136 """Set up some files to use to replace entries
3137
3138 This generates an image, copies it to a new file, extracts all the files
3139 in it and updates some of them
3140
3141 Returns:
3142 List
3143 Image filename
3144 Output directory
3145 Expected values for updated entries, each a string
3146 """
3147 data = self._DoReadFileRealDtb('143_replace_all.dts')
3148
3149 updated_fname = tools.GetOutputFilename('image-updated.bin')
3150 tools.WriteFile(updated_fname, data)
3151
3152 outdir = os.path.join(self._indir, 'extract')
3153 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3154
3155 expected1 = b'x' + U_BOOT_DATA + b'y'
3156 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3157 tools.WriteFile(u_boot_fname1, expected1)
3158
3159 expected2 = b'a' + U_BOOT_DATA + b'b'
3160 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
3161 tools.WriteFile(u_boot_fname2, expected2)
3162
3163 expected_text = b'not the same text'
3164 text_fname = os.path.join(outdir, 'text')
3165 tools.WriteFile(text_fname, expected_text)
3166
3167 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3168 dtb = fdt.FdtScan(dtb_fname)
3169 node = dtb.GetNode('/binman/text')
3170 node.AddString('my-property', 'the value')
3171 dtb.Sync(auto_resize=True)
3172 dtb.Flush()
3173
3174 return updated_fname, outdir, expected1, expected2, expected_text
3175
3176 def _CheckReplaceMultiple(self, entry_paths):
3177 """Handle replacing the contents of multiple entries
3178
3179 Args:
3180 entry_paths: List of entry paths to replace
3181
3182 Returns:
3183 List
3184 Dict of entries in the image:
3185 key: Entry name
3186 Value: Entry object
3187 Expected values for updated entries, each a string
3188 """
3189 updated_fname, outdir, expected1, expected2, expected_text = (
3190 self._SetupForReplace())
3191 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3192
3193 image = Image.FromFile(updated_fname)
3194 image.LoadData()
3195 return image.GetEntries(), expected1, expected2, expected_text
3196
3197 def testReplaceAll(self):
3198 """Test replacing the contents of all entries"""
3199 entries, expected1, expected2, expected_text = (
3200 self._CheckReplaceMultiple([]))
3201 data = entries['u-boot'].data
3202 self.assertEqual(expected1, data)
3203
3204 data = entries['u-boot2'].data
3205 self.assertEqual(expected2, data)
3206
3207 data = entries['text'].data
3208 self.assertEqual(expected_text, data)
3209
3210 # Check that the device tree is updated
3211 data = entries['u-boot-dtb'].data
3212 dtb = fdt.Fdt.FromData(data)
3213 dtb.Scan()
3214 node = dtb.GetNode('/binman/text')
3215 self.assertEqual('the value', node.props['my-property'].value)
3216
3217 def testReplaceSome(self):
3218 """Test replacing the contents of a few entries"""
3219 entries, expected1, expected2, expected_text = (
3220 self._CheckReplaceMultiple(['u-boot2', 'text']))
3221
3222 # This one should not change
3223 data = entries['u-boot'].data
3224 self.assertEqual(U_BOOT_DATA, data)
3225
3226 data = entries['u-boot2'].data
3227 self.assertEqual(expected2, data)
3228
3229 data = entries['text'].data
3230 self.assertEqual(expected_text, data)
3231
3232 def testReplaceCmd(self):
3233 """Test replacing a file fron an image on the command line"""
3234 self._DoReadFileRealDtb('143_replace_all.dts')
3235
3236 try:
3237 tmpdir, updated_fname = self._SetupImageInTmpdir()
3238
3239 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3240 expected = b'x' * len(U_BOOT_DATA)
3241 tools.WriteFile(fname, expected)
3242
3243 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
3244 data = tools.ReadFile(updated_fname)
3245 self.assertEqual(expected, data[:len(expected)])
3246 map_fname = os.path.join(tmpdir, 'image-updated.map')
3247 self.assertFalse(os.path.exists(map_fname))
3248 finally:
3249 shutil.rmtree(tmpdir)
3250
3251 def testReplaceCmdSome(self):
3252 """Test replacing some files fron an image on the command line"""
3253 updated_fname, outdir, expected1, expected2, expected_text = (
3254 self._SetupForReplace())
3255
3256 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3257 'u-boot2', 'text')
3258
3259 tools.PrepareOutputDir(None)
3260 image = Image.FromFile(updated_fname)
3261 image.LoadData()
3262 entries = image.GetEntries()
3263
3264 # This one should not change
3265 data = entries['u-boot'].data
3266 self.assertEqual(U_BOOT_DATA, data)
3267
3268 data = entries['u-boot2'].data
3269 self.assertEqual(expected2, data)
3270
3271 data = entries['text'].data
3272 self.assertEqual(expected_text, data)
3273
3274 def testReplaceMissing(self):
3275 """Test replacing entries where the file is missing"""
3276 updated_fname, outdir, expected1, expected2, expected_text = (
3277 self._SetupForReplace())
3278
3279 # Remove one of the files, to generate a warning
3280 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3281 os.remove(u_boot_fname1)
3282
3283 with test_util.capture_sys_output() as (stdout, stderr):
3284 control.ReplaceEntries(updated_fname, None, outdir, [])
3285 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass38fdb4c2020-07-09 18:39:39 -06003286 stderr.getvalue())
Simon Glassa6cb9952019-07-20 12:24:15 -06003287
3288 def testReplaceCmdMap(self):
3289 """Test replacing a file fron an image on the command line"""
3290 self._DoReadFileRealDtb('143_replace_all.dts')
3291
3292 try:
3293 tmpdir, updated_fname = self._SetupImageInTmpdir()
3294
3295 fname = os.path.join(self._indir, 'update-u-boot.bin')
3296 expected = b'x' * len(U_BOOT_DATA)
3297 tools.WriteFile(fname, expected)
3298
3299 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3300 '-f', fname, '-m')
3301 map_fname = os.path.join(tmpdir, 'image-updated.map')
3302 self.assertTrue(os.path.exists(map_fname))
3303 finally:
3304 shutil.rmtree(tmpdir)
3305
3306 def testReplaceNoEntryPaths(self):
3307 """Test replacing an entry without an entry path"""
3308 self._DoReadFileRealDtb('143_replace_all.dts')
3309 image_fname = tools.GetOutputFilename('image.bin')
3310 with self.assertRaises(ValueError) as e:
3311 control.ReplaceEntries(image_fname, 'fname', None, [])
3312 self.assertIn('Must specify an entry path to read with -f',
3313 str(e.exception))
3314
3315 def testReplaceTooManyEntryPaths(self):
3316 """Test extracting some entries"""
3317 self._DoReadFileRealDtb('143_replace_all.dts')
3318 image_fname = tools.GetOutputFilename('image.bin')
3319 with self.assertRaises(ValueError) as e:
3320 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3321 self.assertIn('Must specify exactly one entry path to write with -f',
3322 str(e.exception))
3323
Simon Glass2250ee62019-08-24 07:22:48 -06003324 def testPackReset16(self):
3325 """Test that an image with an x86 reset16 region can be created"""
3326 data = self._DoReadFile('144_x86_reset16.dts')
3327 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3328
3329 def testPackReset16Spl(self):
3330 """Test that an image with an x86 reset16-spl region can be created"""
3331 data = self._DoReadFile('145_x86_reset16_spl.dts')
3332 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3333
3334 def testPackReset16Tpl(self):
3335 """Test that an image with an x86 reset16-tpl region can be created"""
3336 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3337 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3338
Simon Glass5af12072019-08-24 07:22:50 -06003339 def testPackIntelFit(self):
3340 """Test that an image with an Intel FIT and pointer can be created"""
3341 data = self._DoReadFile('147_intel_fit.dts')
3342 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3343 fit = data[16:32];
3344 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3345 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3346
3347 image = control.images['image']
3348 entries = image.GetEntries()
3349 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3350 self.assertEqual(expected_ptr, ptr)
3351
3352 def testPackIntelFitMissing(self):
3353 """Test detection of a FIT pointer with not FIT region"""
3354 with self.assertRaises(ValueError) as e:
3355 self._DoReadFile('148_intel_fit_missing.dts')
3356 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3357 str(e.exception))
3358
Simon Glass7c150132019-11-06 17:22:44 -07003359 def _CheckSymbolsTplSection(self, dts, expected_vals):
3360 data = self._DoReadFile(dts)
3361 sym_values = struct.pack('<LQLL', *expected_vals)
Simon Glass2090f1e2019-08-24 07:23:00 -06003362 upto1 = 4 + len(U_BOOT_SPL_DATA)
Simon Glassb87064c2019-08-24 07:23:05 -06003363 expected1 = tools.GetBytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[20:]
Simon Glass2090f1e2019-08-24 07:23:00 -06003364 self.assertEqual(expected1, data[:upto1])
3365
3366 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Simon Glassb87064c2019-08-24 07:23:05 -06003367 expected2 = tools.GetBytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[20:]
Simon Glass2090f1e2019-08-24 07:23:00 -06003368 self.assertEqual(expected2, data[upto1:upto2])
3369
Simon Glasseb0086f2019-08-24 07:23:04 -06003370 upto3 = 0x34 + len(U_BOOT_DATA)
3371 expected3 = tools.GetBytes(0xff, 1) + U_BOOT_DATA
Simon Glass2090f1e2019-08-24 07:23:00 -06003372 self.assertEqual(expected3, data[upto2:upto3])
3373
Simon Glassb87064c2019-08-24 07:23:05 -06003374 expected4 = sym_values + U_BOOT_TPL_DATA[20:]
Simon Glass7c150132019-11-06 17:22:44 -07003375 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3376
3377 def testSymbolsTplSection(self):
3378 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3379 self._SetupSplElf('u_boot_binman_syms')
3380 self._SetupTplElf('u_boot_binman_syms')
3381 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
3382 [0x04, 0x1c, 0x10 + 0x34, 0x04])
3383
3384 def testSymbolsTplSectionX86(self):
3385 """Test binman can assign symbols in a section with end-at-4gb"""
3386 self._SetupSplElf('u_boot_binman_syms_x86')
3387 self._SetupTplElf('u_boot_binman_syms_x86')
3388 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
3389 [0xffffff04, 0xffffff1c, 0xffffff34,
3390 0x04])
Simon Glass2090f1e2019-08-24 07:23:00 -06003391
Simon Glassbf4d0e22019-08-24 07:23:03 -06003392 def testPackX86RomIfwiSectiom(self):
3393 """Test that a section can be placed in an IFWI region"""
3394 self._SetupIfwi('fitimage.bin')
3395 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3396 self._CheckIfwi(data)
3397
Simon Glassea0fff92019-08-24 07:23:07 -06003398 def testPackFspM(self):
3399 """Test that an image with a FSP memory-init binary can be created"""
3400 data = self._DoReadFile('152_intel_fsp_m.dts')
3401 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3402
Simon Glassbc6a88f2019-10-20 21:31:35 -06003403 def testPackFspS(self):
3404 """Test that an image with a FSP silicon-init binary can be created"""
3405 data = self._DoReadFile('153_intel_fsp_s.dts')
3406 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassea0fff92019-08-24 07:23:07 -06003407
Simon Glass998d1482019-10-20 21:31:36 -06003408 def testPackFspT(self):
3409 """Test that an image with a FSP temp-ram-init binary can be created"""
3410 data = self._DoReadFile('154_intel_fsp_t.dts')
3411 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3412
Simon Glass0dc706f2020-07-09 18:39:31 -06003413 def testMkimage(self):
3414 """Test using mkimage to build an image"""
3415 data = self._DoReadFile('156_mkimage.dts')
3416
3417 # Just check that the data appears in the file somewhere
3418 self.assertIn(U_BOOT_SPL_DATA, data)
3419
Simon Glassce867ad2020-07-09 18:39:36 -06003420 def testExtblob(self):
3421 """Test an image with an external blob"""
3422 data = self._DoReadFile('157_blob_ext.dts')
3423 self.assertEqual(REFCODE_DATA, data)
3424
3425 def testExtblobMissing(self):
3426 """Test an image with a missing external blob"""
3427 with self.assertRaises(ValueError) as e:
3428 self._DoReadFile('158_blob_ext_missing.dts')
3429 self.assertIn("Filename 'missing-file' not found in input path",
3430 str(e.exception))
3431
Simon Glass4f9f1052020-07-09 18:39:38 -06003432 def testExtblobMissingOk(self):
3433 """Test an image with an missing external blob that is allowed"""
Simon Glassb1cca952020-07-09 18:39:40 -06003434 with test_util.capture_sys_output() as (stdout, stderr):
3435 self._DoTestFile('158_blob_ext_missing.dts', allow_missing=True)
3436 err = stderr.getvalue()
3437 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
3438
3439 def testExtblobMissingOkSect(self):
3440 """Test an image with an missing external blob that is allowed"""
3441 with test_util.capture_sys_output() as (stdout, stderr):
3442 self._DoTestFile('159_blob_ext_missing_sect.dts',
3443 allow_missing=True)
3444 err = stderr.getvalue()
3445 self.assertRegex(err, "Image 'main-section'.*missing.*: "
3446 "blob-ext blob-ext2")
Simon Glass4f9f1052020-07-09 18:39:38 -06003447
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003448 def testPackX86RomMeMissingDesc(self):
3449 """Test that an missing Intel descriptor entry is allowed"""
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003450 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass52b10dd2020-07-25 15:11:19 -06003451 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003452 err = stderr.getvalue()
3453 self.assertRegex(err,
3454 "Image 'main-section'.*missing.*: intel-descriptor")
3455
3456 def testPackX86RomMissingIfwi(self):
3457 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3458 self._SetupIfwi('fitimage.bin')
3459 pathname = os.path.join(self._indir, 'fitimage.bin')
3460 os.remove(pathname)
3461 with test_util.capture_sys_output() as (stdout, stderr):
3462 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3463 err = stderr.getvalue()
3464 self.assertRegex(err, "Image 'main-section'.*missing.*: intel-ifwi")
3465
Simon Glassb3295fd2020-07-09 18:39:42 -06003466 def testPackOverlap(self):
3467 """Test that zero-size overlapping regions are ignored"""
3468 self._DoTestFile('160_pack_overlap_zero.dts')
3469
Simon Glassfdc34362020-07-09 18:39:45 -06003470 def testSimpleFit(self):
3471 """Test an image with a FIT inside"""
3472 data = self._DoReadFile('161_fit.dts')
3473 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3474 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3475 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3476
3477 # The data should be inside the FIT
3478 dtb = fdt.Fdt.FromData(fit_data)
3479 dtb.Scan()
3480 fnode = dtb.GetNode('/images/kernel')
3481 self.assertIn('data', fnode.props)
3482
3483 fname = os.path.join(self._indir, 'fit_data.fit')
3484 tools.WriteFile(fname, fit_data)
3485 out = tools.Run('dumpimage', '-l', fname)
3486
3487 # Check a few features to make sure the plumbing works. We don't need
3488 # to test the operation of mkimage or dumpimage here. First convert the
3489 # output into a dict where the keys are the fields printed by dumpimage
3490 # and the values are a list of values for each field
3491 lines = out.splitlines()
3492
3493 # Converts "Compression: gzip compressed" into two groups:
3494 # 'Compression' and 'gzip compressed'
3495 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3496 vals = collections.defaultdict(list)
3497 for line in lines:
3498 mat = re_line.match(line)
3499 vals[mat.group(1)].append(mat.group(2))
3500
3501 self.assertEquals('FIT description: test-desc', lines[0])
3502 self.assertIn('Created:', lines[1])
3503 self.assertIn('Image 0 (kernel)', vals)
3504 self.assertIn('Hash value', vals)
3505 data_sizes = vals.get('Data Size')
3506 self.assertIsNotNone(data_sizes)
3507 self.assertEqual(2, len(data_sizes))
3508 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
3509 self.assertEqual(len(U_BOOT_DATA), int(data_sizes[0].split()[0]))
3510 self.assertEqual(len(U_BOOT_SPL_DTB_DATA), int(data_sizes[1].split()[0]))
3511
3512 def testFitExternal(self):
Simon Glasse9d336d2020-09-01 05:13:55 -06003513 """Test an image with an FIT with external images"""
Simon Glassfdc34362020-07-09 18:39:45 -06003514 data = self._DoReadFile('162_fit_external.dts')
3515 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3516
3517 # The data should be outside the FIT
3518 dtb = fdt.Fdt.FromData(fit_data)
3519 dtb.Scan()
3520 fnode = dtb.GetNode('/images/kernel')
3521 self.assertNotIn('data', fnode.props)
Simon Glass12bb1a92019-07-20 12:23:51 -06003522
Alper Nebi Yasak8001d0b2020-08-31 12:58:18 +03003523 def testSectionIgnoreHashSignature(self):
3524 """Test that sections ignore hash, signature nodes for its data"""
3525 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
3526 expected = (U_BOOT_DATA + U_BOOT_DATA)
3527 self.assertEqual(expected, data)
3528
Alper Nebi Yasak3fdeb142020-08-31 12:58:19 +03003529 def testPadInSections(self):
3530 """Test pad-before, pad-after for entries in sections"""
3531 data = self._DoReadFile('166_pad_in_sections.dts')
3532 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
3533 U_BOOT_DATA + tools.GetBytes(ord('!'), 6) +
3534 U_BOOT_DATA)
3535 self.assertEqual(expected, data)
3536
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03003537 def testFitImageSubentryAlignment(self):
3538 """Test relative alignability of FIT image subentries"""
3539 entry_args = {
3540 'test-id': TEXT_DATA,
3541 }
3542 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
3543 entry_args=entry_args)
3544 dtb = fdt.Fdt.FromData(data)
3545 dtb.Scan()
3546
3547 node = dtb.GetNode('/images/kernel')
3548 data = dtb.GetProps(node)["data"].bytes
3549 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
3550 expected = (tools.GetBytes(0, 0x20) + U_BOOT_SPL_DATA +
3551 tools.GetBytes(0, align_pad) + U_BOOT_DATA)
3552 self.assertEqual(expected, data)
3553
3554 node = dtb.GetNode('/images/fdt-1')
3555 data = dtb.GetProps(node)["data"].bytes
3556 expected = (U_BOOT_SPL_DTB_DATA + tools.GetBytes(0, 20) +
3557 tools.ToBytes(TEXT_DATA) + tools.GetBytes(0, 30) +
3558 U_BOOT_DTB_DATA)
3559 self.assertEqual(expected, data)
3560
3561 def testFitExtblobMissingOk(self):
3562 """Test a FIT with a missing external blob that is allowed"""
3563 with test_util.capture_sys_output() as (stdout, stderr):
3564 self._DoTestFile('168_fit_missing_blob.dts',
3565 allow_missing=True)
3566 err = stderr.getvalue()
Simon Glassb2381432020-09-06 10:39:09 -06003567 self.assertRegex(err, "Image 'main-section'.*missing.*: atf-bl31")
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03003568
Simon Glass3decfa32020-09-01 05:13:54 -06003569 def testBlobNamedByArgMissing(self):
3570 """Test handling of a missing entry arg"""
3571 with self.assertRaises(ValueError) as e:
3572 self._DoReadFile('068_blob_named_by_arg.dts')
3573 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
3574 str(e.exception))
3575
Simon Glassdc2f81a2020-09-01 05:13:58 -06003576 def testPackBl31(self):
3577 """Test that an image with an ATF BL31 binary can be created"""
3578 data = self._DoReadFile('169_atf_bl31.dts')
3579 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
3580
Simon Glass6cf99532020-09-01 05:13:59 -06003581 def testFitFdt(self):
3582 """Test an image with an FIT with multiple FDT images"""
3583 def _CheckFdt(seq, expected_data):
3584 """Check the FDT nodes
3585
3586 Args:
3587 seq: Sequence number to check (0 or 1)
3588 expected_data: Expected contents of 'data' property
3589 """
3590 name = 'fdt-%d' % seq
3591 fnode = dtb.GetNode('/images/%s' % name)
3592 self.assertIsNotNone(fnode)
3593 self.assertEqual({'description','type', 'compression', 'data'},
3594 set(fnode.props.keys()))
3595 self.assertEqual(expected_data, fnode.props['data'].bytes)
3596 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
3597 fnode.props['description'].value)
3598
3599 def _CheckConfig(seq, expected_data):
3600 """Check the configuration nodes
3601
3602 Args:
3603 seq: Sequence number to check (0 or 1)
3604 expected_data: Expected contents of 'data' property
3605 """
3606 cnode = dtb.GetNode('/configurations')
3607 self.assertIn('default', cnode.props)
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003608 self.assertEqual('config-2', cnode.props['default'].value)
Simon Glass6cf99532020-09-01 05:13:59 -06003609
3610 name = 'config-%d' % seq
3611 fnode = dtb.GetNode('/configurations/%s' % name)
3612 self.assertIsNotNone(fnode)
3613 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
3614 set(fnode.props.keys()))
3615 self.assertEqual('conf-test-fdt%d.dtb' % seq,
3616 fnode.props['description'].value)
3617 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
3618
3619 entry_args = {
3620 'of-list': 'test-fdt1 test-fdt2',
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003621 'default-dt': 'test-fdt2',
Simon Glass6cf99532020-09-01 05:13:59 -06003622 }
3623 data = self._DoReadFileDtb(
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003624 '172_fit_fdt.dts',
Simon Glass6cf99532020-09-01 05:13:59 -06003625 entry_args=entry_args,
3626 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3627 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3628 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3629
3630 dtb = fdt.Fdt.FromData(fit_data)
3631 dtb.Scan()
3632 fnode = dtb.GetNode('/images/kernel')
3633 self.assertIn('data', fnode.props)
3634
3635 # Check all the properties in fdt-1 and fdt-2
3636 _CheckFdt(1, TEST_FDT1_DATA)
3637 _CheckFdt(2, TEST_FDT2_DATA)
3638
3639 # Check configurations
3640 _CheckConfig(1, TEST_FDT1_DATA)
3641 _CheckConfig(2, TEST_FDT2_DATA)
3642
3643 def testFitFdtMissingList(self):
3644 """Test handling of a missing 'of-list' entry arg"""
3645 with self.assertRaises(ValueError) as e:
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003646 self._DoReadFile('172_fit_fdt.dts')
Simon Glass6cf99532020-09-01 05:13:59 -06003647 self.assertIn("Generator node requires 'of-list' entry argument",
3648 str(e.exception))
3649
3650 def testFitFdtEmptyList(self):
3651 """Test handling of an empty 'of-list' entry arg"""
3652 entry_args = {
3653 'of-list': '',
3654 }
3655 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
3656
3657 def testFitFdtMissingProp(self):
3658 """Test handling of a missing 'fit,fdt-list' property"""
3659 with self.assertRaises(ValueError) as e:
3660 self._DoReadFile('171_fit_fdt_missing_prop.dts')
3661 self.assertIn("Generator node requires 'fit,fdt-list' property",
3662 str(e.exception))
Simon Glassdc2f81a2020-09-01 05:13:58 -06003663
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003664 def testFitFdtEmptyList(self):
3665 """Test handling of an empty 'of-list' entry arg"""
3666 entry_args = {
3667 'of-list': '',
3668 }
3669 data = self._DoReadFileDtb('172_fit_fdt.dts', entry_args=entry_args)[0]
3670
3671 def testFitFdtMissing(self):
3672 """Test handling of a missing 'default-dt' entry arg"""
3673 entry_args = {
3674 'of-list': 'test-fdt1 test-fdt2',
3675 }
3676 with self.assertRaises(ValueError) as e:
3677 self._DoReadFileDtb(
3678 '172_fit_fdt.dts',
3679 entry_args=entry_args,
3680 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3681 self.assertIn("Generated 'default' node requires default-dt entry argument",
3682 str(e.exception))
3683
3684 def testFitFdtNotInList(self):
3685 """Test handling of a default-dt that is not in the of-list"""
3686 entry_args = {
3687 'of-list': 'test-fdt1 test-fdt2',
3688 'default-dt': 'test-fdt3',
3689 }
3690 with self.assertRaises(ValueError) as e:
3691 self._DoReadFileDtb(
3692 '172_fit_fdt.dts',
3693 entry_args=entry_args,
3694 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3695 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
3696 str(e.exception))
3697
Simon Glassb2381432020-09-06 10:39:09 -06003698 def testFitExtblobMissingHelp(self):
3699 """Test display of help messages when an external blob is missing"""
3700 control.missing_blob_help = control._ReadMissingBlobHelp()
3701 control.missing_blob_help['wibble'] = 'Wibble test'
3702 control.missing_blob_help['another'] = 'Another test'
3703 with test_util.capture_sys_output() as (stdout, stderr):
3704 self._DoTestFile('168_fit_missing_blob.dts',
3705 allow_missing=True)
3706 err = stderr.getvalue()
3707
3708 # We can get the tag from the name, the type or the missing-msg
3709 # property. Check all three.
3710 self.assertIn('You may need to build ARM Trusted', err)
3711 self.assertIn('Wibble test', err)
3712 self.assertIn('Another test', err)
3713
Simon Glass204aa782020-09-06 10:35:32 -06003714 def testMissingBlob(self):
3715 """Test handling of a blob containing a missing file"""
3716 with self.assertRaises(ValueError) as e:
3717 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
3718 self.assertIn("Filename 'missing' not found in input path",
3719 str(e.exception))
3720
Simon Glassfb91d562020-09-06 10:35:33 -06003721 def testEnvironment(self):
3722 """Test adding a U-Boot environment"""
3723 data = self._DoReadFile('174_env.dts')
3724 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3725 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3726 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3727 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
3728 env)
3729
3730 def testEnvironmentNoSize(self):
3731 """Test that a missing 'size' property is detected"""
3732 with self.assertRaises(ValueError) as e:
3733 data = self._DoTestFile('175_env_no_size.dts')
3734 self.assertIn("'u-boot-env' entry must have a size property",
3735 str(e.exception))
3736
3737 def testEnvironmentTooSmall(self):
3738 """Test handling of an environment that does not fit"""
3739 with self.assertRaises(ValueError) as e:
3740 data = self._DoTestFile('176_env_too_small.dts')
3741
3742 # checksum, start byte, environment with \0 terminator, final \0
3743 need = 4 + 1 + len(ENV_DATA) + 1 + 1
3744 short = need - 0x8
3745 self.assertIn("too small to hold data (need %#x more bytes)" % short,
3746 str(e.exception))
3747
3748
Simon Glass9fc60b42017-11-12 21:52:22 -07003749if __name__ == "__main__":
3750 unittest.main()