blob: d3a6cbf71df5fcb19cdbe0f7f41c193656275895 [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 Glass8f5ef892020-10-26 17:40:25 -060073COMPRESS_DATA_BIG = COMPRESS_DATA * 2
Simon Glassc6c10e72019-05-17 22:00:46 -060074REFCODE_DATA = b'refcode'
Simon Glassea0fff92019-08-24 07:23:07 -060075FSP_M_DATA = b'fsp_m'
Simon Glassbc6a88f2019-10-20 21:31:35 -060076FSP_S_DATA = b'fsp_s'
Simon Glass998d1482019-10-20 21:31:36 -060077FSP_T_DATA = b'fsp_t'
Simon Glassdc2f81a2020-09-01 05:13:58 -060078ATF_BL31_DATA = b'bl31'
Bin Meng4c4d6072021-05-10 20:23:33 +080079OPENSBI_DATA = b'opensbi'
Samuel Holland18bd4552020-10-21 21:12:15 -050080SCP_DATA = b'scp'
Simon Glass6cf99532020-09-01 05:13:59 -060081TEST_FDT1_DATA = b'fdt1'
82TEST_FDT2_DATA = b'test-fdt2'
Simon Glassfb91d562020-09-06 10:35:33 -060083ENV_DATA = b'var1=1\nvar2="2"'
Simon Glass6cf99532020-09-01 05:13:59 -060084
85# Subdirectory of the input dir to use to put test FDTs
86TEST_FDT_SUBDIR = 'fdts'
Simon Glassec127af2018-07-17 13:25:39 -060087
Simon Glass6ccbfcd2019-07-20 12:23:47 -060088# The expected size for the device tree in some tests
Simon Glassf667e452019-07-08 14:25:50 -060089EXTRACT_DTB_SIZE = 0x3c9
90
Simon Glass6ccbfcd2019-07-20 12:23:47 -060091# Properties expected to be in the device tree when update_dtb is used
92BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
93
Simon Glass12bb1a92019-07-20 12:23:51 -060094# Extra properties expected to be in the device tree when allow-repack is used
95REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
96
Simon Glass4f443042016-11-25 20:15:52 -070097
98class TestFunctional(unittest.TestCase):
99 """Functional tests for binman
100
101 Most of these use a sample .dts file to build an image and then check
102 that it looks correct. The sample files are in the test/ subdirectory
103 and are numbered.
104
105 For each entry type a very small test file is created using fixed
106 string contents. This makes it easy to test that things look right, and
107 debug problems.
108
109 In some cases a 'real' file must be used - these are also supplied in
110 the test/ diurectory.
111 """
112 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600113 def setUpClass(cls):
Simon Glass4d5994f2017-11-12 21:52:20 -0700114 global entry
Simon Glass16287932020-04-17 18:09:03 -0600115 from binman import entry
Simon Glass4d5994f2017-11-12 21:52:20 -0700116
Simon Glass4f443042016-11-25 20:15:52 -0700117 # Handle the case where argv[0] is 'python'
Simon Glassb986b3b2019-08-24 07:22:43 -0600118 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
119 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
Simon Glass4f443042016-11-25 20:15:52 -0700120
121 # Create a temporary directory for input files
Simon Glassb986b3b2019-08-24 07:22:43 -0600122 cls._indir = tempfile.mkdtemp(prefix='binmant.')
Simon Glass4f443042016-11-25 20:15:52 -0700123
124 # Create some test files
125 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
126 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
127 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glassb8ef5b62018-07-17 13:25:48 -0600128 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700129 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -0700130 TestFunctional._MakeInputFile('me.bin', ME_DATA)
131 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glassb986b3b2019-08-24 07:22:43 -0600132 cls._ResetDtbs()
Simon Glass2250ee62019-08-24 07:22:48 -0600133
Jagdish Gediya9d368f32018-09-03 21:35:08 +0530134 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glass2250ee62019-08-24 07:22:48 -0600135
Simon Glass5e239182019-08-24 07:22:49 -0600136 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
137 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
Simon Glass87722132017-11-12 21:52:26 -0700138 X86_START16_SPL_DATA)
Simon Glass5e239182019-08-24 07:22:49 -0600139 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
Simon Glass35b384c2018-09-14 04:57:10 -0600140 X86_START16_TPL_DATA)
Simon Glass2250ee62019-08-24 07:22:48 -0600141
142 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
143 X86_RESET16_DATA)
144 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
145 X86_RESET16_SPL_DATA)
146 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
147 X86_RESET16_TPL_DATA)
148
Simon Glass4f443042016-11-25 20:15:52 -0700149 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass6b187df2017-11-12 21:52:27 -0700150 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
151 U_BOOT_SPL_NODTB_DATA)
Simon Glassf0253632018-09-14 04:57:32 -0600152 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
153 U_BOOT_TPL_NODTB_DATA)
Simon Glassda229092016-11-25 20:15:56 -0700154 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
155 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Meng59ea8c22017-08-15 22:41:54 -0700156 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassca4f4ff2017-11-12 21:52:28 -0700157 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassec127af2018-07-17 13:25:39 -0600158 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glass0ef87aa2018-07-17 13:25:44 -0600159 TestFunctional._MakeInputDir('devkeys')
160 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass3ae192c2018-10-01 12:22:31 -0600161 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glassea0fff92019-08-24 07:23:07 -0600162 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
Simon Glassbc6a88f2019-10-20 21:31:35 -0600163 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
Simon Glass998d1482019-10-20 21:31:36 -0600164 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700165
Simon Glass53e22bf2019-08-24 07:22:53 -0600166 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
167 elf_test.BuildElfTestFiles(cls._elf_testdir)
168
Simon Glasse0ff8552016-11-25 20:15:53 -0700169 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glassf514d8f2019-08-24 07:22:54 -0600170 TestFunctional._MakeInputFile('u-boot',
171 tools.ReadFile(cls.ElfTestFile('u_boot_ucode_ptr')))
Simon Glasse0ff8552016-11-25 20:15:53 -0700172
173 # Intel flash descriptor file
Simon Glass0ba4b3d2020-07-09 18:39:41 -0600174 cls._SetupDescriptor()
Simon Glasse0ff8552016-11-25 20:15:53 -0700175
Simon Glassb986b3b2019-08-24 07:22:43 -0600176 shutil.copytree(cls.TestFile('files'),
177 os.path.join(cls._indir, 'files'))
Simon Glass0a98b282018-09-14 04:57:28 -0600178
Simon Glass83d73c22018-09-14 04:57:26 -0600179 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
Simon Glass8f5ef892020-10-26 17:40:25 -0600180 TestFunctional._MakeInputFile('compress_big', COMPRESS_DATA_BIG)
Simon Glassdc2f81a2020-09-01 05:13:58 -0600181 TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
Bin Meng4c4d6072021-05-10 20:23:33 +0800182 TestFunctional._MakeInputFile('fw_dynamic.bin', OPENSBI_DATA)
Samuel Holland18bd4552020-10-21 21:12:15 -0500183 TestFunctional._MakeInputFile('scp.bin', SCP_DATA)
Simon Glass83d73c22018-09-14 04:57:26 -0600184
Simon Glass6cf99532020-09-01 05:13:59 -0600185 # Add a few .dtb files for testing
186 TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR,
187 TEST_FDT1_DATA)
188 TestFunctional._MakeInputFile('%s/test-fdt2.dtb' % TEST_FDT_SUBDIR,
189 TEST_FDT2_DATA)
190
Simon Glassfb91d562020-09-06 10:35:33 -0600191 TestFunctional._MakeInputFile('env.txt', ENV_DATA)
192
Simon Glassac62fba2019-07-08 13:18:53 -0600193 # Travis-CI may have an old lz4
Simon Glassb986b3b2019-08-24 07:22:43 -0600194 cls.have_lz4 = True
Simon Glassac62fba2019-07-08 13:18:53 -0600195 try:
196 tools.Run('lz4', '--no-frame-crc', '-c',
Simon Glass3b3e3c02019-10-31 07:42:50 -0600197 os.path.join(cls._indir, 'u-boot.bin'), binary=True)
Simon Glassac62fba2019-07-08 13:18:53 -0600198 except:
Simon Glassb986b3b2019-08-24 07:22:43 -0600199 cls.have_lz4 = False
Simon Glassac62fba2019-07-08 13:18:53 -0600200
Simon Glass4f443042016-11-25 20:15:52 -0700201 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600202 def tearDownClass(cls):
Simon Glass4f443042016-11-25 20:15:52 -0700203 """Remove the temporary input directory and its contents"""
Simon Glassb986b3b2019-08-24 07:22:43 -0600204 if cls.preserve_indir:
205 print('Preserving input dir: %s' % cls._indir)
Simon Glassd5164a72019-07-08 13:18:49 -0600206 else:
Simon Glassb986b3b2019-08-24 07:22:43 -0600207 if cls._indir:
208 shutil.rmtree(cls._indir)
209 cls._indir = None
Simon Glass4f443042016-11-25 20:15:52 -0700210
Simon Glassd5164a72019-07-08 13:18:49 -0600211 @classmethod
Simon Glass8acce602019-07-08 13:18:50 -0600212 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
Simon Glass53cd5d92019-07-08 14:25:29 -0600213 toolpath=None, verbosity=None):
Simon Glassd5164a72019-07-08 13:18:49 -0600214 """Accept arguments controlling test execution
215
216 Args:
217 preserve_indir: Preserve the shared input directory used by all
218 tests in this class.
219 preserve_outdir: Preserve the output directories used by tests. Each
220 test has its own, so this is normally only useful when running a
221 single test.
Simon Glass8acce602019-07-08 13:18:50 -0600222 toolpath: ist of paths to use for tools
Simon Glassd5164a72019-07-08 13:18:49 -0600223 """
224 cls.preserve_indir = preserve_indir
225 cls.preserve_outdirs = preserve_outdirs
Simon Glass8acce602019-07-08 13:18:50 -0600226 cls.toolpath = toolpath
Simon Glass53cd5d92019-07-08 14:25:29 -0600227 cls.verbosity = verbosity
Simon Glassd5164a72019-07-08 13:18:49 -0600228
Simon Glassac62fba2019-07-08 13:18:53 -0600229 def _CheckLz4(self):
230 if not self.have_lz4:
231 self.skipTest('lz4 --no-frame-crc not available')
232
Simon Glassbf574f12019-07-20 12:24:09 -0600233 def _CleanupOutputDir(self):
234 """Remove the temporary output directory"""
235 if self.preserve_outdirs:
236 print('Preserving output dir: %s' % tools.outdir)
237 else:
238 tools._FinaliseForTest()
239
Simon Glass4f443042016-11-25 20:15:52 -0700240 def setUp(self):
241 # Enable this to turn on debugging output
242 # tout.Init(tout.DEBUG)
243 command.test_result = None
244
245 def tearDown(self):
246 """Remove the temporary output directory"""
Simon Glassbf574f12019-07-20 12:24:09 -0600247 self._CleanupOutputDir()
Simon Glass4f443042016-11-25 20:15:52 -0700248
Simon Glassf86a7362019-07-20 12:24:10 -0600249 def _SetupImageInTmpdir(self):
250 """Set up the output image in a new temporary directory
251
252 This is used when an image has been generated in the output directory,
253 but we want to run binman again. This will create a new output
254 directory and fail to delete the original one.
255
256 This creates a new temporary directory, copies the image to it (with a
257 new name) and removes the old output directory.
258
259 Returns:
260 Tuple:
261 Temporary directory to use
262 New image filename
263 """
264 image_fname = tools.GetOutputFilename('image.bin')
265 tmpdir = tempfile.mkdtemp(prefix='binman.')
266 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
267 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
268 self._CleanupOutputDir()
269 return tmpdir, updated_fname
270
Simon Glassb8ef5b62018-07-17 13:25:48 -0600271 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600272 def _ResetDtbs(cls):
Simon Glassb8ef5b62018-07-17 13:25:48 -0600273 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
274 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
275 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
276
Simon Glass4f443042016-11-25 20:15:52 -0700277 def _RunBinman(self, *args, **kwargs):
278 """Run binman using the command line
279
280 Args:
281 Arguments to pass, as a list of strings
282 kwargs: Arguments to pass to Command.RunPipe()
283 """
284 result = command.RunPipe([[self._binman_pathname] + list(args)],
285 capture=True, capture_stderr=True, raise_on_error=False)
286 if result.return_code and kwargs.get('raise_on_error', True):
287 raise Exception("Error running '%s': %s" % (' '.join(args),
288 result.stdout + result.stderr))
289 return result
290
Simon Glass53cd5d92019-07-08 14:25:29 -0600291 def _DoBinman(self, *argv):
Simon Glass4f443042016-11-25 20:15:52 -0700292 """Run binman using directly (in the same process)
293
294 Args:
295 Arguments to pass, as a list of strings
296 Returns:
297 Return value (0 for success)
298 """
Simon Glass53cd5d92019-07-08 14:25:29 -0600299 argv = list(argv)
300 args = cmdline.ParseArgs(argv)
301 args.pager = 'binman-invalid-pager'
302 args.build_dir = self._indir
Simon Glass4f443042016-11-25 20:15:52 -0700303
304 # For testing, you can force an increase in verbosity here
Simon Glass53cd5d92019-07-08 14:25:29 -0600305 # args.verbosity = tout.DEBUG
306 return control.Binman(args)
Simon Glass4f443042016-11-25 20:15:52 -0700307
Simon Glass53af22a2018-07-17 13:25:32 -0600308 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glasseb833d82019-04-25 21:58:34 -0600309 entry_args=None, images=None, use_real_dtb=False,
Simon Glass63aeaeb2021-03-18 20:25:05 +1300310 use_expanded=False, verbosity=None, allow_missing=False,
Simon Glassc69d19c2021-07-06 10:36:37 -0600311 extra_indirs=None, threads=None,
Simon Glass0427bed2021-11-03 21:09:18 -0600312 test_section_timeout=False, update_fdt_in_elf=None):
Simon Glass4f443042016-11-25 20:15:52 -0700313 """Run binman with a given test file
314
315 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600316 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600317 debug: True to enable debugging output
Simon Glass3b0c3822018-06-01 09:38:20 -0600318 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600319 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600320 tree before packing it into the image
Simon Glass0bfa7b02018-09-14 04:57:12 -0600321 entry_args: Dict of entry args to supply to binman
322 key: arg name
323 value: value of that arg
324 images: List of image names to build
Simon Glasse9d336d2020-09-01 05:13:55 -0600325 use_real_dtb: True to use the test file as the contents of
326 the u-boot-dtb entry. Normally this is not needed and the
327 test contents (the U_BOOT_DTB_DATA string) can be used.
328 But in some test we need the real contents.
Simon Glass63aeaeb2021-03-18 20:25:05 +1300329 use_expanded: True to use expanded entries where available, e.g.
330 'u-boot-expanded' instead of 'u-boot'
Simon Glasse9d336d2020-09-01 05:13:55 -0600331 verbosity: Verbosity level to use (0-3, None=don't set it)
332 allow_missing: Set the '--allow-missing' flag so that missing
333 external binaries just produce a warning instead of an error
Simon Glass6cf99532020-09-01 05:13:59 -0600334 extra_indirs: Extra input directories to add using -I
Simon Glassc69d19c2021-07-06 10:36:37 -0600335 threads: Number of threads to use (None for default, 0 for
336 single-threaded)
Simon Glass7115f002021-11-03 21:09:17 -0600337 test_section_timeout: True to force the first time to timeout, as
338 used in testThreadTimeout()
Simon Glass0427bed2021-11-03 21:09:18 -0600339 update_fdt_in_elf: Value to pass with --update-fdt-in-elf=xxx
Simon Glass7115f002021-11-03 21:09:17 -0600340
341 Returns:
342 int return code, 0 on success
Simon Glass4f443042016-11-25 20:15:52 -0700343 """
Simon Glass53cd5d92019-07-08 14:25:29 -0600344 args = []
Simon Glass7fe91732017-11-13 18:55:00 -0700345 if debug:
346 args.append('-D')
Simon Glass53cd5d92019-07-08 14:25:29 -0600347 if verbosity is not None:
348 args.append('-v%d' % verbosity)
349 elif self.verbosity:
350 args.append('-v%d' % self.verbosity)
351 if self.toolpath:
352 for path in self.toolpath:
353 args += ['--toolpath', path]
Simon Glassc69d19c2021-07-06 10:36:37 -0600354 if threads is not None:
355 args.append('-T%d' % threads)
356 if test_section_timeout:
357 args.append('--test-section-timeout')
Simon Glass53cd5d92019-07-08 14:25:29 -0600358 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass3b0c3822018-06-01 09:38:20 -0600359 if map:
360 args.append('-m')
Simon Glass16b8d6b2018-07-06 10:27:42 -0600361 if update_dtb:
Simon Glass2569e102019-07-08 13:18:47 -0600362 args.append('-u')
Simon Glass93d17412018-09-14 04:57:23 -0600363 if not use_real_dtb:
364 args.append('--fake-dtb')
Simon Glass63aeaeb2021-03-18 20:25:05 +1300365 if not use_expanded:
366 args.append('--no-expanded')
Simon Glass53af22a2018-07-17 13:25:32 -0600367 if entry_args:
Simon Glass50979152019-05-14 15:53:41 -0600368 for arg, value in entry_args.items():
Simon Glass53af22a2018-07-17 13:25:32 -0600369 args.append('-a%s=%s' % (arg, value))
Simon Glass4f9f1052020-07-09 18:39:38 -0600370 if allow_missing:
371 args.append('-M')
Simon Glass0427bed2021-11-03 21:09:18 -0600372 if update_fdt_in_elf:
373 args += ['--update-fdt-in-elf', update_fdt_in_elf]
Simon Glass0bfa7b02018-09-14 04:57:12 -0600374 if images:
375 for image in images:
376 args += ['-i', image]
Simon Glass6cf99532020-09-01 05:13:59 -0600377 if extra_indirs:
378 for indir in extra_indirs:
379 args += ['-I', indir]
Simon Glass7fe91732017-11-13 18:55:00 -0700380 return self._DoBinman(*args)
Simon Glass4f443042016-11-25 20:15:52 -0700381
382 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glasse0ff8552016-11-25 20:15:53 -0700383 """Set up a new test device-tree file
384
385 The given file is compiled and set up as the device tree to be used
386 for ths test.
387
388 Args:
389 fname: Filename of .dts file to read
Simon Glass7ae5f312018-06-01 09:38:19 -0600390 outfile: Output filename for compiled device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700391
392 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600393 Contents of device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700394 """
Simon Glassa004f292019-07-20 12:23:49 -0600395 tmpdir = tempfile.mkdtemp(prefix='binmant.')
396 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
Simon Glass1d0ebf72019-05-14 15:53:42 -0600397 with open(dtb, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700398 data = fd.read()
399 TestFunctional._MakeInputFile(outfile, data)
Simon Glassa004f292019-07-20 12:23:49 -0600400 shutil.rmtree(tmpdir)
Simon Glasse0e62752018-10-01 21:12:41 -0600401 return data
Simon Glass4f443042016-11-25 20:15:52 -0700402
Simon Glass6ed45ba2018-09-14 04:57:24 -0600403 def _GetDtbContentsForSplTpl(self, dtb_data, name):
404 """Create a version of the main DTB for SPL or SPL
405
406 For testing we don't actually have different versions of the DTB. With
407 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
408 we don't normally have any unwanted nodes.
409
410 We still want the DTBs for SPL and TPL to be different though, since
411 otherwise it is confusing to know which one we are looking at. So add
412 an 'spl' or 'tpl' property to the top-level node.
Simon Glasse9d336d2020-09-01 05:13:55 -0600413
414 Args:
415 dtb_data: dtb data to modify (this should be a value devicetree)
416 name: Name of a new property to add
417
418 Returns:
419 New dtb data with the property added
Simon Glass6ed45ba2018-09-14 04:57:24 -0600420 """
421 dtb = fdt.Fdt.FromData(dtb_data)
422 dtb.Scan()
423 dtb.GetNode('/binman').AddZeroProp(name)
424 dtb.Sync(auto_resize=True)
425 dtb.Pack()
426 return dtb.GetContents()
427
Simon Glass63aeaeb2021-03-18 20:25:05 +1300428 def _DoReadFileDtb(self, fname, use_real_dtb=False, use_expanded=False,
429 map=False, update_dtb=False, entry_args=None,
Simon Glassc69d19c2021-07-06 10:36:37 -0600430 reset_dtbs=True, extra_indirs=None, threads=None):
Simon Glass4f443042016-11-25 20:15:52 -0700431 """Run binman and return the resulting image
432
433 This runs binman with a given test file and then reads the resulting
434 output file. It is a shortcut function since most tests need to do
435 these steps.
436
437 Raises an assertion failure if binman returns a non-zero exit code.
438
439 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600440 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass4f443042016-11-25 20:15:52 -0700441 use_real_dtb: True to use the test file as the contents of
442 the u-boot-dtb entry. Normally this is not needed and the
443 test contents (the U_BOOT_DTB_DATA string) can be used.
444 But in some test we need the real contents.
Simon Glass63aeaeb2021-03-18 20:25:05 +1300445 use_expanded: True to use expanded entries where available, e.g.
446 'u-boot-expanded' instead of 'u-boot'
Simon Glass3b0c3822018-06-01 09:38:20 -0600447 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600448 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600449 tree before packing it into the image
Simon Glasse9d336d2020-09-01 05:13:55 -0600450 entry_args: Dict of entry args to supply to binman
451 key: arg name
452 value: value of that arg
453 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
454 function. If reset_dtbs is True, then the original test dtb
455 is written back before this function finishes
Simon Glass6cf99532020-09-01 05:13:59 -0600456 extra_indirs: Extra input directories to add using -I
Simon Glassc69d19c2021-07-06 10:36:37 -0600457 threads: Number of threads to use (None for default, 0 for
458 single-threaded)
Simon Glasse0ff8552016-11-25 20:15:53 -0700459
460 Returns:
461 Tuple:
462 Resulting image contents
463 Device tree contents
Simon Glass3b0c3822018-06-01 09:38:20 -0600464 Map data showing contents of image (or None if none)
Simon Glassea6922e2018-07-17 13:25:27 -0600465 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass4f443042016-11-25 20:15:52 -0700466 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700467 dtb_data = None
Simon Glass4f443042016-11-25 20:15:52 -0700468 # Use the compiled test file as the u-boot-dtb input
469 if use_real_dtb:
Simon Glasse0ff8552016-11-25 20:15:53 -0700470 dtb_data = self._SetupDtb(fname)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600471
472 # For testing purposes, make a copy of the DT for SPL and TPL. Add
473 # a node indicating which it is, so aid verification.
474 for name in ['spl', 'tpl']:
475 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
476 outfile = os.path.join(self._indir, dtb_fname)
477 TestFunctional._MakeInputFile(dtb_fname,
478 self._GetDtbContentsForSplTpl(dtb_data, name))
Simon Glass4f443042016-11-25 20:15:52 -0700479
480 try:
Simon Glass53af22a2018-07-17 13:25:32 -0600481 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glass6cf99532020-09-01 05:13:59 -0600482 entry_args=entry_args, use_real_dtb=use_real_dtb,
Simon Glassc69d19c2021-07-06 10:36:37 -0600483 use_expanded=use_expanded, extra_indirs=extra_indirs,
484 threads=threads)
Simon Glass4f443042016-11-25 20:15:52 -0700485 self.assertEqual(0, retcode)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600486 out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
Simon Glass4f443042016-11-25 20:15:52 -0700487
488 # Find the (only) image, read it and return its contents
489 image = control.images['image']
Simon Glass16b8d6b2018-07-06 10:27:42 -0600490 image_fname = tools.GetOutputFilename('image.bin')
491 self.assertTrue(os.path.exists(image_fname))
Simon Glass3b0c3822018-06-01 09:38:20 -0600492 if map:
493 map_fname = tools.GetOutputFilename('image.map')
494 with open(map_fname) as fd:
495 map_data = fd.read()
496 else:
497 map_data = None
Simon Glass1d0ebf72019-05-14 15:53:42 -0600498 with open(image_fname, 'rb') as fd:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600499 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass4f443042016-11-25 20:15:52 -0700500 finally:
501 # Put the test file back
Simon Glass6ed45ba2018-09-14 04:57:24 -0600502 if reset_dtbs and use_real_dtb:
Simon Glassb8ef5b62018-07-17 13:25:48 -0600503 self._ResetDtbs()
Simon Glass4f443042016-11-25 20:15:52 -0700504
Simon Glass3c081312019-07-08 14:25:26 -0600505 def _DoReadFileRealDtb(self, fname):
506 """Run binman with a real .dtb file and return the resulting data
507
508 Args:
509 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
510
511 Returns:
512 Resulting image contents
513 """
514 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
515
Simon Glasse0ff8552016-11-25 20:15:53 -0700516 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass7ae5f312018-06-01 09:38:19 -0600517 """Helper function which discards the device-tree binary
518
519 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600520 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600521 use_real_dtb: True to use the test file as the contents of
522 the u-boot-dtb entry. Normally this is not needed and the
523 test contents (the U_BOOT_DTB_DATA string) can be used.
524 But in some test we need the real contents.
Simon Glassea6922e2018-07-17 13:25:27 -0600525
526 Returns:
527 Resulting image contents
Simon Glass7ae5f312018-06-01 09:38:19 -0600528 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700529 return self._DoReadFileDtb(fname, use_real_dtb)[0]
530
Simon Glass4f443042016-11-25 20:15:52 -0700531 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600532 def _MakeInputFile(cls, fname, contents):
Simon Glass4f443042016-11-25 20:15:52 -0700533 """Create a new test input file, creating directories as needed
534
535 Args:
Simon Glass3ab95982018-08-01 15:22:37 -0600536 fname: Filename to create
Simon Glass4f443042016-11-25 20:15:52 -0700537 contents: File contents to write in to the file
538 Returns:
539 Full pathname of file created
540 """
Simon Glassb986b3b2019-08-24 07:22:43 -0600541 pathname = os.path.join(cls._indir, fname)
Simon Glass4f443042016-11-25 20:15:52 -0700542 dirname = os.path.dirname(pathname)
543 if dirname and not os.path.exists(dirname):
544 os.makedirs(dirname)
545 with open(pathname, 'wb') as fd:
546 fd.write(contents)
547 return pathname
548
549 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600550 def _MakeInputDir(cls, dirname):
Simon Glass0ef87aa2018-07-17 13:25:44 -0600551 """Create a new test input directory, creating directories as needed
552
553 Args:
554 dirname: Directory name to create
555
556 Returns:
557 Full pathname of directory created
558 """
Simon Glassb986b3b2019-08-24 07:22:43 -0600559 pathname = os.path.join(cls._indir, dirname)
Simon Glass0ef87aa2018-07-17 13:25:44 -0600560 if not os.path.exists(pathname):
561 os.makedirs(pathname)
562 return pathname
563
564 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600565 def _SetupSplElf(cls, src_fname='bss_data'):
Simon Glass11ae93e2018-10-01 21:12:47 -0600566 """Set up an ELF file with a '_dt_ucode_base_size' symbol
567
568 Args:
569 Filename of ELF file to use as SPL
570 """
Simon Glassc9a0b272019-08-24 07:22:59 -0600571 TestFunctional._MakeInputFile('spl/u-boot-spl',
572 tools.ReadFile(cls.ElfTestFile(src_fname)))
Simon Glass11ae93e2018-10-01 21:12:47 -0600573
574 @classmethod
Simon Glass2090f1e2019-08-24 07:23:00 -0600575 def _SetupTplElf(cls, src_fname='bss_data'):
576 """Set up an ELF file with a '_dt_ucode_base_size' symbol
577
578 Args:
579 Filename of ELF file to use as TPL
580 """
581 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
582 tools.ReadFile(cls.ElfTestFile(src_fname)))
583
584 @classmethod
Simon Glass0ba4b3d2020-07-09 18:39:41 -0600585 def _SetupDescriptor(cls):
586 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
587 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
588
589 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600590 def TestFile(cls, fname):
591 return os.path.join(cls._binman_dir, 'test', fname)
Simon Glass4f443042016-11-25 20:15:52 -0700592
Simon Glass53e22bf2019-08-24 07:22:53 -0600593 @classmethod
594 def ElfTestFile(cls, fname):
595 return os.path.join(cls._elf_testdir, fname)
596
Simon Glass4f443042016-11-25 20:15:52 -0700597 def AssertInList(self, grep_list, target):
598 """Assert that at least one of a list of things is in a target
599
600 Args:
601 grep_list: List of strings to check
602 target: Target string
603 """
604 for grep in grep_list:
605 if grep in target:
606 return
Simon Glass1fc62de2019-05-17 22:00:50 -0600607 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass4f443042016-11-25 20:15:52 -0700608
609 def CheckNoGaps(self, entries):
610 """Check that all entries fit together without gaps
611
612 Args:
613 entries: List of entries to check
614 """
Simon Glass3ab95982018-08-01 15:22:37 -0600615 offset = 0
Simon Glass4f443042016-11-25 20:15:52 -0700616 for entry in entries.values():
Simon Glass3ab95982018-08-01 15:22:37 -0600617 self.assertEqual(offset, entry.offset)
618 offset += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700619
Simon Glasse0ff8552016-11-25 20:15:53 -0700620 def GetFdtLen(self, dtb):
Simon Glass7ae5f312018-06-01 09:38:19 -0600621 """Get the totalsize field from a device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700622
623 Args:
Simon Glass7ae5f312018-06-01 09:38:19 -0600624 dtb: Device-tree binary contents
Simon Glasse0ff8552016-11-25 20:15:53 -0700625
626 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600627 Total size of device-tree binary, from the header
Simon Glasse0ff8552016-11-25 20:15:53 -0700628 """
629 return struct.unpack('>L', dtb[4:8])[0]
630
Simon Glass086cec92019-07-08 14:25:27 -0600631 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glass16b8d6b2018-07-06 10:27:42 -0600632 def AddNode(node, path):
633 if node.name != '/':
634 path += '/' + node.name
Simon Glass086cec92019-07-08 14:25:27 -0600635 for prop in node.props.values():
636 if prop.name in prop_names:
637 prop_path = path + ':' + prop.name
638 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
639 prop.value)
Simon Glass16b8d6b2018-07-06 10:27:42 -0600640 for subnode in node.subnodes:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600641 AddNode(subnode, path)
642
643 tree = {}
Simon Glass16b8d6b2018-07-06 10:27:42 -0600644 AddNode(dtb.GetRoot(), '')
645 return tree
646
Simon Glass4f443042016-11-25 20:15:52 -0700647 def testRun(self):
648 """Test a basic run with valid args"""
649 result = self._RunBinman('-h')
650
651 def testFullHelp(self):
652 """Test that the full help is displayed with -H"""
653 result = self._RunBinman('-H')
Simon Glass61adb2d2021-03-18 20:25:13 +1300654 help_file = os.path.join(self._binman_dir, 'README.rst')
Tom Rini3759df02018-01-16 15:29:50 -0500655 # Remove possible extraneous strings
656 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
657 gothelp = result.stdout.replace(extra, '')
658 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass4f443042016-11-25 20:15:52 -0700659 self.assertEqual(0, len(result.stderr))
660 self.assertEqual(0, result.return_code)
661
662 def testFullHelpInternal(self):
663 """Test that the full help is displayed with -H"""
664 try:
665 command.test_result = command.CommandResult()
666 result = self._DoBinman('-H')
Simon Glass61adb2d2021-03-18 20:25:13 +1300667 help_file = os.path.join(self._binman_dir, 'README.rst')
Simon Glass4f443042016-11-25 20:15:52 -0700668 finally:
669 command.test_result = None
670
671 def testHelp(self):
672 """Test that the basic help is displayed with -h"""
673 result = self._RunBinman('-h')
674 self.assertTrue(len(result.stdout) > 200)
675 self.assertEqual(0, len(result.stderr))
676 self.assertEqual(0, result.return_code)
677
Simon Glass4f443042016-11-25 20:15:52 -0700678 def testBoard(self):
679 """Test that we can run it with a specific board"""
Simon Glass741f2d62018-10-01 12:22:30 -0600680 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass4f443042016-11-25 20:15:52 -0700681 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glass63aeaeb2021-03-18 20:25:05 +1300682 result = self._DoBinman('build', '-n', '-b', 'sandbox')
Simon Glass4f443042016-11-25 20:15:52 -0700683 self.assertEqual(0, result)
684
685 def testNeedBoard(self):
686 """Test that we get an error when no board ius supplied"""
687 with self.assertRaises(ValueError) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600688 result = self._DoBinman('build')
Simon Glass4f443042016-11-25 20:15:52 -0700689 self.assertIn("Must provide a board to process (use -b <board>)",
690 str(e.exception))
691
692 def testMissingDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600693 """Test that an invalid device-tree file generates an error"""
Simon Glass4f443042016-11-25 20:15:52 -0700694 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600695 self._RunBinman('build', '-d', 'missing_file')
Simon Glass4f443042016-11-25 20:15:52 -0700696 # We get one error from libfdt, and a different one from fdtget.
697 self.AssertInList(["Couldn't open blob from 'missing_file'",
698 'No such file or directory'], str(e.exception))
699
700 def testBrokenDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600701 """Test that an invalid device-tree source file generates an error
Simon Glass4f443042016-11-25 20:15:52 -0700702
703 Since this is a source file it should be compiled and the error
704 will come from the device-tree compiler (dtc).
705 """
706 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600707 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700708 self.assertIn("FATAL ERROR: Unable to parse input tree",
709 str(e.exception))
710
711 def testMissingNode(self):
712 """Test that a device tree without a 'binman' node generates an error"""
713 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600714 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700715 self.assertIn("does not have a 'binman' node", str(e.exception))
716
717 def testEmpty(self):
718 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glass53cd5d92019-07-08 14:25:29 -0600719 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700720 self.assertEqual(0, len(result.stderr))
721 self.assertEqual(0, result.return_code)
722
723 def testInvalidEntry(self):
724 """Test that an invalid entry is flagged"""
725 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600726 result = self._RunBinman('build', '-d',
Simon Glass741f2d62018-10-01 12:22:30 -0600727 self.TestFile('004_invalid_entry.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700728 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
729 "'/binman/not-a-valid-type'", str(e.exception))
730
731 def testSimple(self):
732 """Test a simple binman with a single file"""
Simon Glass741f2d62018-10-01 12:22:30 -0600733 data = self._DoReadFile('005_simple.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700734 self.assertEqual(U_BOOT_DATA, data)
735
Simon Glass7fe91732017-11-13 18:55:00 -0700736 def testSimpleDebug(self):
737 """Test a simple binman run with debugging enabled"""
Simon Glasse2705fa2019-07-08 14:25:53 -0600738 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass7fe91732017-11-13 18:55:00 -0700739
Simon Glass4f443042016-11-25 20:15:52 -0700740 def testDual(self):
741 """Test that we can handle creating two images
742
743 This also tests image padding.
744 """
Simon Glass741f2d62018-10-01 12:22:30 -0600745 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700746 self.assertEqual(0, retcode)
747
748 image = control.images['image1']
Simon Glass8beb11e2019-07-08 14:25:47 -0600749 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700750 fname = tools.GetOutputFilename('image1.bin')
751 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600752 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700753 data = fd.read()
754 self.assertEqual(U_BOOT_DATA, data)
755
756 image = control.images['image2']
Simon Glass8beb11e2019-07-08 14:25:47 -0600757 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700758 fname = tools.GetOutputFilename('image2.bin')
759 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600760 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700761 data = fd.read()
762 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glasse6d85ff2019-05-14 15:53:47 -0600763 self.assertEqual(tools.GetBytes(0, 3), data[:3])
764 self.assertEqual(tools.GetBytes(0, 5), data[7:])
Simon Glass4f443042016-11-25 20:15:52 -0700765
766 def testBadAlign(self):
767 """Test that an invalid alignment value is detected"""
768 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600769 self._DoTestFile('007_bad_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700770 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
771 "of two", str(e.exception))
772
773 def testPackSimple(self):
774 """Test that packing works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600775 retcode = self._DoTestFile('008_pack.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700776 self.assertEqual(0, retcode)
777 self.assertIn('image', control.images)
778 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600779 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700780 self.assertEqual(5, len(entries))
781
782 # First u-boot
783 self.assertIn('u-boot', entries)
784 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600785 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700786 self.assertEqual(len(U_BOOT_DATA), entry.size)
787
788 # Second u-boot, aligned to 16-byte boundary
789 self.assertIn('u-boot-align', entries)
790 entry = entries['u-boot-align']
Simon Glass3ab95982018-08-01 15:22:37 -0600791 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700792 self.assertEqual(len(U_BOOT_DATA), entry.size)
793
794 # Third u-boot, size 23 bytes
795 self.assertIn('u-boot-size', entries)
796 entry = entries['u-boot-size']
Simon Glass3ab95982018-08-01 15:22:37 -0600797 self.assertEqual(20, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700798 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
799 self.assertEqual(23, entry.size)
800
801 # Fourth u-boot, placed immediate after the above
802 self.assertIn('u-boot-next', entries)
803 entry = entries['u-boot-next']
Simon Glass3ab95982018-08-01 15:22:37 -0600804 self.assertEqual(43, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700805 self.assertEqual(len(U_BOOT_DATA), entry.size)
806
Simon Glass3ab95982018-08-01 15:22:37 -0600807 # Fifth u-boot, placed at a fixed offset
Simon Glass4f443042016-11-25 20:15:52 -0700808 self.assertIn('u-boot-fixed', entries)
809 entry = entries['u-boot-fixed']
Simon Glass3ab95982018-08-01 15:22:37 -0600810 self.assertEqual(61, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700811 self.assertEqual(len(U_BOOT_DATA), entry.size)
812
Simon Glass8beb11e2019-07-08 14:25:47 -0600813 self.assertEqual(65, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700814
815 def testPackExtra(self):
816 """Test that extra packing feature works as expected"""
Simon Glass4eec34c2020-10-26 17:40:10 -0600817 data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
818 update_dtb=True)
Simon Glass4f443042016-11-25 20:15:52 -0700819
Simon Glass4f443042016-11-25 20:15:52 -0700820 self.assertIn('image', control.images)
821 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600822 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700823 self.assertEqual(5, len(entries))
824
825 # First u-boot with padding before and after
826 self.assertIn('u-boot', entries)
827 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600828 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700829 self.assertEqual(3, entry.pad_before)
830 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600831 self.assertEqual(U_BOOT_DATA, entry.data)
832 self.assertEqual(tools.GetBytes(0, 3) + U_BOOT_DATA +
833 tools.GetBytes(0, 5), data[:entry.size])
834 pos = entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700835
836 # Second u-boot has an aligned size, but it has no effect
837 self.assertIn('u-boot-align-size-nop', entries)
838 entry = entries['u-boot-align-size-nop']
Simon Glassef439ed2020-10-26 17:40:08 -0600839 self.assertEqual(pos, entry.offset)
840 self.assertEqual(len(U_BOOT_DATA), entry.size)
841 self.assertEqual(U_BOOT_DATA, entry.data)
842 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
843 pos += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700844
845 # Third u-boot has an aligned size too
846 self.assertIn('u-boot-align-size', entries)
847 entry = entries['u-boot-align-size']
Simon Glassef439ed2020-10-26 17:40:08 -0600848 self.assertEqual(pos, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700849 self.assertEqual(32, entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600850 self.assertEqual(U_BOOT_DATA, entry.data)
851 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 32 - len(U_BOOT_DATA)),
852 data[pos:pos + entry.size])
853 pos += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700854
855 # Fourth u-boot has an aligned end
856 self.assertIn('u-boot-align-end', entries)
857 entry = entries['u-boot-align-end']
Simon Glass3ab95982018-08-01 15:22:37 -0600858 self.assertEqual(48, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700859 self.assertEqual(16, entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600860 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
861 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 16 - len(U_BOOT_DATA)),
862 data[pos:pos + entry.size])
863 pos += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700864
865 # Fifth u-boot immediately afterwards
866 self.assertIn('u-boot-align-both', entries)
867 entry = entries['u-boot-align-both']
Simon Glass3ab95982018-08-01 15:22:37 -0600868 self.assertEqual(64, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700869 self.assertEqual(64, entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600870 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
871 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 64 - len(U_BOOT_DATA)),
872 data[pos:pos + entry.size])
Simon Glass4f443042016-11-25 20:15:52 -0700873
874 self.CheckNoGaps(entries)
Simon Glass8beb11e2019-07-08 14:25:47 -0600875 self.assertEqual(128, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700876
Simon Glass4eec34c2020-10-26 17:40:10 -0600877 dtb = fdt.Fdt(out_dtb_fname)
878 dtb.Scan()
879 props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
880 expected = {
881 'image-pos': 0,
882 'offset': 0,
883 'size': 128,
884
885 'u-boot:image-pos': 0,
886 'u-boot:offset': 0,
887 'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
888
889 'u-boot-align-size-nop:image-pos': 12,
890 'u-boot-align-size-nop:offset': 12,
891 'u-boot-align-size-nop:size': 4,
892
893 'u-boot-align-size:image-pos': 16,
894 'u-boot-align-size:offset': 16,
895 'u-boot-align-size:size': 32,
896
897 'u-boot-align-end:image-pos': 48,
898 'u-boot-align-end:offset': 48,
899 'u-boot-align-end:size': 16,
900
901 'u-boot-align-both:image-pos': 64,
902 'u-boot-align-both:offset': 64,
903 'u-boot-align-both:size': 64,
904 }
905 self.assertEqual(expected, props)
906
Simon Glass4f443042016-11-25 20:15:52 -0700907 def testPackAlignPowerOf2(self):
908 """Test that invalid entry alignment is detected"""
909 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600910 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700911 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
912 "of two", str(e.exception))
913
914 def testPackAlignSizePowerOf2(self):
915 """Test that invalid entry size alignment is detected"""
916 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600917 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700918 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
919 "power of two", str(e.exception))
920
921 def testPackInvalidAlign(self):
Simon Glass3ab95982018-08-01 15:22:37 -0600922 """Test detection of an offset that does not match its alignment"""
Simon Glass4f443042016-11-25 20:15:52 -0700923 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600924 self._DoTestFile('012_pack_inv_align.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600925 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700926 "align 0x4 (4)", str(e.exception))
927
928 def testPackInvalidSizeAlign(self):
929 """Test that invalid entry size alignment is detected"""
930 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600931 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700932 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
933 "align-size 0x4 (4)", str(e.exception))
934
935 def testPackOverlap(self):
936 """Test that overlapping regions are detected"""
937 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600938 self._DoTestFile('014_pack_overlap.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600939 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -0700940 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
941 str(e.exception))
942
943 def testPackEntryOverflow(self):
944 """Test that entries that overflow their size are detected"""
945 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600946 self._DoTestFile('015_pack_overflow.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700947 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
948 "but entry size is 0x3 (3)", str(e.exception))
949
950 def testPackImageOverflow(self):
951 """Test that entries which overflow the image size are detected"""
952 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600953 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600954 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass4f443042016-11-25 20:15:52 -0700955 "size 0x3 (3)", str(e.exception))
956
957 def testPackImageSize(self):
958 """Test that the image size can be set"""
Simon Glass741f2d62018-10-01 12:22:30 -0600959 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700960 self.assertEqual(0, retcode)
961 self.assertIn('image', control.images)
962 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -0600963 self.assertEqual(7, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700964
965 def testPackImageSizeAlign(self):
966 """Test that image size alignemnt works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600967 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700968 self.assertEqual(0, retcode)
969 self.assertIn('image', control.images)
970 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -0600971 self.assertEqual(16, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700972
973 def testPackInvalidImageAlign(self):
974 """Test that invalid image alignment is detected"""
975 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600976 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600977 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700978 "align-size 0x8 (8)", str(e.exception))
979
980 def testPackAlignPowerOf2(self):
981 """Test that invalid image alignment is detected"""
982 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600983 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -0600984 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass4f443042016-11-25 20:15:52 -0700985 "two", str(e.exception))
986
987 def testImagePadByte(self):
988 """Test that the image pad byte can be specified"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600989 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600990 data = self._DoReadFile('021_image_pad.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -0600991 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0xff, 1) +
992 U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -0700993
994 def testImageName(self):
995 """Test that image files can be named"""
Simon Glass741f2d62018-10-01 12:22:30 -0600996 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700997 self.assertEqual(0, retcode)
998 image = control.images['image1']
999 fname = tools.GetOutputFilename('test-name')
1000 self.assertTrue(os.path.exists(fname))
1001
1002 image = control.images['image2']
1003 fname = tools.GetOutputFilename('test-name.xx')
1004 self.assertTrue(os.path.exists(fname))
1005
1006 def testBlobFilename(self):
1007 """Test that generic blobs can be provided by filename"""
Simon Glass741f2d62018-10-01 12:22:30 -06001008 data = self._DoReadFile('023_blob.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001009 self.assertEqual(BLOB_DATA, data)
1010
1011 def testPackSorted(self):
1012 """Test that entries can be sorted"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001013 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001014 data = self._DoReadFile('024_sorted.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001015 self.assertEqual(tools.GetBytes(0, 1) + U_BOOT_SPL_DATA +
1016 tools.GetBytes(0, 2) + U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -07001017
Simon Glass3ab95982018-08-01 15:22:37 -06001018 def testPackZeroOffset(self):
1019 """Test that an entry at offset 0 is not given a new offset"""
Simon Glass4f443042016-11-25 20:15:52 -07001020 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001021 self._DoTestFile('025_pack_zero_size.dts')
Simon Glass3ab95982018-08-01 15:22:37 -06001022 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -07001023 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1024 str(e.exception))
1025
1026 def testPackUbootDtb(self):
1027 """Test that a device tree can be added to U-Boot"""
Simon Glass741f2d62018-10-01 12:22:30 -06001028 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001029 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glasse0ff8552016-11-25 20:15:53 -07001030
1031 def testPackX86RomNoSize(self):
1032 """Test that the end-at-4gb property requires a size property"""
1033 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001034 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -06001035 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glasse0ff8552016-11-25 20:15:53 -07001036 "using end-at-4gb", str(e.exception))
1037
Jagdish Gediya94b57db2018-09-03 21:35:07 +05301038 def test4gbAndSkipAtStartTogether(self):
1039 """Test that the end-at-4gb and skip-at-size property can't be used
1040 together"""
1041 with self.assertRaises(ValueError) as e:
Simon Glassdfdd2b62019-08-24 07:23:02 -06001042 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -06001043 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya94b57db2018-09-03 21:35:07 +05301044 "'skip-at-start'", str(e.exception))
1045
Simon Glasse0ff8552016-11-25 20:15:53 -07001046 def testPackX86RomOutside(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001047 """Test that the end-at-4gb property checks for offset boundaries"""
Simon Glasse0ff8552016-11-25 20:15:53 -07001048 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001049 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glasse6bed4f2020-10-26 17:40:05 -06001050 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
1051 "is outside the section '/binman' starting at "
1052 '0xffffffe0 (4294967264) of size 0x20 (32)',
Simon Glasse0ff8552016-11-25 20:15:53 -07001053 str(e.exception))
1054
1055 def testPackX86Rom(self):
1056 """Test that a basic x86 ROM can be created"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001057 self._SetupSplElf()
Simon Glass9255f3c2019-08-24 07:23:01 -06001058 data = self._DoReadFile('029_x86_rom.dts')
Simon Glasseb0086f2019-08-24 07:23:04 -06001059 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 3) + U_BOOT_SPL_DATA +
Simon Glasse6d85ff2019-05-14 15:53:47 -06001060 tools.GetBytes(0, 2), data)
Simon Glasse0ff8552016-11-25 20:15:53 -07001061
1062 def testPackX86RomMeNoDesc(self):
1063 """Test that an invalid Intel descriptor entry is detected"""
Simon Glass0ba4b3d2020-07-09 18:39:41 -06001064 try:
Simon Glass52b10dd2020-07-25 15:11:19 -06001065 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
Simon Glass0ba4b3d2020-07-09 18:39:41 -06001066 with self.assertRaises(ValueError) as e:
Simon Glass52b10dd2020-07-25 15:11:19 -06001067 self._DoTestFile('163_x86_rom_me_empty.dts')
Simon Glass0ba4b3d2020-07-09 18:39:41 -06001068 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1069 str(e.exception))
1070 finally:
1071 self._SetupDescriptor()
Simon Glasse0ff8552016-11-25 20:15:53 -07001072
1073 def testPackX86RomBadDesc(self):
1074 """Test that the Intel requires a descriptor entry"""
1075 with self.assertRaises(ValueError) as e:
Simon Glass9255f3c2019-08-24 07:23:01 -06001076 self._DoTestFile('030_x86_rom_me_no_desc.dts')
Simon Glass3ab95982018-08-01 15:22:37 -06001077 self.assertIn("Node '/binman/intel-me': No offset set with "
1078 "offset-unset: should another entry provide this correct "
1079 "offset?", str(e.exception))
Simon Glasse0ff8552016-11-25 20:15:53 -07001080
1081 def testPackX86RomMe(self):
1082 """Test that an x86 ROM with an ME region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001083 data = self._DoReadFile('031_x86_rom_me.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06001084 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
1085 if data[:0x1000] != expected_desc:
1086 self.fail('Expected descriptor binary at start of image')
Simon Glasse0ff8552016-11-25 20:15:53 -07001087 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1088
1089 def testPackVga(self):
1090 """Test that an image with a VGA binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001091 data = self._DoReadFile('032_intel_vga.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -07001092 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1093
1094 def testPackStart16(self):
1095 """Test that an image with an x86 start16 region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001096 data = self._DoReadFile('033_x86_start16.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -07001097 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1098
Jagdish Gediya9d368f32018-09-03 21:35:08 +05301099 def testPackPowerpcMpc85xxBootpgResetvec(self):
1100 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1101 created"""
Simon Glassdfdd2b62019-08-24 07:23:02 -06001102 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
Jagdish Gediya9d368f32018-09-03 21:35:08 +05301103 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1104
Simon Glass736bb0a2018-07-06 10:27:17 -06001105 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glassadc57012018-07-06 10:27:16 -06001106 """Handle running a test for insertion of microcode
1107
1108 Args:
1109 dts_fname: Name of test .dts file
1110 nodtb_data: Data that we expect in the first section
Simon Glass736bb0a2018-07-06 10:27:17 -06001111 ucode_second: True if the microsecond entry is second instead of
1112 third
Simon Glassadc57012018-07-06 10:27:16 -06001113
1114 Returns:
1115 Tuple:
1116 Contents of first region (U-Boot or SPL)
Simon Glass3ab95982018-08-01 15:22:37 -06001117 Offset and size components of microcode pointer, as inserted
Simon Glassadc57012018-07-06 10:27:16 -06001118 in the above (two 4-byte words)
1119 """
Simon Glass6b187df2017-11-12 21:52:27 -07001120 data = self._DoReadFile(dts_fname, True)
Simon Glasse0ff8552016-11-25 20:15:53 -07001121
1122 # Now check the device tree has no microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001123 if ucode_second:
1124 ucode_content = data[len(nodtb_data):]
1125 ucode_pos = len(nodtb_data)
1126 dtb_with_ucode = ucode_content[16:]
1127 fdt_len = self.GetFdtLen(dtb_with_ucode)
1128 else:
1129 dtb_with_ucode = data[len(nodtb_data):]
1130 fdt_len = self.GetFdtLen(dtb_with_ucode)
1131 ucode_content = dtb_with_ucode[fdt_len:]
1132 ucode_pos = len(nodtb_data) + fdt_len
Simon Glasse0ff8552016-11-25 20:15:53 -07001133 fname = tools.GetOutputFilename('test.dtb')
1134 with open(fname, 'wb') as fd:
Simon Glassadc57012018-07-06 10:27:16 -06001135 fd.write(dtb_with_ucode)
Simon Glassec3f3782017-05-27 07:38:29 -06001136 dtb = fdt.FdtScan(fname)
1137 ucode = dtb.GetNode('/microcode')
Simon Glasse0ff8552016-11-25 20:15:53 -07001138 self.assertTrue(ucode)
1139 for node in ucode.subnodes:
1140 self.assertFalse(node.props.get('data'))
1141
Simon Glasse0ff8552016-11-25 20:15:53 -07001142 # Check that the microcode appears immediately after the Fdt
1143 # This matches the concatenation of the data properties in
Simon Glass87722132017-11-12 21:52:26 -07001144 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glasse0ff8552016-11-25 20:15:53 -07001145 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1146 0x78235609)
Simon Glassadc57012018-07-06 10:27:16 -06001147 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glasse0ff8552016-11-25 20:15:53 -07001148
1149 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -06001150 # expected offset and size
Simon Glasse0ff8552016-11-25 20:15:53 -07001151 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1152 len(ucode_data))
Simon Glass736bb0a2018-07-06 10:27:17 -06001153 u_boot = data[:len(nodtb_data)]
1154 return u_boot, pos_and_size
Simon Glass6b187df2017-11-12 21:52:27 -07001155
1156 def testPackUbootMicrocode(self):
1157 """Test that x86 microcode can be handled correctly
1158
1159 We expect to see the following in the image, in order:
1160 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1161 place
1162 u-boot.dtb with the microcode removed
1163 the microcode
1164 """
Simon Glass741f2d62018-10-01 12:22:30 -06001165 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass6b187df2017-11-12 21:52:27 -07001166 U_BOOT_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001167 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1168 b' somewhere in here', first)
Simon Glasse0ff8552016-11-25 20:15:53 -07001169
Simon Glass160a7662017-05-27 07:38:26 -06001170 def _RunPackUbootSingleMicrocode(self):
Simon Glasse0ff8552016-11-25 20:15:53 -07001171 """Test that x86 microcode can be handled correctly
1172
1173 We expect to see the following in the image, in order:
1174 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1175 place
1176 u-boot.dtb with the microcode
1177 an empty microcode region
1178 """
1179 # We need the libfdt library to run this test since only that allows
1180 # finding the offset of a property. This is required by
1181 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass741f2d62018-10-01 12:22:30 -06001182 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glasse0ff8552016-11-25 20:15:53 -07001183
1184 second = data[len(U_BOOT_NODTB_DATA):]
1185
1186 fdt_len = self.GetFdtLen(second)
1187 third = second[fdt_len:]
1188 second = second[:fdt_len]
1189
Simon Glass160a7662017-05-27 07:38:26 -06001190 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1191 self.assertIn(ucode_data, second)
1192 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -07001193
Simon Glass160a7662017-05-27 07:38:26 -06001194 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -06001195 # expected offset and size
Simon Glass160a7662017-05-27 07:38:26 -06001196 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1197 len(ucode_data))
1198 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glassc6c10e72019-05-17 22:00:46 -06001199 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1200 b' somewhere in here', first)
Simon Glassc49deb82016-11-25 20:15:54 -07001201
Simon Glass75db0862016-11-25 20:15:55 -07001202 def testPackUbootSingleMicrocode(self):
1203 """Test that x86 microcode can be handled correctly with fdt_normal.
1204 """
Simon Glass160a7662017-05-27 07:38:26 -06001205 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001206
Simon Glassc49deb82016-11-25 20:15:54 -07001207 def testUBootImg(self):
1208 """Test that u-boot.img can be put in a file"""
Simon Glass741f2d62018-10-01 12:22:30 -06001209 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glassc49deb82016-11-25 20:15:54 -07001210 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glass75db0862016-11-25 20:15:55 -07001211
1212 def testNoMicrocode(self):
1213 """Test that a missing microcode region is detected"""
1214 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001215 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001216 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1217 "node found in ", str(e.exception))
1218
1219 def testMicrocodeWithoutNode(self):
1220 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1221 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001222 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001223 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1224 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1225
1226 def testMicrocodeWithoutNode2(self):
1227 """Test that a missing u-boot-ucode node is detected"""
1228 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001229 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001230 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1231 "microcode region u-boot-ucode", str(e.exception))
1232
1233 def testMicrocodeWithoutPtrInElf(self):
1234 """Test that a U-Boot binary without the microcode symbol is detected"""
1235 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glass75db0862016-11-25 20:15:55 -07001236 try:
Simon Glassbccd91d2019-08-24 07:22:55 -06001237 TestFunctional._MakeInputFile('u-boot',
1238 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass75db0862016-11-25 20:15:55 -07001239
1240 with self.assertRaises(ValueError) as e:
Simon Glass160a7662017-05-27 07:38:26 -06001241 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001242 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1243 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1244
1245 finally:
1246 # Put the original file back
Simon Glassf514d8f2019-08-24 07:22:54 -06001247 TestFunctional._MakeInputFile('u-boot',
1248 tools.ReadFile(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glass75db0862016-11-25 20:15:55 -07001249
1250 def testMicrocodeNotInImage(self):
1251 """Test that microcode must be placed within the image"""
1252 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001253 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001254 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1255 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glass25ac0e62018-06-01 09:38:14 -06001256 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glass75db0862016-11-25 20:15:55 -07001257
1258 def testWithoutMicrocode(self):
1259 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glassbccd91d2019-08-24 07:22:55 -06001260 TestFunctional._MakeInputFile('u-boot',
1261 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass741f2d62018-10-01 12:22:30 -06001262 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001263
1264 # Now check the device tree has no microcode
1265 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1266 second = data[len(U_BOOT_NODTB_DATA):]
1267
1268 fdt_len = self.GetFdtLen(second)
1269 self.assertEqual(dtb, second[:fdt_len])
1270
1271 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1272 third = data[used_len:]
Simon Glasse6d85ff2019-05-14 15:53:47 -06001273 self.assertEqual(tools.GetBytes(0, 0x200 - used_len), third)
Simon Glass75db0862016-11-25 20:15:55 -07001274
1275 def testUnknownPosSize(self):
1276 """Test that microcode must be placed within the image"""
1277 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001278 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glass3ab95982018-08-01 15:22:37 -06001279 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glass75db0862016-11-25 20:15:55 -07001280 "entry 'invalid-entry'", str(e.exception))
Simon Glassda229092016-11-25 20:15:56 -07001281
1282 def testPackFsp(self):
1283 """Test that an image with a FSP binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001284 data = self._DoReadFile('042_intel_fsp.dts')
Simon Glassda229092016-11-25 20:15:56 -07001285 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1286
1287 def testPackCmc(self):
Bin Meng59ea8c22017-08-15 22:41:54 -07001288 """Test that an image with a CMC binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001289 data = self._DoReadFile('043_intel_cmc.dts')
Simon Glassda229092016-11-25 20:15:56 -07001290 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Meng59ea8c22017-08-15 22:41:54 -07001291
1292 def testPackVbt(self):
1293 """Test that an image with a VBT binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001294 data = self._DoReadFile('046_intel_vbt.dts')
Bin Meng59ea8c22017-08-15 22:41:54 -07001295 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glass9fc60b42017-11-12 21:52:22 -07001296
Simon Glass56509842017-11-12 21:52:25 -07001297 def testSplBssPad(self):
1298 """Test that we can pad SPL's BSS with zeros"""
Simon Glass6b187df2017-11-12 21:52:27 -07001299 # ELF file with a '__bss_size' symbol
Simon Glass11ae93e2018-10-01 21:12:47 -06001300 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001301 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001302 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
1303 data)
Simon Glass56509842017-11-12 21:52:25 -07001304
Simon Glass86af5112018-10-01 21:12:42 -06001305 def testSplBssPadMissing(self):
1306 """Test that a missing symbol is detected"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001307 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glassb50e5612017-11-13 18:54:54 -07001308 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001309 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassb50e5612017-11-13 18:54:54 -07001310 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1311 str(e.exception))
1312
Simon Glass87722132017-11-12 21:52:26 -07001313 def testPackStart16Spl(self):
Simon Glass35b384c2018-09-14 04:57:10 -06001314 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001315 data = self._DoReadFile('048_x86_start16_spl.dts')
Simon Glass87722132017-11-12 21:52:26 -07001316 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1317
Simon Glass736bb0a2018-07-06 10:27:17 -06001318 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1319 """Helper function for microcode tests
Simon Glass6b187df2017-11-12 21:52:27 -07001320
1321 We expect to see the following in the image, in order:
1322 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1323 correct place
1324 u-boot.dtb with the microcode removed
1325 the microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001326
1327 Args:
1328 dts: Device tree file to use for test
1329 ucode_second: True if the microsecond entry is second instead of
1330 third
Simon Glass6b187df2017-11-12 21:52:27 -07001331 """
Simon Glass11ae93e2018-10-01 21:12:47 -06001332 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass736bb0a2018-07-06 10:27:17 -06001333 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1334 ucode_second=ucode_second)
Simon Glassc6c10e72019-05-17 22:00:46 -06001335 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1336 b'ter somewhere in here', first)
Simon Glass6b187df2017-11-12 21:52:27 -07001337
Simon Glass736bb0a2018-07-06 10:27:17 -06001338 def testPackUbootSplMicrocode(self):
1339 """Test that x86 microcode can be handled correctly in SPL"""
Simon Glass741f2d62018-10-01 12:22:30 -06001340 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass736bb0a2018-07-06 10:27:17 -06001341
1342 def testPackUbootSplMicrocodeReorder(self):
1343 """Test that order doesn't matter for microcode entries
1344
1345 This is the same as testPackUbootSplMicrocode but when we process the
1346 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1347 entry, so we reply on binman to try later.
1348 """
Simon Glass741f2d62018-10-01 12:22:30 -06001349 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass736bb0a2018-07-06 10:27:17 -06001350 ucode_second=True)
1351
Simon Glassca4f4ff2017-11-12 21:52:28 -07001352 def testPackMrc(self):
1353 """Test that an image with an MRC binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001354 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassca4f4ff2017-11-12 21:52:28 -07001355 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1356
Simon Glass47419ea2017-11-13 18:54:55 -07001357 def testSplDtb(self):
1358 """Test that an image with spl/u-boot-spl.dtb can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001359 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass47419ea2017-11-13 18:54:55 -07001360 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1361
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001362 def testSplNoDtb(self):
1363 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass0fe44dc2021-04-25 08:39:32 +12001364 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001365 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001366 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1367
Simon Glass3d433382021-03-21 18:24:30 +13001368 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
1369 use_expanded=False):
Simon Glassf5898822021-03-18 20:24:56 +13001370 """Check the image contains the expected symbol values
1371
1372 Args:
1373 dts: Device tree file to use for test
1374 base_data: Data before and after 'u-boot' section
1375 u_boot_offset: Offset of 'u-boot' section in image
Simon Glass3d433382021-03-21 18:24:30 +13001376 entry_args: Dict of entry args to supply to binman
1377 key: arg name
1378 value: value of that arg
1379 use_expanded: True to use expanded entries where available, e.g.
1380 'u-boot-expanded' instead of 'u-boot'
Simon Glassf5898822021-03-18 20:24:56 +13001381 """
Simon Glass1542c8b2019-08-24 07:22:56 -06001382 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass19790632017-11-13 18:55:01 -07001383 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1384 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Simon Glassf5898822021-03-18 20:24:56 +13001385 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
1386 addr)
Simon Glass19790632017-11-13 18:55:01 -07001387
Simon Glass11ae93e2018-10-01 21:12:47 -06001388 self._SetupSplElf('u_boot_binman_syms')
Simon Glass3d433382021-03-21 18:24:30 +13001389 data = self._DoReadFileDtb(dts, entry_args=entry_args,
1390 use_expanded=use_expanded)[0]
Simon Glassf5898822021-03-18 20:24:56 +13001391 # The image should contain the symbols from u_boot_binman_syms.c
1392 # Note that image_pos is adjusted by the base address of the image,
1393 # which is 0x10 in our test image
1394 sym_values = struct.pack('<LQLL', 0x00,
1395 u_boot_offset + len(U_BOOT_DATA),
1396 0x10 + u_boot_offset, 0x04)
1397 expected = (sym_values + base_data[20:] +
Simon Glasse6d85ff2019-05-14 15:53:47 -06001398 tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
Simon Glassf5898822021-03-18 20:24:56 +13001399 base_data[20:])
Simon Glass19790632017-11-13 18:55:01 -07001400 self.assertEqual(expected, data)
1401
Simon Glassf5898822021-03-18 20:24:56 +13001402 def testSymbols(self):
1403 """Test binman can assign symbols embedded in U-Boot"""
1404 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x18)
1405
1406 def testSymbolsNoDtb(self):
1407 """Test binman can assign symbols embedded in U-Boot SPL"""
Simon Glasse9e0db82021-03-21 18:24:29 +13001408 self.checkSymbols('196_symbols_nodtb.dts',
Simon Glassf5898822021-03-18 20:24:56 +13001409 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1410 0x38)
1411
Simon Glassdd57c132018-06-01 09:38:11 -06001412 def testPackUnitAddress(self):
1413 """Test that we support multiple binaries with the same name"""
Simon Glass741f2d62018-10-01 12:22:30 -06001414 data = self._DoReadFile('054_unit_address.dts')
Simon Glassdd57c132018-06-01 09:38:11 -06001415 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1416
Simon Glass18546952018-06-01 09:38:16 -06001417 def testSections(self):
1418 """Basic test of sections"""
Simon Glass741f2d62018-10-01 12:22:30 -06001419 data = self._DoReadFile('055_sections.dts')
Simon Glassc6c10e72019-05-17 22:00:46 -06001420 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1421 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
1422 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
Simon Glass18546952018-06-01 09:38:16 -06001423 self.assertEqual(expected, data)
Simon Glass9fc60b42017-11-12 21:52:22 -07001424
Simon Glass3b0c3822018-06-01 09:38:20 -06001425 def testMap(self):
1426 """Tests outputting a map of the images"""
Simon Glass741f2d62018-10-01 12:22:30 -06001427 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001428 self.assertEqual('''ImagePos Offset Size Name
142900000000 00000000 00000028 main-section
143000000000 00000000 00000010 section@0
143100000000 00000000 00000004 u-boot
143200000010 00000010 00000010 section@1
143300000010 00000000 00000004 u-boot
143400000020 00000020 00000004 section@2
143500000020 00000000 00000004 u-boot
Simon Glass3b0c3822018-06-01 09:38:20 -06001436''', map_data)
1437
Simon Glassc8d48ef2018-06-01 09:38:21 -06001438 def testNamePrefix(self):
1439 """Tests that name prefixes are used"""
Simon Glass741f2d62018-10-01 12:22:30 -06001440 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001441 self.assertEqual('''ImagePos Offset Size Name
144200000000 00000000 00000028 main-section
144300000000 00000000 00000010 section@0
144400000000 00000000 00000004 ro-u-boot
144500000010 00000010 00000010 section@1
144600000010 00000000 00000004 rw-u-boot
Simon Glassc8d48ef2018-06-01 09:38:21 -06001447''', map_data)
1448
Simon Glass736bb0a2018-07-06 10:27:17 -06001449 def testUnknownContents(self):
1450 """Test that obtaining the contents works as expected"""
1451 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001452 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass8beb11e2019-07-08 14:25:47 -06001453 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glass16287932020-04-17 18:09:03 -06001454 "processing of contents: remaining ["
1455 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass736bb0a2018-07-06 10:27:17 -06001456
Simon Glass5c890232018-07-06 10:27:19 -06001457 def testBadChangeSize(self):
1458 """Test that trying to change the size of an entry fails"""
Simon Glassc52c9e72019-07-08 14:25:37 -06001459 try:
1460 state.SetAllowEntryExpansion(False)
1461 with self.assertRaises(ValueError) as e:
1462 self._DoReadFile('059_change_size.dts', True)
Simon Glass79d3c582019-07-20 12:23:57 -06001463 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glassc52c9e72019-07-08 14:25:37 -06001464 str(e.exception))
1465 finally:
1466 state.SetAllowEntryExpansion(True)
Simon Glass5c890232018-07-06 10:27:19 -06001467
Simon Glass16b8d6b2018-07-06 10:27:42 -06001468 def testUpdateFdt(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001469 """Test that we can update the device tree with offset/size info"""
Simon Glass741f2d62018-10-01 12:22:30 -06001470 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glass16b8d6b2018-07-06 10:27:42 -06001471 update_dtb=True)
Simon Glasscee02e62018-07-17 13:25:52 -06001472 dtb = fdt.Fdt(out_dtb_fname)
1473 dtb.Scan()
Simon Glass12bb1a92019-07-20 12:23:51 -06001474 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001475 self.assertEqual({
Simon Glassdbf6be92018-08-01 15:22:42 -06001476 'image-pos': 0,
Simon Glass8122f392018-07-17 13:25:28 -06001477 'offset': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001478 '_testing:offset': 32,
Simon Glass79d3c582019-07-20 12:23:57 -06001479 '_testing:size': 2,
Simon Glassdbf6be92018-08-01 15:22:42 -06001480 '_testing:image-pos': 32,
Simon Glass3ab95982018-08-01 15:22:37 -06001481 'section@0/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001482 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001483 'section@0/u-boot:image-pos': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001484 'section@0:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001485 'section@0:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001486 'section@0:image-pos': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001487
Simon Glass3ab95982018-08-01 15:22:37 -06001488 'section@1/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001489 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001490 'section@1/u-boot:image-pos': 16,
Simon Glass3ab95982018-08-01 15:22:37 -06001491 'section@1:offset': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001492 'section@1:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001493 'section@1:image-pos': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001494 'size': 40
1495 }, props)
1496
1497 def testUpdateFdtBad(self):
1498 """Test that we detect when ProcessFdt never completes"""
1499 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001500 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001501 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glass16287932020-04-17 18:09:03 -06001502 '[<binman.etype._testing.Entry__testing',
1503 str(e.exception))
Simon Glass5c890232018-07-06 10:27:19 -06001504
Simon Glass53af22a2018-07-17 13:25:32 -06001505 def testEntryArgs(self):
1506 """Test passing arguments to entries from the command line"""
1507 entry_args = {
1508 'test-str-arg': 'test1',
1509 'test-int-arg': '456',
1510 }
Simon Glass741f2d62018-10-01 12:22:30 -06001511 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001512 self.assertIn('image', control.images)
1513 entry = control.images['image'].GetEntries()['_testing']
1514 self.assertEqual('test0', entry.test_str_fdt)
1515 self.assertEqual('test1', entry.test_str_arg)
1516 self.assertEqual(123, entry.test_int_fdt)
1517 self.assertEqual(456, entry.test_int_arg)
1518
1519 def testEntryArgsMissing(self):
1520 """Test missing arguments and properties"""
1521 entry_args = {
1522 'test-int-arg': '456',
1523 }
Simon Glass741f2d62018-10-01 12:22:30 -06001524 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001525 entry = control.images['image'].GetEntries()['_testing']
1526 self.assertEqual('test0', entry.test_str_fdt)
1527 self.assertEqual(None, entry.test_str_arg)
1528 self.assertEqual(None, entry.test_int_fdt)
1529 self.assertEqual(456, entry.test_int_arg)
1530
1531 def testEntryArgsRequired(self):
1532 """Test missing arguments and properties"""
1533 entry_args = {
1534 'test-int-arg': '456',
1535 }
1536 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001537 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass3decfa32020-09-01 05:13:54 -06001538 self.assertIn("Node '/binman/_testing': "
1539 'Missing required properties/entry args: test-str-arg, '
1540 'test-int-fdt, test-int-arg',
Simon Glass53af22a2018-07-17 13:25:32 -06001541 str(e.exception))
1542
1543 def testEntryArgsInvalidFormat(self):
1544 """Test that an invalid entry-argument format is detected"""
Simon Glass53cd5d92019-07-08 14:25:29 -06001545 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1546 '-ano-value']
Simon Glass53af22a2018-07-17 13:25:32 -06001547 with self.assertRaises(ValueError) as e:
1548 self._DoBinman(*args)
1549 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1550
1551 def testEntryArgsInvalidInteger(self):
1552 """Test that an invalid entry-argument integer is detected"""
1553 entry_args = {
1554 'test-int-arg': 'abc',
1555 }
1556 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001557 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001558 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1559 "'test-int-arg' (value 'abc') to integer",
1560 str(e.exception))
1561
1562 def testEntryArgsInvalidDatatype(self):
1563 """Test that an invalid entry-argument datatype is detected
1564
1565 This test could be written in entry_test.py except that it needs
1566 access to control.entry_args, which seems more than that module should
1567 be able to see.
1568 """
1569 entry_args = {
1570 'test-bad-datatype-arg': '12',
1571 }
1572 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001573 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass53af22a2018-07-17 13:25:32 -06001574 entry_args=entry_args)
1575 self.assertIn('GetArg() internal error: Unknown data type ',
1576 str(e.exception))
1577
Simon Glassbb748372018-07-17 13:25:33 -06001578 def testText(self):
1579 """Test for a text entry type"""
1580 entry_args = {
1581 'test-id': TEXT_DATA,
1582 'test-id2': TEXT_DATA2,
1583 'test-id3': TEXT_DATA3,
1584 }
Simon Glass741f2d62018-10-01 12:22:30 -06001585 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glassbb748372018-07-17 13:25:33 -06001586 entry_args=entry_args)
Simon Glassc6c10e72019-05-17 22:00:46 -06001587 expected = (tools.ToBytes(TEXT_DATA) +
1588 tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1589 tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
Simon Glassaa88b502019-07-08 13:18:40 -06001590 b'some text' + b'more text')
Simon Glassbb748372018-07-17 13:25:33 -06001591 self.assertEqual(expected, data)
1592
Simon Glassfd8d1f72018-07-17 13:25:36 -06001593 def testEntryDocs(self):
1594 """Test for creation of entry documentation"""
1595 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass87d43322020-08-05 13:27:46 -06001596 control.WriteEntryDocs(control.GetEntryModules())
Simon Glassfd8d1f72018-07-17 13:25:36 -06001597 self.assertTrue(len(stdout.getvalue()) > 0)
1598
1599 def testEntryDocsMissing(self):
1600 """Test handling of missing entry documentation"""
1601 with self.assertRaises(ValueError) as e:
1602 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass87d43322020-08-05 13:27:46 -06001603 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glassfd8d1f72018-07-17 13:25:36 -06001604 self.assertIn('Documentation is missing for modules: u_boot',
1605 str(e.exception))
1606
Simon Glass11e36cc2018-07-17 13:25:38 -06001607 def testFmap(self):
1608 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001609 data = self._DoReadFile('067_fmap.dts')
Simon Glass11e36cc2018-07-17 13:25:38 -06001610 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc6c10e72019-05-17 22:00:46 -06001611 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1612 U_BOOT_DATA + tools.GetBytes(ord('a'), 12))
Simon Glass11e36cc2018-07-17 13:25:38 -06001613 self.assertEqual(expected, data[:32])
Simon Glassc6c10e72019-05-17 22:00:46 -06001614 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass11e36cc2018-07-17 13:25:38 -06001615 self.assertEqual(1, fhdr.ver_major)
1616 self.assertEqual(0, fhdr.ver_minor)
1617 self.assertEqual(0, fhdr.base)
Simon Glass17365752021-04-03 11:05:10 +13001618 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 5
Simon Glassc7722e82021-04-03 11:05:09 +13001619 self.assertEqual(16 + 16 + expect_size, fhdr.image_size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001620 self.assertEqual(b'FMAP', fhdr.name)
Simon Glass17365752021-04-03 11:05:10 +13001621 self.assertEqual(5, fhdr.nareas)
Simon Glassc7722e82021-04-03 11:05:09 +13001622 fiter = iter(fentries)
Simon Glass11e36cc2018-07-17 13:25:38 -06001623
Simon Glassc7722e82021-04-03 11:05:09 +13001624 fentry = next(fiter)
Simon Glass17365752021-04-03 11:05:10 +13001625 self.assertEqual(b'SECTION0', fentry.name)
1626 self.assertEqual(0, fentry.offset)
1627 self.assertEqual(16, fentry.size)
1628 self.assertEqual(0, fentry.flags)
1629
1630 fentry = next(fiter)
Simon Glassc7722e82021-04-03 11:05:09 +13001631 self.assertEqual(b'RO_U_BOOT', fentry.name)
1632 self.assertEqual(0, fentry.offset)
1633 self.assertEqual(4, fentry.size)
1634 self.assertEqual(0, fentry.flags)
Simon Glass11e36cc2018-07-17 13:25:38 -06001635
Simon Glassc7722e82021-04-03 11:05:09 +13001636 fentry = next(fiter)
Simon Glass17365752021-04-03 11:05:10 +13001637 self.assertEqual(b'SECTION1', fentry.name)
1638 self.assertEqual(16, fentry.offset)
1639 self.assertEqual(16, fentry.size)
1640 self.assertEqual(0, fentry.flags)
1641
1642 fentry = next(fiter)
Simon Glassc7722e82021-04-03 11:05:09 +13001643 self.assertEqual(b'RW_U_BOOT', fentry.name)
1644 self.assertEqual(16, fentry.offset)
1645 self.assertEqual(4, fentry.size)
1646 self.assertEqual(0, fentry.flags)
Simon Glass11e36cc2018-07-17 13:25:38 -06001647
Simon Glassc7722e82021-04-03 11:05:09 +13001648 fentry = next(fiter)
1649 self.assertEqual(b'FMAP', fentry.name)
1650 self.assertEqual(32, fentry.offset)
1651 self.assertEqual(expect_size, fentry.size)
1652 self.assertEqual(0, fentry.flags)
Simon Glass11e36cc2018-07-17 13:25:38 -06001653
Simon Glassec127af2018-07-17 13:25:39 -06001654 def testBlobNamedByArg(self):
1655 """Test we can add a blob with the filename coming from an entry arg"""
1656 entry_args = {
1657 'cros-ec-rw-path': 'ecrw.bin',
1658 }
Simon Glass3decfa32020-09-01 05:13:54 -06001659 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassec127af2018-07-17 13:25:39 -06001660
Simon Glass3af8e492018-07-17 13:25:40 -06001661 def testFill(self):
1662 """Test for an fill entry type"""
Simon Glass741f2d62018-10-01 12:22:30 -06001663 data = self._DoReadFile('069_fill.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001664 expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
Simon Glass3af8e492018-07-17 13:25:40 -06001665 self.assertEqual(expected, data)
1666
1667 def testFillNoSize(self):
1668 """Test for an fill entry type with no size"""
1669 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001670 self._DoReadFile('070_fill_no_size.dts')
Simon Glass3af8e492018-07-17 13:25:40 -06001671 self.assertIn("'fill' entry must have a size property",
1672 str(e.exception))
1673
Simon Glass0ef87aa2018-07-17 13:25:44 -06001674 def _HandleGbbCommand(self, pipe_list):
1675 """Fake calls to the futility utility"""
1676 if pipe_list[0][0] == 'futility':
1677 fname = pipe_list[0][-1]
1678 # Append our GBB data to the file, which will happen every time the
1679 # futility command is called.
Simon Glass1d0ebf72019-05-14 15:53:42 -06001680 with open(fname, 'ab') as fd:
Simon Glass0ef87aa2018-07-17 13:25:44 -06001681 fd.write(GBB_DATA)
1682 return command.CommandResult()
1683
1684 def testGbb(self):
1685 """Test for the Chromium OS Google Binary Block"""
1686 command.test_result = self._HandleGbbCommand
1687 entry_args = {
1688 'keydir': 'devkeys',
1689 'bmpblk': 'bmpblk.bin',
1690 }
Simon Glass741f2d62018-10-01 12:22:30 -06001691 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glass0ef87aa2018-07-17 13:25:44 -06001692
1693 # Since futility
Simon Glasse6d85ff2019-05-14 15:53:47 -06001694 expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1695 tools.GetBytes(0, 0x2180 - 16))
Simon Glass0ef87aa2018-07-17 13:25:44 -06001696 self.assertEqual(expected, data)
1697
1698 def testGbbTooSmall(self):
1699 """Test for the Chromium OS Google Binary Block being large enough"""
1700 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001701 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001702 self.assertIn("Node '/binman/gbb': GBB is too small",
1703 str(e.exception))
1704
1705 def testGbbNoSize(self):
1706 """Test for the Chromium OS Google Binary Block having a size"""
1707 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001708 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001709 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1710 str(e.exception))
1711
Simon Glass24d0d3c2018-07-17 13:25:47 -06001712 def _HandleVblockCommand(self, pipe_list):
Simon Glass5af9ebc2021-01-06 21:35:17 -07001713 """Fake calls to the futility utility
1714
1715 The expected pipe is:
1716
1717 [('futility', 'vbutil_firmware', '--vblock',
1718 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1719 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1720 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1721 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1722
1723 This writes to the output file (here, 'vblock.vblock'). If
1724 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1725 of the input data (here, 'input.vblock').
1726 """
Simon Glass24d0d3c2018-07-17 13:25:47 -06001727 if pipe_list[0][0] == 'futility':
1728 fname = pipe_list[0][3]
Simon Glassa326b492018-09-14 04:57:11 -06001729 with open(fname, 'wb') as fd:
Simon Glass5af9ebc2021-01-06 21:35:17 -07001730 if self._hash_data:
1731 infile = pipe_list[0][11]
1732 m = hashlib.sha256()
1733 data = tools.ReadFile(infile)
1734 m.update(data)
1735 fd.write(m.digest())
1736 else:
1737 fd.write(VBLOCK_DATA)
1738
Simon Glass24d0d3c2018-07-17 13:25:47 -06001739 return command.CommandResult()
1740
1741 def testVblock(self):
1742 """Test for the Chromium OS Verified Boot Block"""
Simon Glass5af9ebc2021-01-06 21:35:17 -07001743 self._hash_data = False
Simon Glass24d0d3c2018-07-17 13:25:47 -06001744 command.test_result = self._HandleVblockCommand
1745 entry_args = {
1746 'keydir': 'devkeys',
1747 }
Simon Glass741f2d62018-10-01 12:22:30 -06001748 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass24d0d3c2018-07-17 13:25:47 -06001749 entry_args=entry_args)
1750 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1751 self.assertEqual(expected, data)
1752
1753 def testVblockNoContent(self):
1754 """Test we detect a vblock which has no content to sign"""
1755 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001756 self._DoReadFile('075_vblock_no_content.dts')
Simon Glass189f2912021-03-21 18:24:31 +13001757 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
Simon Glass24d0d3c2018-07-17 13:25:47 -06001758 'property', str(e.exception))
1759
1760 def testVblockBadPhandle(self):
1761 """Test that we detect a vblock with an invalid phandle in contents"""
1762 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001763 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001764 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1765 '1000', str(e.exception))
1766
1767 def testVblockBadEntry(self):
1768 """Test that we detect an entry that points to a non-entry"""
1769 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001770 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001771 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1772 "'other'", str(e.exception))
1773
Simon Glass5af9ebc2021-01-06 21:35:17 -07001774 def testVblockContent(self):
1775 """Test that the vblock signs the right data"""
1776 self._hash_data = True
1777 command.test_result = self._HandleVblockCommand
1778 entry_args = {
1779 'keydir': 'devkeys',
1780 }
1781 data = self._DoReadFileDtb(
1782 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1783 entry_args=entry_args)[0]
1784 hashlen = 32 # SHA256 hash is 32 bytes
1785 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1786 hashval = data[-hashlen:]
1787 dtb = data[len(U_BOOT_DATA):-hashlen]
1788
1789 expected_data = U_BOOT_DATA + dtb
1790
1791 # The hashval should be a hash of the dtb
1792 m = hashlib.sha256()
1793 m.update(expected_data)
1794 expected_hashval = m.digest()
1795 self.assertEqual(expected_hashval, hashval)
1796
Simon Glassb8ef5b62018-07-17 13:25:48 -06001797 def testTpl(self):
Simon Glass2090f1e2019-08-24 07:23:00 -06001798 """Test that an image with TPL and its device tree can be created"""
Simon Glassb8ef5b62018-07-17 13:25:48 -06001799 # ELF file with a '__bss_size' symbol
Simon Glass2090f1e2019-08-24 07:23:00 -06001800 self._SetupTplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001801 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glassb8ef5b62018-07-17 13:25:48 -06001802 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1803
Simon Glass15a587c2018-07-17 13:25:51 -06001804 def testUsesPos(self):
1805 """Test that the 'pos' property cannot be used anymore"""
1806 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001807 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass15a587c2018-07-17 13:25:51 -06001808 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1809 "'pos'", str(e.exception))
1810
Simon Glassd178eab2018-09-14 04:57:08 -06001811 def testFillZero(self):
1812 """Test for an fill entry type with a size of 0"""
Simon Glass741f2d62018-10-01 12:22:30 -06001813 data = self._DoReadFile('080_fill_empty.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001814 self.assertEqual(tools.GetBytes(0, 16), data)
Simon Glassd178eab2018-09-14 04:57:08 -06001815
Simon Glass0b489362018-09-14 04:57:09 -06001816 def testTextMissing(self):
1817 """Test for a text entry type where there is no text"""
1818 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001819 self._DoReadFileDtb('066_text.dts',)
Simon Glass0b489362018-09-14 04:57:09 -06001820 self.assertIn("Node '/binman/text': No value provided for text label "
1821 "'test-id'", str(e.exception))
1822
Simon Glass35b384c2018-09-14 04:57:10 -06001823 def testPackStart16Tpl(self):
1824 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001825 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glass35b384c2018-09-14 04:57:10 -06001826 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1827
Simon Glass0bfa7b02018-09-14 04:57:12 -06001828 def testSelectImage(self):
1829 """Test that we can select which images to build"""
Simon Glasseb833d82019-04-25 21:58:34 -06001830 expected = 'Skipping images: image1'
Simon Glass0bfa7b02018-09-14 04:57:12 -06001831
Simon Glasseb833d82019-04-25 21:58:34 -06001832 # We should only get the expected message in verbose mode
Simon Glassee0c9a72019-07-08 13:18:48 -06001833 for verbosity in (0, 2):
Simon Glasseb833d82019-04-25 21:58:34 -06001834 with test_util.capture_sys_output() as (stdout, stderr):
1835 retcode = self._DoTestFile('006_dual_image.dts',
1836 verbosity=verbosity,
1837 images=['image2'])
1838 self.assertEqual(0, retcode)
1839 if verbosity:
1840 self.assertIn(expected, stdout.getvalue())
1841 else:
1842 self.assertNotIn(expected, stdout.getvalue())
1843
1844 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1845 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
Simon Glassf86a7362019-07-20 12:24:10 -06001846 self._CleanupOutputDir()
Simon Glass0bfa7b02018-09-14 04:57:12 -06001847
Simon Glass6ed45ba2018-09-14 04:57:24 -06001848 def testUpdateFdtAll(self):
1849 """Test that all device trees are updated with offset/size info"""
Simon Glass3c081312019-07-08 14:25:26 -06001850 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glass6ed45ba2018-09-14 04:57:24 -06001851
1852 base_expected = {
1853 'section:image-pos': 0,
1854 'u-boot-tpl-dtb:size': 513,
1855 'u-boot-spl-dtb:size': 513,
1856 'u-boot-spl-dtb:offset': 493,
1857 'image-pos': 0,
1858 'section/u-boot-dtb:image-pos': 0,
1859 'u-boot-spl-dtb:image-pos': 493,
1860 'section/u-boot-dtb:size': 493,
1861 'u-boot-tpl-dtb:image-pos': 1006,
1862 'section/u-boot-dtb:offset': 0,
1863 'section:size': 493,
1864 'offset': 0,
1865 'section:offset': 0,
1866 'u-boot-tpl-dtb:offset': 1006,
1867 'size': 1519
1868 }
1869
1870 # We expect three device-tree files in the output, one after the other.
1871 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1872 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1873 # main U-Boot tree. All three should have the same postions and offset.
1874 start = 0
1875 for item in ['', 'spl', 'tpl']:
1876 dtb = fdt.Fdt.FromData(data[start:])
1877 dtb.Scan()
Simon Glass12bb1a92019-07-20 12:23:51 -06001878 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
1879 ['spl', 'tpl'])
Simon Glass6ed45ba2018-09-14 04:57:24 -06001880 expected = dict(base_expected)
1881 if item:
1882 expected[item] = 0
1883 self.assertEqual(expected, props)
1884 start += dtb._fdt_obj.totalsize()
1885
1886 def testUpdateFdtOutput(self):
1887 """Test that output DTB files are updated"""
1888 try:
Simon Glass741f2d62018-10-01 12:22:30 -06001889 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glass6ed45ba2018-09-14 04:57:24 -06001890 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1891
1892 # Unfortunately, compiling a source file always results in a file
1893 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass741f2d62018-10-01 12:22:30 -06001894 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glass6ed45ba2018-09-14 04:57:24 -06001895 # binman as a file called u-boot.dtb. To fix this, copy the file
1896 # over to the expected place.
Simon Glass6ed45ba2018-09-14 04:57:24 -06001897 start = 0
1898 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1899 'tpl/u-boot-tpl.dtb.out']:
1900 dtb = fdt.Fdt.FromData(data[start:])
1901 size = dtb._fdt_obj.totalsize()
1902 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1903 outdata = tools.ReadFile(pathname)
1904 name = os.path.split(fname)[0]
1905
1906 if name:
1907 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1908 else:
1909 orig_indata = dtb_data
1910 self.assertNotEqual(outdata, orig_indata,
1911 "Expected output file '%s' be updated" % pathname)
1912 self.assertEqual(outdata, data[start:start + size],
1913 "Expected output file '%s' to match output image" %
1914 pathname)
1915 start += size
1916 finally:
1917 self._ResetDtbs()
1918
Simon Glass83d73c22018-09-14 04:57:26 -06001919 def _decompress(self, data):
Simon Glassff5c7e32019-07-08 13:18:42 -06001920 return tools.Decompress(data, 'lz4')
Simon Glass83d73c22018-09-14 04:57:26 -06001921
1922 def testCompress(self):
1923 """Test compression of blobs"""
Simon Glassac62fba2019-07-08 13:18:53 -06001924 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06001925 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass83d73c22018-09-14 04:57:26 -06001926 use_real_dtb=True, update_dtb=True)
1927 dtb = fdt.Fdt(out_dtb_fname)
1928 dtb.Scan()
1929 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1930 orig = self._decompress(data)
1931 self.assertEquals(COMPRESS_DATA, orig)
Simon Glass97c3e9a2020-10-26 17:40:15 -06001932
1933 # Do a sanity check on various fields
1934 image = control.images['image']
1935 entries = image.GetEntries()
1936 self.assertEqual(1, len(entries))
1937
1938 entry = entries['blob']
1939 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
1940 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
1941 orig = self._decompress(entry.data)
1942 self.assertEqual(orig, entry.uncomp_data)
1943
Simon Glass63e7ba62020-10-26 17:40:16 -06001944 self.assertEqual(image.data, entry.data)
1945
Simon Glass83d73c22018-09-14 04:57:26 -06001946 expected = {
1947 'blob:uncomp-size': len(COMPRESS_DATA),
1948 'blob:size': len(data),
1949 'size': len(data),
1950 }
1951 self.assertEqual(expected, props)
1952
Simon Glass0a98b282018-09-14 04:57:28 -06001953 def testFiles(self):
1954 """Test bringing in multiple files"""
Simon Glass741f2d62018-10-01 12:22:30 -06001955 data = self._DoReadFile('084_files.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001956 self.assertEqual(FILES_DATA, data)
1957
1958 def testFilesCompress(self):
1959 """Test bringing in multiple files and compressing them"""
Simon Glassac62fba2019-07-08 13:18:53 -06001960 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06001961 data = self._DoReadFile('085_files_compress.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001962
1963 image = control.images['image']
1964 entries = image.GetEntries()
1965 files = entries['files']
Simon Glass8beb11e2019-07-08 14:25:47 -06001966 entries = files._entries
Simon Glass0a98b282018-09-14 04:57:28 -06001967
Simon Glassc6c10e72019-05-17 22:00:46 -06001968 orig = b''
Simon Glass0a98b282018-09-14 04:57:28 -06001969 for i in range(1, 3):
1970 key = '%d.dat' % i
1971 start = entries[key].image_pos
1972 len = entries[key].size
1973 chunk = data[start:start + len]
1974 orig += self._decompress(chunk)
1975
1976 self.assertEqual(FILES_DATA, orig)
1977
1978 def testFilesMissing(self):
1979 """Test missing files"""
1980 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001981 data = self._DoReadFile('086_files_none.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001982 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1983 'no files', str(e.exception))
1984
1985 def testFilesNoPattern(self):
1986 """Test missing files"""
1987 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001988 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001989 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1990 str(e.exception))
1991
Simon Glassba64a0b2018-09-14 04:57:29 -06001992 def testExpandSize(self):
1993 """Test an expanding entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001994 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
Simon Glassba64a0b2018-09-14 04:57:29 -06001995 map=True)
Simon Glassc6c10e72019-05-17 22:00:46 -06001996 expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA +
1997 MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA +
1998 tools.GetBytes(ord('c'), 8) + U_BOOT_DATA +
1999 tools.GetBytes(ord('d'), 8))
Simon Glassba64a0b2018-09-14 04:57:29 -06002000 self.assertEqual(expect, data)
2001 self.assertEqual('''ImagePos Offset Size Name
200200000000 00000000 00000028 main-section
200300000000 00000000 00000008 fill
200400000008 00000008 00000004 u-boot
20050000000c 0000000c 00000004 section
20060000000c 00000000 00000003 intel-mrc
200700000010 00000010 00000004 u-boot2
200800000014 00000014 0000000c section2
200900000014 00000000 00000008 fill
20100000001c 00000008 00000004 u-boot
201100000020 00000020 00000008 fill2
2012''', map_data)
2013
2014 def testExpandSizeBad(self):
2015 """Test an expanding entry which fails to provide contents"""
Simon Glass163ed6c2018-09-14 04:57:36 -06002016 with test_util.capture_sys_output() as (stdout, stderr):
2017 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002018 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
Simon Glassba64a0b2018-09-14 04:57:29 -06002019 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
2020 'expanding entry', str(e.exception))
2021
Simon Glasse0e5df92018-09-14 04:57:31 -06002022 def testHash(self):
2023 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06002024 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06002025 use_real_dtb=True, update_dtb=True)
2026 dtb = fdt.Fdt(out_dtb_fname)
2027 dtb.Scan()
2028 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
2029 m = hashlib.sha256()
2030 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06002031 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06002032
2033 def testHashNoAlgo(self):
2034 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002035 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06002036 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2037 'hash node', str(e.exception))
2038
2039 def testHashBadAlgo(self):
2040 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002041 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06002042 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
2043 str(e.exception))
2044
2045 def testHashSection(self):
2046 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06002047 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06002048 use_real_dtb=True, update_dtb=True)
2049 dtb = fdt.Fdt(out_dtb_fname)
2050 dtb.Scan()
2051 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2052 m = hashlib.sha256()
2053 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06002054 m.update(tools.GetBytes(ord('a'), 16))
2055 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06002056
Simon Glassf0253632018-09-14 04:57:32 -06002057 def testPackUBootTplMicrocode(self):
2058 """Test that x86 microcode can be handled correctly in TPL
2059
2060 We expect to see the following in the image, in order:
2061 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2062 place
2063 u-boot-tpl.dtb with the microcode removed
2064 the microcode
2065 """
Simon Glass2090f1e2019-08-24 07:23:00 -06002066 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass741f2d62018-10-01 12:22:30 -06002067 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glassf0253632018-09-14 04:57:32 -06002068 U_BOOT_TPL_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06002069 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2070 b'ter somewhere in here', first)
Simon Glassf0253632018-09-14 04:57:32 -06002071
Simon Glassf8f8df62018-09-14 04:57:34 -06002072 def testFmapX86(self):
2073 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06002074 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassf8f8df62018-09-14 04:57:34 -06002075 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc6c10e72019-05-17 22:00:46 -06002076 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06002077 self.assertEqual(expected, data[:32])
2078 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2079
2080 self.assertEqual(0x100, fhdr.image_size)
2081
2082 self.assertEqual(0, fentries[0].offset)
2083 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06002084 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06002085
2086 self.assertEqual(4, fentries[1].offset)
2087 self.assertEqual(3, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06002088 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06002089
2090 self.assertEqual(32, fentries[2].offset)
2091 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2092 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06002093 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06002094
2095 def testFmapX86Section(self):
2096 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06002097 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glassc6c10e72019-05-17 22:00:46 -06002098 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06002099 self.assertEqual(expected, data[:32])
2100 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2101
Simon Glass17365752021-04-03 11:05:10 +13002102 self.assertEqual(0x180, fhdr.image_size)
2103 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
Simon Glassc7722e82021-04-03 11:05:09 +13002104 fiter = iter(fentries)
Simon Glassf8f8df62018-09-14 04:57:34 -06002105
Simon Glassc7722e82021-04-03 11:05:09 +13002106 fentry = next(fiter)
2107 self.assertEqual(b'U_BOOT', fentry.name)
2108 self.assertEqual(0, fentry.offset)
2109 self.assertEqual(4, fentry.size)
Simon Glassf8f8df62018-09-14 04:57:34 -06002110
Simon Glassc7722e82021-04-03 11:05:09 +13002111 fentry = next(fiter)
Simon Glass17365752021-04-03 11:05:10 +13002112 self.assertEqual(b'SECTION', fentry.name)
2113 self.assertEqual(4, fentry.offset)
2114 self.assertEqual(0x20 + expect_size, fentry.size)
2115
2116 fentry = next(fiter)
Simon Glassc7722e82021-04-03 11:05:09 +13002117 self.assertEqual(b'INTEL_MRC', fentry.name)
2118 self.assertEqual(4, fentry.offset)
2119 self.assertEqual(3, fentry.size)
Simon Glassf8f8df62018-09-14 04:57:34 -06002120
Simon Glassc7722e82021-04-03 11:05:09 +13002121 fentry = next(fiter)
2122 self.assertEqual(b'FMAP', fentry.name)
2123 self.assertEqual(36, fentry.offset)
2124 self.assertEqual(expect_size, fentry.size)
Simon Glassf8f8df62018-09-14 04:57:34 -06002125
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002126 def testElf(self):
2127 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06002128 self._SetupSplElf()
Simon Glass2090f1e2019-08-24 07:23:00 -06002129 self._SetupTplElf()
Simon Glass53e22bf2019-08-24 07:22:53 -06002130 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002131 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06002132 data = self._DoReadFile('096_elf.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002133
Simon Glass093d1682019-07-08 13:18:25 -06002134 def testElfStrip(self):
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002135 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06002136 self._SetupSplElf()
Simon Glass53e22bf2019-08-24 07:22:53 -06002137 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002138 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06002139 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002140
Simon Glass163ed6c2018-09-14 04:57:36 -06002141 def testPackOverlapMap(self):
2142 """Test that overlapping regions are detected"""
2143 with test_util.capture_sys_output() as (stdout, stderr):
2144 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002145 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glass163ed6c2018-09-14 04:57:36 -06002146 map_fname = tools.GetOutputFilename('image.map')
2147 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2148 stdout.getvalue())
2149
2150 # We should not get an inmage, but there should be a map file
2151 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
2152 self.assertTrue(os.path.exists(map_fname))
Simon Glasseb546ac2019-05-17 22:00:51 -06002153 map_data = tools.ReadFile(map_fname, binary=False)
Simon Glass163ed6c2018-09-14 04:57:36 -06002154 self.assertEqual('''ImagePos Offset Size Name
Simon Glass0ff83da2020-10-26 17:40:24 -06002155<none> 00000000 00000008 main-section
Simon Glass163ed6c2018-09-14 04:57:36 -06002156<none> 00000000 00000004 u-boot
2157<none> 00000003 00000004 u-boot-align
2158''', map_data)
2159
Simon Glass093d1682019-07-08 13:18:25 -06002160 def testPackRefCode(self):
Simon Glass3ae192c2018-10-01 12:22:31 -06002161 """Test that an image with an Intel Reference code binary works"""
2162 data = self._DoReadFile('100_intel_refcode.dts')
2163 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2164
Simon Glass9481c802019-04-25 21:58:39 -06002165 def testSectionOffset(self):
2166 """Tests use of a section with an offset"""
2167 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2168 map=True)
2169 self.assertEqual('''ImagePos Offset Size Name
217000000000 00000000 00000038 main-section
217100000004 00000004 00000010 section@0
217200000004 00000000 00000004 u-boot
217300000018 00000018 00000010 section@1
217400000018 00000000 00000004 u-boot
21750000002c 0000002c 00000004 section@2
21760000002c 00000000 00000004 u-boot
2177''', map_data)
2178 self.assertEqual(data,
Simon Glasse6d85ff2019-05-14 15:53:47 -06002179 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2180 tools.GetBytes(0x21, 12) +
2181 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2182 tools.GetBytes(0x61, 12) +
2183 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2184 tools.GetBytes(0x26, 8))
Simon Glass9481c802019-04-25 21:58:39 -06002185
Simon Glassac62fba2019-07-08 13:18:53 -06002186 def testCbfsRaw(self):
2187 """Test base handling of a Coreboot Filesystem (CBFS)
2188
2189 The exact contents of the CBFS is verified by similar tests in
2190 cbfs_util_test.py. The tests here merely check that the files added to
2191 the CBFS can be found in the final image.
2192 """
2193 data = self._DoReadFile('102_cbfs_raw.dts')
2194 size = 0xb0
2195
2196 cbfs = cbfs_util.CbfsReader(data)
2197 self.assertEqual(size, cbfs.rom_size)
2198
2199 self.assertIn('u-boot-dtb', cbfs.files)
2200 cfile = cbfs.files['u-boot-dtb']
2201 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2202
2203 def testCbfsArch(self):
2204 """Test on non-x86 architecture"""
2205 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2206 size = 0x100
2207
2208 cbfs = cbfs_util.CbfsReader(data)
2209 self.assertEqual(size, cbfs.rom_size)
2210
2211 self.assertIn('u-boot-dtb', cbfs.files)
2212 cfile = cbfs.files['u-boot-dtb']
2213 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2214
2215 def testCbfsStage(self):
2216 """Tests handling of a Coreboot Filesystem (CBFS)"""
2217 if not elf.ELF_TOOLS:
2218 self.skipTest('Python elftools not available')
2219 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2220 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2221 size = 0xb0
2222
2223 data = self._DoReadFile('104_cbfs_stage.dts')
2224 cbfs = cbfs_util.CbfsReader(data)
2225 self.assertEqual(size, cbfs.rom_size)
2226
2227 self.assertIn('u-boot', cbfs.files)
2228 cfile = cbfs.files['u-boot']
2229 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2230
2231 def testCbfsRawCompress(self):
2232 """Test handling of compressing raw files"""
2233 self._CheckLz4()
2234 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2235 size = 0x140
2236
2237 cbfs = cbfs_util.CbfsReader(data)
2238 self.assertIn('u-boot', cbfs.files)
2239 cfile = cbfs.files['u-boot']
2240 self.assertEqual(COMPRESS_DATA, cfile.data)
2241
2242 def testCbfsBadArch(self):
2243 """Test handling of a bad architecture"""
2244 with self.assertRaises(ValueError) as e:
2245 self._DoReadFile('106_cbfs_bad_arch.dts')
2246 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2247
2248 def testCbfsNoSize(self):
2249 """Test handling of a missing size property"""
2250 with self.assertRaises(ValueError) as e:
2251 self._DoReadFile('107_cbfs_no_size.dts')
2252 self.assertIn('entry must have a size property', str(e.exception))
2253
Simon Glasse2f04742021-11-23 11:03:54 -07002254 def testCbfsNoContents(self):
Simon Glassac62fba2019-07-08 13:18:53 -06002255 """Test handling of a CBFS entry which does not provide contentsy"""
2256 with self.assertRaises(ValueError) as e:
2257 self._DoReadFile('108_cbfs_no_contents.dts')
2258 self.assertIn('Could not complete processing of contents',
2259 str(e.exception))
2260
2261 def testCbfsBadCompress(self):
2262 """Test handling of a bad architecture"""
2263 with self.assertRaises(ValueError) as e:
2264 self._DoReadFile('109_cbfs_bad_compress.dts')
2265 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2266 str(e.exception))
2267
2268 def testCbfsNamedEntries(self):
2269 """Test handling of named entries"""
2270 data = self._DoReadFile('110_cbfs_name.dts')
2271
2272 cbfs = cbfs_util.CbfsReader(data)
2273 self.assertIn('FRED', cbfs.files)
2274 cfile1 = cbfs.files['FRED']
2275 self.assertEqual(U_BOOT_DATA, cfile1.data)
2276
2277 self.assertIn('hello', cbfs.files)
2278 cfile2 = cbfs.files['hello']
2279 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2280
Simon Glassc5ac1382019-07-08 13:18:54 -06002281 def _SetupIfwi(self, fname):
2282 """Set up to run an IFWI test
2283
2284 Args:
2285 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2286 """
2287 self._SetupSplElf()
Simon Glass2090f1e2019-08-24 07:23:00 -06002288 self._SetupTplElf()
Simon Glassc5ac1382019-07-08 13:18:54 -06002289
2290 # Intel Integrated Firmware Image (IFWI) file
2291 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2292 data = fd.read()
2293 TestFunctional._MakeInputFile(fname,data)
2294
2295 def _CheckIfwi(self, data):
2296 """Check that an image with an IFWI contains the correct output
2297
2298 Args:
2299 data: Conents of output file
2300 """
2301 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
2302 if data[:0x1000] != expected_desc:
2303 self.fail('Expected descriptor binary at start of image')
2304
2305 # We expect to find the TPL wil in subpart IBBP entry IBBL
2306 image_fname = tools.GetOutputFilename('image.bin')
2307 tpl_fname = tools.GetOutputFilename('tpl.out')
2308 tools.RunIfwiTool(image_fname, tools.CMD_EXTRACT, fname=tpl_fname,
2309 subpart='IBBP', entry_name='IBBL')
2310
2311 tpl_data = tools.ReadFile(tpl_fname)
Simon Glasse95be632019-08-24 07:22:51 -06002312 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glassc5ac1382019-07-08 13:18:54 -06002313
2314 def testPackX86RomIfwi(self):
2315 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2316 self._SetupIfwi('fitimage.bin')
Simon Glass9255f3c2019-08-24 07:23:01 -06002317 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002318 self._CheckIfwi(data)
2319
2320 def testPackX86RomIfwiNoDesc(self):
2321 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2322 self._SetupIfwi('ifwi.bin')
Simon Glass9255f3c2019-08-24 07:23:01 -06002323 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002324 self._CheckIfwi(data)
2325
2326 def testPackX86RomIfwiNoData(self):
2327 """Test that an x86 ROM with IFWI handles missing data"""
2328 self._SetupIfwi('ifwi.bin')
2329 with self.assertRaises(ValueError) as e:
Simon Glass9255f3c2019-08-24 07:23:01 -06002330 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002331 self.assertIn('Could not complete processing of contents',
2332 str(e.exception))
Simon Glass53af22a2018-07-17 13:25:32 -06002333
Simon Glasse073d4e2019-07-08 13:18:56 -06002334 def testCbfsOffset(self):
2335 """Test a CBFS with files at particular offsets
2336
2337 Like all CFBS tests, this is just checking the logic that calls
2338 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2339 """
2340 data = self._DoReadFile('114_cbfs_offset.dts')
2341 size = 0x200
2342
2343 cbfs = cbfs_util.CbfsReader(data)
2344 self.assertEqual(size, cbfs.rom_size)
2345
2346 self.assertIn('u-boot', cbfs.files)
2347 cfile = cbfs.files['u-boot']
2348 self.assertEqual(U_BOOT_DATA, cfile.data)
2349 self.assertEqual(0x40, cfile.cbfs_offset)
2350
2351 self.assertIn('u-boot-dtb', cbfs.files)
2352 cfile2 = cbfs.files['u-boot-dtb']
2353 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2354 self.assertEqual(0x140, cfile2.cbfs_offset)
2355
Simon Glass086cec92019-07-08 14:25:27 -06002356 def testFdtmap(self):
2357 """Test an FDT map can be inserted in the image"""
2358 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2359 fdtmap_data = data[len(U_BOOT_DATA):]
2360 magic = fdtmap_data[:8]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002361 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass086cec92019-07-08 14:25:27 -06002362 self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
2363
2364 fdt_data = fdtmap_data[16:]
2365 dtb = fdt.Fdt.FromData(fdt_data)
2366 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002367 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass086cec92019-07-08 14:25:27 -06002368 self.assertEqual({
2369 'image-pos': 0,
2370 'offset': 0,
2371 'u-boot:offset': 0,
2372 'u-boot:size': len(U_BOOT_DATA),
2373 'u-boot:image-pos': 0,
2374 'fdtmap:image-pos': 4,
2375 'fdtmap:offset': 4,
2376 'fdtmap:size': len(fdtmap_data),
2377 'size': len(data),
2378 }, props)
2379
2380 def testFdtmapNoMatch(self):
2381 """Check handling of an FDT map when the section cannot be found"""
2382 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2383
2384 # Mangle the section name, which should cause a mismatch between the
2385 # correct FDT path and the one expected by the section
2386 image = control.images['image']
Simon Glasscf228942019-07-08 14:25:28 -06002387 image._node.path += '-suffix'
Simon Glass086cec92019-07-08 14:25:27 -06002388 entries = image.GetEntries()
2389 fdtmap = entries['fdtmap']
2390 with self.assertRaises(ValueError) as e:
2391 fdtmap._GetFdtmap()
2392 self.assertIn("Cannot locate node for path '/binman-suffix'",
2393 str(e.exception))
2394
Simon Glasscf228942019-07-08 14:25:28 -06002395 def testFdtmapHeader(self):
2396 """Test an FDT map and image header can be inserted in the image"""
2397 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2398 fdtmap_pos = len(U_BOOT_DATA)
2399 fdtmap_data = data[fdtmap_pos:]
2400 fdt_data = fdtmap_data[16:]
2401 dtb = fdt.Fdt.FromData(fdt_data)
2402 fdt_size = dtb.GetFdtObj().totalsize()
2403 hdr_data = data[-8:]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002404 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002405 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2406 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2407
2408 def testFdtmapHeaderStart(self):
2409 """Test an image header can be inserted at the image start"""
2410 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2411 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2412 hdr_data = data[:8]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002413 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002414 offset = struct.unpack('<I', hdr_data[4:])[0]
2415 self.assertEqual(fdtmap_pos, offset)
2416
2417 def testFdtmapHeaderPos(self):
2418 """Test an image header can be inserted at a chosen position"""
2419 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2420 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2421 hdr_data = data[0x80:0x88]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002422 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002423 offset = struct.unpack('<I', hdr_data[4:])[0]
2424 self.assertEqual(fdtmap_pos, offset)
2425
2426 def testHeaderMissingFdtmap(self):
2427 """Test an image header requires an fdtmap"""
2428 with self.assertRaises(ValueError) as e:
2429 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2430 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2431 str(e.exception))
2432
2433 def testHeaderNoLocation(self):
2434 """Test an image header with a no specified location is detected"""
2435 with self.assertRaises(ValueError) as e:
2436 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2437 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2438 str(e.exception))
2439
Simon Glassc52c9e72019-07-08 14:25:37 -06002440 def testEntryExpand(self):
2441 """Test expanding an entry after it is packed"""
2442 data = self._DoReadFile('121_entry_expand.dts')
Simon Glass79d3c582019-07-20 12:23:57 -06002443 self.assertEqual(b'aaa', data[:3])
2444 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2445 self.assertEqual(b'aaa', data[-3:])
Simon Glassc52c9e72019-07-08 14:25:37 -06002446
2447 def testEntryExpandBad(self):
2448 """Test expanding an entry after it is packed, twice"""
2449 with self.assertRaises(ValueError) as e:
2450 self._DoReadFile('122_entry_expand_twice.dts')
Simon Glass61ec04f2019-07-20 12:23:58 -06002451 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glassc52c9e72019-07-08 14:25:37 -06002452 str(e.exception))
2453
2454 def testEntryExpandSection(self):
2455 """Test expanding an entry within a section after it is packed"""
2456 data = self._DoReadFile('123_entry_expand_section.dts')
Simon Glass79d3c582019-07-20 12:23:57 -06002457 self.assertEqual(b'aaa', data[:3])
2458 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2459 self.assertEqual(b'aaa', data[-3:])
Simon Glassc52c9e72019-07-08 14:25:37 -06002460
Simon Glass6c223fd2019-07-08 14:25:38 -06002461 def testCompressDtb(self):
2462 """Test that compress of device-tree files is supported"""
2463 self._CheckLz4()
2464 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2465 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2466 comp_data = data[len(U_BOOT_DATA):]
2467 orig = self._decompress(comp_data)
2468 dtb = fdt.Fdt.FromData(orig)
2469 dtb.Scan()
2470 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2471 expected = {
2472 'u-boot:size': len(U_BOOT_DATA),
2473 'u-boot-dtb:uncomp-size': len(orig),
2474 'u-boot-dtb:size': len(comp_data),
2475 'size': len(data),
2476 }
2477 self.assertEqual(expected, props)
2478
Simon Glass69f7cb32019-07-08 14:25:41 -06002479 def testCbfsUpdateFdt(self):
2480 """Test that we can update the device tree with CBFS offset/size info"""
2481 self._CheckLz4()
2482 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2483 update_dtb=True)
2484 dtb = fdt.Fdt(out_dtb_fname)
2485 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002486 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass69f7cb32019-07-08 14:25:41 -06002487 del props['cbfs/u-boot:size']
2488 self.assertEqual({
2489 'offset': 0,
2490 'size': len(data),
2491 'image-pos': 0,
2492 'cbfs:offset': 0,
2493 'cbfs:size': len(data),
2494 'cbfs:image-pos': 0,
2495 'cbfs/u-boot:offset': 0x38,
2496 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2497 'cbfs/u-boot:image-pos': 0x38,
2498 'cbfs/u-boot-dtb:offset': 0xb8,
2499 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2500 'cbfs/u-boot-dtb:image-pos': 0xb8,
2501 }, props)
2502
Simon Glass8a1ad062019-07-08 14:25:42 -06002503 def testCbfsBadType(self):
2504 """Test an image header with a no specified location is detected"""
2505 with self.assertRaises(ValueError) as e:
2506 self._DoReadFile('126_cbfs_bad_type.dts')
2507 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2508
Simon Glass41b8ba02019-07-08 14:25:43 -06002509 def testList(self):
2510 """Test listing the files in an image"""
2511 self._CheckLz4()
2512 data = self._DoReadFile('127_list.dts')
2513 image = control.images['image']
2514 entries = image.BuildEntryList()
2515 self.assertEqual(7, len(entries))
2516
2517 ent = entries[0]
2518 self.assertEqual(0, ent.indent)
2519 self.assertEqual('main-section', ent.name)
2520 self.assertEqual('section', ent.etype)
2521 self.assertEqual(len(data), ent.size)
2522 self.assertEqual(0, ent.image_pos)
2523 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002524 self.assertEqual(0, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002525
2526 ent = entries[1]
2527 self.assertEqual(1, ent.indent)
2528 self.assertEqual('u-boot', ent.name)
2529 self.assertEqual('u-boot', ent.etype)
2530 self.assertEqual(len(U_BOOT_DATA), ent.size)
2531 self.assertEqual(0, ent.image_pos)
2532 self.assertEqual(None, ent.uncomp_size)
2533 self.assertEqual(0, ent.offset)
2534
2535 ent = entries[2]
2536 self.assertEqual(1, ent.indent)
2537 self.assertEqual('section', ent.name)
2538 self.assertEqual('section', ent.etype)
2539 section_size = ent.size
2540 self.assertEqual(0x100, ent.image_pos)
2541 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002542 self.assertEqual(0x100, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002543
2544 ent = entries[3]
2545 self.assertEqual(2, ent.indent)
2546 self.assertEqual('cbfs', ent.name)
2547 self.assertEqual('cbfs', ent.etype)
2548 self.assertEqual(0x400, ent.size)
2549 self.assertEqual(0x100, ent.image_pos)
2550 self.assertEqual(None, ent.uncomp_size)
2551 self.assertEqual(0, ent.offset)
2552
2553 ent = entries[4]
2554 self.assertEqual(3, ent.indent)
2555 self.assertEqual('u-boot', ent.name)
2556 self.assertEqual('u-boot', ent.etype)
2557 self.assertEqual(len(U_BOOT_DATA), ent.size)
2558 self.assertEqual(0x138, ent.image_pos)
2559 self.assertEqual(None, ent.uncomp_size)
2560 self.assertEqual(0x38, ent.offset)
2561
2562 ent = entries[5]
2563 self.assertEqual(3, ent.indent)
2564 self.assertEqual('u-boot-dtb', ent.name)
2565 self.assertEqual('text', ent.etype)
2566 self.assertGreater(len(COMPRESS_DATA), ent.size)
2567 self.assertEqual(0x178, ent.image_pos)
2568 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2569 self.assertEqual(0x78, ent.offset)
2570
2571 ent = entries[6]
2572 self.assertEqual(2, ent.indent)
2573 self.assertEqual('u-boot-dtb', ent.name)
2574 self.assertEqual('u-boot-dtb', ent.etype)
2575 self.assertEqual(0x500, ent.image_pos)
2576 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2577 dtb_size = ent.size
2578 # Compressing this data expands it since headers are added
2579 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2580 self.assertEqual(0x400, ent.offset)
2581
2582 self.assertEqual(len(data), 0x100 + section_size)
2583 self.assertEqual(section_size, 0x400 + dtb_size)
2584
Simon Glasse1925fa2019-07-08 14:25:44 -06002585 def testFindFdtmap(self):
2586 """Test locating an FDT map in an image"""
2587 self._CheckLz4()
2588 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2589 image = control.images['image']
2590 entries = image.GetEntries()
2591 entry = entries['fdtmap']
2592 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2593
2594 def testFindFdtmapMissing(self):
2595 """Test failing to locate an FDP map"""
2596 data = self._DoReadFile('005_simple.dts')
2597 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2598
Simon Glass2d260032019-07-08 14:25:45 -06002599 def testFindImageHeader(self):
2600 """Test locating a image header"""
2601 self._CheckLz4()
Simon Glassffded752019-07-08 14:25:46 -06002602 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002603 image = control.images['image']
2604 entries = image.GetEntries()
2605 entry = entries['fdtmap']
2606 # The header should point to the FDT map
2607 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2608
2609 def testFindImageHeaderStart(self):
2610 """Test locating a image header located at the start of an image"""
Simon Glassffded752019-07-08 14:25:46 -06002611 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002612 image = control.images['image']
2613 entries = image.GetEntries()
2614 entry = entries['fdtmap']
2615 # The header should point to the FDT map
2616 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2617
2618 def testFindImageHeaderMissing(self):
2619 """Test failing to locate an image header"""
2620 data = self._DoReadFile('005_simple.dts')
2621 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2622
Simon Glassffded752019-07-08 14:25:46 -06002623 def testReadImage(self):
2624 """Test reading an image and accessing its FDT map"""
2625 self._CheckLz4()
2626 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2627 image_fname = tools.GetOutputFilename('image.bin')
2628 orig_image = control.images['image']
2629 image = Image.FromFile(image_fname)
2630 self.assertEqual(orig_image.GetEntries().keys(),
2631 image.GetEntries().keys())
2632
2633 orig_entry = orig_image.GetEntries()['fdtmap']
2634 entry = image.GetEntries()['fdtmap']
2635 self.assertEquals(orig_entry.offset, entry.offset)
2636 self.assertEquals(orig_entry.size, entry.size)
2637 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2638
2639 def testReadImageNoHeader(self):
2640 """Test accessing an image's FDT map without an image header"""
2641 self._CheckLz4()
2642 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
2643 image_fname = tools.GetOutputFilename('image.bin')
2644 image = Image.FromFile(image_fname)
2645 self.assertTrue(isinstance(image, Image))
Simon Glass10f9d002019-07-20 12:23:50 -06002646 self.assertEqual('image', image.image_name[-5:])
Simon Glassffded752019-07-08 14:25:46 -06002647
2648 def testReadImageFail(self):
2649 """Test failing to read an image image's FDT map"""
2650 self._DoReadFile('005_simple.dts')
2651 image_fname = tools.GetOutputFilename('image.bin')
2652 with self.assertRaises(ValueError) as e:
2653 image = Image.FromFile(image_fname)
2654 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glasse073d4e2019-07-08 13:18:56 -06002655
Simon Glass61f564d2019-07-08 14:25:48 -06002656 def testListCmd(self):
2657 """Test listing the files in an image using an Fdtmap"""
2658 self._CheckLz4()
2659 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2660
2661 # lz4 compression size differs depending on the version
2662 image = control.images['image']
2663 entries = image.GetEntries()
2664 section_size = entries['section'].size
2665 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2666 fdtmap_offset = entries['fdtmap'].offset
2667
Simon Glassf86a7362019-07-20 12:24:10 -06002668 try:
2669 tmpdir, updated_fname = self._SetupImageInTmpdir()
2670 with test_util.capture_sys_output() as (stdout, stderr):
2671 self._DoBinman('ls', '-i', updated_fname)
2672 finally:
2673 shutil.rmtree(tmpdir)
Simon Glass61f564d2019-07-08 14:25:48 -06002674 lines = stdout.getvalue().splitlines()
2675 expected = [
2676'Name Image-pos Size Entry-type Offset Uncomp-size',
2677'----------------------------------------------------------------------',
2678'main-section 0 c00 section 0',
2679' u-boot 0 4 u-boot 0',
2680' section 100 %x section 100' % section_size,
2681' cbfs 100 400 cbfs 0',
2682' u-boot 138 4 u-boot 38',
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002683' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glass61f564d2019-07-08 14:25:48 -06002684' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002685' fdtmap %x 3bd fdtmap %x' %
Simon Glass61f564d2019-07-08 14:25:48 -06002686 (fdtmap_offset, fdtmap_offset),
2687' image-header bf8 8 image-header bf8',
2688 ]
2689 self.assertEqual(expected, lines)
2690
2691 def testListCmdFail(self):
2692 """Test failing to list an image"""
2693 self._DoReadFile('005_simple.dts')
Simon Glassf86a7362019-07-20 12:24:10 -06002694 try:
2695 tmpdir, updated_fname = self._SetupImageInTmpdir()
2696 with self.assertRaises(ValueError) as e:
2697 self._DoBinman('ls', '-i', updated_fname)
2698 finally:
2699 shutil.rmtree(tmpdir)
Simon Glass61f564d2019-07-08 14:25:48 -06002700 self.assertIn("Cannot find FDT map in image", str(e.exception))
2701
2702 def _RunListCmd(self, paths, expected):
2703 """List out entries and check the result
2704
2705 Args:
2706 paths: List of paths to pass to the list command
2707 expected: Expected list of filenames to be returned, in order
2708 """
2709 self._CheckLz4()
2710 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2711 image_fname = tools.GetOutputFilename('image.bin')
2712 image = Image.FromFile(image_fname)
2713 lines = image.GetListEntries(paths)[1]
2714 files = [line[0].strip() for line in lines[1:]]
2715 self.assertEqual(expected, files)
2716
2717 def testListCmdSection(self):
2718 """Test listing the files in a section"""
2719 self._RunListCmd(['section'],
2720 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2721
2722 def testListCmdFile(self):
2723 """Test listing a particular file"""
2724 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2725
2726 def testListCmdWildcard(self):
2727 """Test listing a wildcarded file"""
2728 self._RunListCmd(['*boot*'],
2729 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2730
2731 def testListCmdWildcardMulti(self):
2732 """Test listing a wildcarded file"""
2733 self._RunListCmd(['*cb*', '*head*'],
2734 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2735
2736 def testListCmdEmpty(self):
2737 """Test listing a wildcarded file"""
2738 self._RunListCmd(['nothing'], [])
2739
2740 def testListCmdPath(self):
2741 """Test listing the files in a sub-entry of a section"""
2742 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2743
Simon Glassf667e452019-07-08 14:25:50 -06002744 def _RunExtractCmd(self, entry_name, decomp=True):
2745 """Extract an entry from an image
2746
2747 Args:
2748 entry_name: Entry name to extract
2749 decomp: True to decompress the data if compressed, False to leave
2750 it in its raw uncompressed format
2751
2752 Returns:
2753 data from entry
2754 """
2755 self._CheckLz4()
2756 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2757 image_fname = tools.GetOutputFilename('image.bin')
2758 return control.ReadEntry(image_fname, entry_name, decomp)
2759
2760 def testExtractSimple(self):
2761 """Test extracting a single file"""
2762 data = self._RunExtractCmd('u-boot')
2763 self.assertEqual(U_BOOT_DATA, data)
2764
Simon Glass71ce0ba2019-07-08 14:25:52 -06002765 def testExtractSection(self):
2766 """Test extracting the files in a section"""
2767 data = self._RunExtractCmd('section')
2768 cbfs_data = data[:0x400]
2769 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002770 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass71ce0ba2019-07-08 14:25:52 -06002771 dtb_data = data[0x400:]
2772 dtb = self._decompress(dtb_data)
2773 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2774
2775 def testExtractCompressed(self):
2776 """Test extracting compressed data"""
2777 data = self._RunExtractCmd('section/u-boot-dtb')
2778 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2779
2780 def testExtractRaw(self):
2781 """Test extracting compressed data without decompressing it"""
2782 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2783 dtb = self._decompress(data)
2784 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2785
2786 def testExtractCbfs(self):
2787 """Test extracting CBFS data"""
2788 data = self._RunExtractCmd('section/cbfs/u-boot')
2789 self.assertEqual(U_BOOT_DATA, data)
2790
2791 def testExtractCbfsCompressed(self):
2792 """Test extracting CBFS compressed data"""
2793 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2794 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2795
2796 def testExtractCbfsRaw(self):
2797 """Test extracting CBFS compressed data without decompressing it"""
2798 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Simon Glasseb0f4a42019-07-20 12:24:06 -06002799 dtb = tools.Decompress(data, 'lzma', with_header=False)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002800 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2801
Simon Glassf667e452019-07-08 14:25:50 -06002802 def testExtractBadEntry(self):
2803 """Test extracting a bad section path"""
2804 with self.assertRaises(ValueError) as e:
2805 self._RunExtractCmd('section/does-not-exist')
2806 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2807 str(e.exception))
2808
2809 def testExtractMissingFile(self):
2810 """Test extracting file that does not exist"""
2811 with self.assertRaises(IOError) as e:
2812 control.ReadEntry('missing-file', 'name')
2813
2814 def testExtractBadFile(self):
2815 """Test extracting an invalid file"""
2816 fname = os.path.join(self._indir, 'badfile')
2817 tools.WriteFile(fname, b'')
2818 with self.assertRaises(ValueError) as e:
2819 control.ReadEntry(fname, 'name')
2820
Simon Glass71ce0ba2019-07-08 14:25:52 -06002821 def testExtractCmd(self):
2822 """Test extracting a file fron an image on the command line"""
2823 self._CheckLz4()
2824 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass71ce0ba2019-07-08 14:25:52 -06002825 fname = os.path.join(self._indir, 'output.extact')
Simon Glassf86a7362019-07-20 12:24:10 -06002826 try:
2827 tmpdir, updated_fname = self._SetupImageInTmpdir()
2828 with test_util.capture_sys_output() as (stdout, stderr):
2829 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2830 '-f', fname)
2831 finally:
2832 shutil.rmtree(tmpdir)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002833 data = tools.ReadFile(fname)
2834 self.assertEqual(U_BOOT_DATA, data)
2835
2836 def testExtractOneEntry(self):
2837 """Test extracting a single entry fron an image """
2838 self._CheckLz4()
2839 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2840 image_fname = tools.GetOutputFilename('image.bin')
2841 fname = os.path.join(self._indir, 'output.extact')
2842 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
2843 data = tools.ReadFile(fname)
2844 self.assertEqual(U_BOOT_DATA, data)
2845
2846 def _CheckExtractOutput(self, decomp):
2847 """Helper to test file output with and without decompression
2848
2849 Args:
2850 decomp: True to decompress entry data, False to output it raw
2851 """
2852 def _CheckPresent(entry_path, expect_data, expect_size=None):
2853 """Check and remove expected file
2854
2855 This checks the data/size of a file and removes the file both from
2856 the outfiles set and from the output directory. Once all files are
2857 processed, both the set and directory should be empty.
2858
2859 Args:
2860 entry_path: Entry path
2861 expect_data: Data to expect in file, or None to skip check
2862 expect_size: Size of data to expect in file, or None to skip
2863 """
2864 path = os.path.join(outdir, entry_path)
2865 data = tools.ReadFile(path)
2866 os.remove(path)
2867 if expect_data:
2868 self.assertEqual(expect_data, data)
2869 elif expect_size:
2870 self.assertEqual(expect_size, len(data))
2871 outfiles.remove(path)
2872
2873 def _CheckDirPresent(name):
2874 """Remove expected directory
2875
2876 This gives an error if the directory does not exist as expected
2877
2878 Args:
2879 name: Name of directory to remove
2880 """
2881 path = os.path.join(outdir, name)
2882 os.rmdir(path)
2883
2884 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2885 image_fname = tools.GetOutputFilename('image.bin')
2886 outdir = os.path.join(self._indir, 'extract')
2887 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2888
2889 # Create a set of all file that were output (should be 9)
2890 outfiles = set()
2891 for root, dirs, files in os.walk(outdir):
2892 outfiles |= set([os.path.join(root, fname) for fname in files])
2893 self.assertEqual(9, len(outfiles))
2894 self.assertEqual(9, len(einfos))
2895
2896 image = control.images['image']
2897 entries = image.GetEntries()
2898
2899 # Check the 9 files in various ways
2900 section = entries['section']
2901 section_entries = section.GetEntries()
2902 cbfs_entries = section_entries['cbfs'].GetEntries()
2903 _CheckPresent('u-boot', U_BOOT_DATA)
2904 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
2905 dtb_len = EXTRACT_DTB_SIZE
2906 if not decomp:
2907 dtb_len = cbfs_entries['u-boot-dtb'].size
2908 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
2909 if not decomp:
2910 dtb_len = section_entries['u-boot-dtb'].size
2911 _CheckPresent('section/u-boot-dtb', None, dtb_len)
2912
2913 fdtmap = entries['fdtmap']
2914 _CheckPresent('fdtmap', fdtmap.data)
2915 hdr = entries['image-header']
2916 _CheckPresent('image-header', hdr.data)
2917
2918 _CheckPresent('section/root', section.data)
2919 cbfs = section_entries['cbfs']
2920 _CheckPresent('section/cbfs/root', cbfs.data)
2921 data = tools.ReadFile(image_fname)
2922 _CheckPresent('root', data)
2923
2924 # There should be no files left. Remove all the directories to check.
2925 # If there are any files/dirs remaining, one of these checks will fail.
2926 self.assertEqual(0, len(outfiles))
2927 _CheckDirPresent('section/cbfs')
2928 _CheckDirPresent('section')
2929 _CheckDirPresent('')
2930 self.assertFalse(os.path.exists(outdir))
2931
2932 def testExtractAllEntries(self):
2933 """Test extracting all entries"""
2934 self._CheckLz4()
2935 self._CheckExtractOutput(decomp=True)
2936
2937 def testExtractAllEntriesRaw(self):
2938 """Test extracting all entries without decompressing them"""
2939 self._CheckLz4()
2940 self._CheckExtractOutput(decomp=False)
2941
2942 def testExtractSelectedEntries(self):
2943 """Test extracting some entries"""
2944 self._CheckLz4()
2945 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2946 image_fname = tools.GetOutputFilename('image.bin')
2947 outdir = os.path.join(self._indir, 'extract')
2948 einfos = control.ExtractEntries(image_fname, None, outdir,
2949 ['*cb*', '*head*'])
2950
2951 # File output is tested by testExtractAllEntries(), so just check that
2952 # the expected entries are selected
2953 names = [einfo.name for einfo in einfos]
2954 self.assertEqual(names,
2955 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2956
2957 def testExtractNoEntryPaths(self):
2958 """Test extracting some entries"""
2959 self._CheckLz4()
2960 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2961 image_fname = tools.GetOutputFilename('image.bin')
2962 with self.assertRaises(ValueError) as e:
2963 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassbb5edc12019-07-20 12:24:14 -06002964 self.assertIn('Must specify an entry path to write with -f',
Simon Glass71ce0ba2019-07-08 14:25:52 -06002965 str(e.exception))
2966
2967 def testExtractTooManyEntryPaths(self):
2968 """Test extracting some entries"""
2969 self._CheckLz4()
2970 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2971 image_fname = tools.GetOutputFilename('image.bin')
2972 with self.assertRaises(ValueError) as e:
2973 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassbb5edc12019-07-20 12:24:14 -06002974 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass71ce0ba2019-07-08 14:25:52 -06002975 str(e.exception))
2976
Simon Glasse2705fa2019-07-08 14:25:53 -06002977 def testPackAlignSection(self):
2978 """Test that sections can have alignment"""
2979 self._DoReadFile('131_pack_align_section.dts')
2980
2981 self.assertIn('image', control.images)
2982 image = control.images['image']
2983 entries = image.GetEntries()
2984 self.assertEqual(3, len(entries))
2985
2986 # First u-boot
2987 self.assertIn('u-boot', entries)
2988 entry = entries['u-boot']
2989 self.assertEqual(0, entry.offset)
2990 self.assertEqual(0, entry.image_pos)
2991 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2992 self.assertEqual(len(U_BOOT_DATA), entry.size)
2993
2994 # Section0
2995 self.assertIn('section0', entries)
2996 section0 = entries['section0']
2997 self.assertEqual(0x10, section0.offset)
2998 self.assertEqual(0x10, section0.image_pos)
2999 self.assertEqual(len(U_BOOT_DATA), section0.size)
3000
3001 # Second u-boot
3002 section_entries = section0.GetEntries()
3003 self.assertIn('u-boot', section_entries)
3004 entry = section_entries['u-boot']
3005 self.assertEqual(0, entry.offset)
3006 self.assertEqual(0x10, entry.image_pos)
3007 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3008 self.assertEqual(len(U_BOOT_DATA), entry.size)
3009
3010 # Section1
3011 self.assertIn('section1', entries)
3012 section1 = entries['section1']
3013 self.assertEqual(0x14, section1.offset)
3014 self.assertEqual(0x14, section1.image_pos)
3015 self.assertEqual(0x20, section1.size)
3016
3017 # Second u-boot
3018 section_entries = section1.GetEntries()
3019 self.assertIn('u-boot', section_entries)
3020 entry = section_entries['u-boot']
3021 self.assertEqual(0, entry.offset)
3022 self.assertEqual(0x14, entry.image_pos)
3023 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3024 self.assertEqual(len(U_BOOT_DATA), entry.size)
3025
3026 # Section2
3027 self.assertIn('section2', section_entries)
3028 section2 = section_entries['section2']
3029 self.assertEqual(0x4, section2.offset)
3030 self.assertEqual(0x18, section2.image_pos)
3031 self.assertEqual(4, section2.size)
3032
3033 # Third u-boot
3034 section_entries = section2.GetEntries()
3035 self.assertIn('u-boot', section_entries)
3036 entry = section_entries['u-boot']
3037 self.assertEqual(0, entry.offset)
3038 self.assertEqual(0x18, entry.image_pos)
3039 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3040 self.assertEqual(len(U_BOOT_DATA), entry.size)
3041
Simon Glass51014aa2019-07-20 12:23:56 -06003042 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3043 dts='132_replace.dts'):
Simon Glass10f9d002019-07-20 12:23:50 -06003044 """Replace an entry in an image
3045
3046 This writes the entry data to update it, then opens the updated file and
3047 returns the value that it now finds there.
3048
3049 Args:
3050 entry_name: Entry name to replace
3051 data: Data to replace it with
3052 decomp: True to compress the data if needed, False if data is
3053 already compressed so should be used as is
Simon Glass51014aa2019-07-20 12:23:56 -06003054 allow_resize: True to allow entries to change size, False to raise
3055 an exception
Simon Glass10f9d002019-07-20 12:23:50 -06003056
3057 Returns:
3058 Tuple:
3059 data from entry
3060 data from fdtmap (excluding header)
Simon Glass51014aa2019-07-20 12:23:56 -06003061 Image object that was modified
Simon Glass10f9d002019-07-20 12:23:50 -06003062 """
Simon Glass51014aa2019-07-20 12:23:56 -06003063 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass10f9d002019-07-20 12:23:50 -06003064 update_dtb=True)[1]
3065
3066 self.assertIn('image', control.images)
3067 image = control.images['image']
3068 entries = image.GetEntries()
3069 orig_dtb_data = entries['u-boot-dtb'].data
3070 orig_fdtmap_data = entries['fdtmap'].data
3071
3072 image_fname = tools.GetOutputFilename('image.bin')
3073 updated_fname = tools.GetOutputFilename('image-updated.bin')
3074 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
Simon Glass51014aa2019-07-20 12:23:56 -06003075 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3076 allow_resize)
Simon Glass10f9d002019-07-20 12:23:50 -06003077 data = control.ReadEntry(updated_fname, entry_name, decomp)
3078
Simon Glass51014aa2019-07-20 12:23:56 -06003079 # The DT data should not change unless resized:
3080 if not allow_resize:
3081 new_dtb_data = entries['u-boot-dtb'].data
3082 self.assertEqual(new_dtb_data, orig_dtb_data)
3083 new_fdtmap_data = entries['fdtmap'].data
3084 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass10f9d002019-07-20 12:23:50 -06003085
Simon Glass51014aa2019-07-20 12:23:56 -06003086 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass10f9d002019-07-20 12:23:50 -06003087
3088 def testReplaceSimple(self):
3089 """Test replacing a single file"""
3090 expected = b'x' * len(U_BOOT_DATA)
Simon Glass51014aa2019-07-20 12:23:56 -06003091 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3092 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06003093 self.assertEqual(expected, data)
3094
3095 # Test that the state looks right. There should be an FDT for the fdtmap
3096 # that we jsut read back in, and it should match what we find in the
3097 # 'control' tables. Checking for an FDT that does not exist should
3098 # return None.
3099 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glass51014aa2019-07-20 12:23:56 -06003100 self.assertIsNotNone(path)
Simon Glass10f9d002019-07-20 12:23:50 -06003101 self.assertEqual(expected_fdtmap, fdtmap)
3102
3103 dtb = state.GetFdtForEtype('fdtmap')
3104 self.assertEqual(dtb.GetContents(), fdtmap)
3105
3106 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3107 self.assertIsNone(missing_path)
3108 self.assertIsNone(missing_fdtmap)
3109
3110 missing_dtb = state.GetFdtForEtype('missing')
3111 self.assertIsNone(missing_dtb)
3112
3113 self.assertEqual('/binman', state.fdt_path_prefix)
3114
3115 def testReplaceResizeFail(self):
3116 """Test replacing a file by something larger"""
3117 expected = U_BOOT_DATA + b'x'
3118 with self.assertRaises(ValueError) as e:
Simon Glass51014aa2019-07-20 12:23:56 -06003119 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3120 dts='139_replace_repack.dts')
Simon Glass10f9d002019-07-20 12:23:50 -06003121 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3122 str(e.exception))
3123
3124 def testReplaceMulti(self):
3125 """Test replacing entry data where multiple images are generated"""
3126 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3127 update_dtb=True)[0]
3128 expected = b'x' * len(U_BOOT_DATA)
3129 updated_fname = tools.GetOutputFilename('image-updated.bin')
3130 tools.WriteFile(updated_fname, data)
3131 entry_name = 'u-boot'
Simon Glass51014aa2019-07-20 12:23:56 -06003132 control.WriteEntry(updated_fname, entry_name, expected,
3133 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06003134 data = control.ReadEntry(updated_fname, entry_name)
3135 self.assertEqual(expected, data)
3136
3137 # Check the state looks right.
3138 self.assertEqual('/binman/image', state.fdt_path_prefix)
3139
3140 # Now check we can write the first image
3141 image_fname = tools.GetOutputFilename('first-image.bin')
3142 updated_fname = tools.GetOutputFilename('first-updated.bin')
3143 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
3144 entry_name = 'u-boot'
Simon Glass51014aa2019-07-20 12:23:56 -06003145 control.WriteEntry(updated_fname, entry_name, expected,
3146 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06003147 data = control.ReadEntry(updated_fname, entry_name)
3148 self.assertEqual(expected, data)
3149
3150 # Check the state looks right.
3151 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass8beb11e2019-07-08 14:25:47 -06003152
Simon Glass12bb1a92019-07-20 12:23:51 -06003153 def testUpdateFdtAllRepack(self):
3154 """Test that all device trees are updated with offset/size info"""
3155 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3156 SECTION_SIZE = 0x300
3157 DTB_SIZE = 602
3158 FDTMAP_SIZE = 608
3159 base_expected = {
3160 'offset': 0,
3161 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3162 'image-pos': 0,
3163 'section:offset': 0,
3164 'section:size': SECTION_SIZE,
3165 'section:image-pos': 0,
3166 'section/u-boot-dtb:offset': 4,
3167 'section/u-boot-dtb:size': 636,
3168 'section/u-boot-dtb:image-pos': 4,
3169 'u-boot-spl-dtb:offset': SECTION_SIZE,
3170 'u-boot-spl-dtb:size': DTB_SIZE,
3171 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3172 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3173 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3174 'u-boot-tpl-dtb:size': DTB_SIZE,
3175 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3176 'fdtmap:size': FDTMAP_SIZE,
3177 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3178 }
3179 main_expected = {
3180 'section:orig-size': SECTION_SIZE,
3181 'section/u-boot-dtb:orig-offset': 4,
3182 }
3183
3184 # We expect three device-tree files in the output, with the first one
3185 # within a fixed-size section.
3186 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3187 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3188 # main U-Boot tree. All three should have the same positions and offset
3189 # except that the main tree should include the main_expected properties
3190 start = 4
3191 for item in ['', 'spl', 'tpl', None]:
3192 if item is None:
3193 start += 16 # Move past fdtmap header
3194 dtb = fdt.Fdt.FromData(data[start:])
3195 dtb.Scan()
3196 props = self._GetPropTree(dtb,
3197 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3198 prefix='/' if item is None else '/binman/')
3199 expected = dict(base_expected)
3200 if item:
3201 expected[item] = 0
3202 else:
3203 # Main DTB and fdtdec should include the 'orig-' properties
3204 expected.update(main_expected)
3205 # Helpful for debugging:
3206 #for prop in sorted(props):
3207 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3208 self.assertEqual(expected, props)
3209 if item == '':
3210 start = SECTION_SIZE
3211 else:
3212 start += dtb._fdt_obj.totalsize()
3213
Simon Glasseba1f0c2019-07-20 12:23:55 -06003214 def testFdtmapHeaderMiddle(self):
3215 """Test an FDT map in the middle of an image when it should be at end"""
3216 with self.assertRaises(ValueError) as e:
3217 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3218 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3219 str(e.exception))
3220
3221 def testFdtmapHeaderStartBad(self):
3222 """Test an FDT map in middle of an image when it should be at start"""
3223 with self.assertRaises(ValueError) as e:
3224 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3225 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3226 str(e.exception))
3227
3228 def testFdtmapHeaderEndBad(self):
3229 """Test an FDT map at the start of an image when it should be at end"""
3230 with self.assertRaises(ValueError) as e:
3231 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3232 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3233 str(e.exception))
3234
3235 def testFdtmapHeaderNoSize(self):
3236 """Test an image header at the end of an image with undefined size"""
3237 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3238
Simon Glass51014aa2019-07-20 12:23:56 -06003239 def testReplaceResize(self):
3240 """Test replacing a single file in an entry with a larger file"""
3241 expected = U_BOOT_DATA + b'x'
3242 data, _, image = self._RunReplaceCmd('u-boot', expected,
3243 dts='139_replace_repack.dts')
3244 self.assertEqual(expected, data)
3245
3246 entries = image.GetEntries()
3247 dtb_data = entries['u-boot-dtb'].data
3248 dtb = fdt.Fdt.FromData(dtb_data)
3249 dtb.Scan()
3250
3251 # The u-boot section should now be larger in the dtb
3252 node = dtb.GetNode('/binman/u-boot')
3253 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3254
3255 # Same for the fdtmap
3256 fdata = entries['fdtmap'].data
3257 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3258 fdtb.Scan()
3259 fnode = fdtb.GetNode('/u-boot')
3260 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3261
3262 def testReplaceResizeNoRepack(self):
3263 """Test replacing an entry with a larger file when not allowed"""
3264 expected = U_BOOT_DATA + b'x'
3265 with self.assertRaises(ValueError) as e:
3266 self._RunReplaceCmd('u-boot', expected)
3267 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3268 str(e.exception))
3269
Simon Glass61ec04f2019-07-20 12:23:58 -06003270 def testEntryShrink(self):
3271 """Test contracting an entry after it is packed"""
3272 try:
3273 state.SetAllowEntryContraction(True)
3274 data = self._DoReadFileDtb('140_entry_shrink.dts',
3275 update_dtb=True)[0]
3276 finally:
3277 state.SetAllowEntryContraction(False)
3278 self.assertEqual(b'a', data[:1])
3279 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3280 self.assertEqual(b'a', data[-1:])
3281
3282 def testEntryShrinkFail(self):
3283 """Test not being allowed to contract an entry after it is packed"""
3284 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3285
3286 # In this case there is a spare byte at the end of the data. The size of
3287 # the contents is only 1 byte but we still have the size before it
3288 # shrunk.
3289 self.assertEqual(b'a\0', data[:2])
3290 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3291 self.assertEqual(b'a\0', data[-2:])
3292
Simon Glass27145fd2019-07-20 12:24:01 -06003293 def testDescriptorOffset(self):
3294 """Test that the Intel descriptor is always placed at at the start"""
3295 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3296 image = control.images['image']
3297 entries = image.GetEntries()
3298 desc = entries['intel-descriptor']
3299 self.assertEqual(0xff800000, desc.offset);
3300 self.assertEqual(0xff800000, desc.image_pos);
3301
Simon Glasseb0f4a42019-07-20 12:24:06 -06003302 def testReplaceCbfs(self):
3303 """Test replacing a single file in CBFS without changing the size"""
3304 self._CheckLz4()
3305 expected = b'x' * len(U_BOOT_DATA)
3306 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3307 updated_fname = tools.GetOutputFilename('image-updated.bin')
3308 tools.WriteFile(updated_fname, data)
3309 entry_name = 'section/cbfs/u-boot'
3310 control.WriteEntry(updated_fname, entry_name, expected,
3311 allow_resize=True)
3312 data = control.ReadEntry(updated_fname, entry_name)
3313 self.assertEqual(expected, data)
3314
3315 def testReplaceResizeCbfs(self):
3316 """Test replacing a single file in CBFS with one of a different size"""
3317 self._CheckLz4()
3318 expected = U_BOOT_DATA + b'x'
3319 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3320 updated_fname = tools.GetOutputFilename('image-updated.bin')
3321 tools.WriteFile(updated_fname, data)
3322 entry_name = 'section/cbfs/u-boot'
3323 control.WriteEntry(updated_fname, entry_name, expected,
3324 allow_resize=True)
3325 data = control.ReadEntry(updated_fname, entry_name)
3326 self.assertEqual(expected, data)
3327
Simon Glassa6cb9952019-07-20 12:24:15 -06003328 def _SetupForReplace(self):
3329 """Set up some files to use to replace entries
3330
3331 This generates an image, copies it to a new file, extracts all the files
3332 in it and updates some of them
3333
3334 Returns:
3335 List
3336 Image filename
3337 Output directory
3338 Expected values for updated entries, each a string
3339 """
3340 data = self._DoReadFileRealDtb('143_replace_all.dts')
3341
3342 updated_fname = tools.GetOutputFilename('image-updated.bin')
3343 tools.WriteFile(updated_fname, data)
3344
3345 outdir = os.path.join(self._indir, 'extract')
3346 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3347
3348 expected1 = b'x' + U_BOOT_DATA + b'y'
3349 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3350 tools.WriteFile(u_boot_fname1, expected1)
3351
3352 expected2 = b'a' + U_BOOT_DATA + b'b'
3353 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
3354 tools.WriteFile(u_boot_fname2, expected2)
3355
3356 expected_text = b'not the same text'
3357 text_fname = os.path.join(outdir, 'text')
3358 tools.WriteFile(text_fname, expected_text)
3359
3360 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3361 dtb = fdt.FdtScan(dtb_fname)
3362 node = dtb.GetNode('/binman/text')
3363 node.AddString('my-property', 'the value')
3364 dtb.Sync(auto_resize=True)
3365 dtb.Flush()
3366
3367 return updated_fname, outdir, expected1, expected2, expected_text
3368
3369 def _CheckReplaceMultiple(self, entry_paths):
3370 """Handle replacing the contents of multiple entries
3371
3372 Args:
3373 entry_paths: List of entry paths to replace
3374
3375 Returns:
3376 List
3377 Dict of entries in the image:
3378 key: Entry name
3379 Value: Entry object
3380 Expected values for updated entries, each a string
3381 """
3382 updated_fname, outdir, expected1, expected2, expected_text = (
3383 self._SetupForReplace())
3384 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3385
3386 image = Image.FromFile(updated_fname)
3387 image.LoadData()
3388 return image.GetEntries(), expected1, expected2, expected_text
3389
3390 def testReplaceAll(self):
3391 """Test replacing the contents of all entries"""
3392 entries, expected1, expected2, expected_text = (
3393 self._CheckReplaceMultiple([]))
3394 data = entries['u-boot'].data
3395 self.assertEqual(expected1, data)
3396
3397 data = entries['u-boot2'].data
3398 self.assertEqual(expected2, data)
3399
3400 data = entries['text'].data
3401 self.assertEqual(expected_text, data)
3402
3403 # Check that the device tree is updated
3404 data = entries['u-boot-dtb'].data
3405 dtb = fdt.Fdt.FromData(data)
3406 dtb.Scan()
3407 node = dtb.GetNode('/binman/text')
3408 self.assertEqual('the value', node.props['my-property'].value)
3409
3410 def testReplaceSome(self):
3411 """Test replacing the contents of a few entries"""
3412 entries, expected1, expected2, expected_text = (
3413 self._CheckReplaceMultiple(['u-boot2', 'text']))
3414
3415 # This one should not change
3416 data = entries['u-boot'].data
3417 self.assertEqual(U_BOOT_DATA, data)
3418
3419 data = entries['u-boot2'].data
3420 self.assertEqual(expected2, data)
3421
3422 data = entries['text'].data
3423 self.assertEqual(expected_text, data)
3424
3425 def testReplaceCmd(self):
3426 """Test replacing a file fron an image on the command line"""
3427 self._DoReadFileRealDtb('143_replace_all.dts')
3428
3429 try:
3430 tmpdir, updated_fname = self._SetupImageInTmpdir()
3431
3432 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3433 expected = b'x' * len(U_BOOT_DATA)
3434 tools.WriteFile(fname, expected)
3435
3436 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
3437 data = tools.ReadFile(updated_fname)
3438 self.assertEqual(expected, data[:len(expected)])
3439 map_fname = os.path.join(tmpdir, 'image-updated.map')
3440 self.assertFalse(os.path.exists(map_fname))
3441 finally:
3442 shutil.rmtree(tmpdir)
3443
3444 def testReplaceCmdSome(self):
3445 """Test replacing some files fron an image on the command line"""
3446 updated_fname, outdir, expected1, expected2, expected_text = (
3447 self._SetupForReplace())
3448
3449 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3450 'u-boot2', 'text')
3451
3452 tools.PrepareOutputDir(None)
3453 image = Image.FromFile(updated_fname)
3454 image.LoadData()
3455 entries = image.GetEntries()
3456
3457 # This one should not change
3458 data = entries['u-boot'].data
3459 self.assertEqual(U_BOOT_DATA, data)
3460
3461 data = entries['u-boot2'].data
3462 self.assertEqual(expected2, data)
3463
3464 data = entries['text'].data
3465 self.assertEqual(expected_text, data)
3466
3467 def testReplaceMissing(self):
3468 """Test replacing entries where the file is missing"""
3469 updated_fname, outdir, expected1, expected2, expected_text = (
3470 self._SetupForReplace())
3471
3472 # Remove one of the files, to generate a warning
3473 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3474 os.remove(u_boot_fname1)
3475
3476 with test_util.capture_sys_output() as (stdout, stderr):
3477 control.ReplaceEntries(updated_fname, None, outdir, [])
3478 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass38fdb4c2020-07-09 18:39:39 -06003479 stderr.getvalue())
Simon Glassa6cb9952019-07-20 12:24:15 -06003480
3481 def testReplaceCmdMap(self):
3482 """Test replacing a file fron an image on the command line"""
3483 self._DoReadFileRealDtb('143_replace_all.dts')
3484
3485 try:
3486 tmpdir, updated_fname = self._SetupImageInTmpdir()
3487
3488 fname = os.path.join(self._indir, 'update-u-boot.bin')
3489 expected = b'x' * len(U_BOOT_DATA)
3490 tools.WriteFile(fname, expected)
3491
3492 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3493 '-f', fname, '-m')
3494 map_fname = os.path.join(tmpdir, 'image-updated.map')
3495 self.assertTrue(os.path.exists(map_fname))
3496 finally:
3497 shutil.rmtree(tmpdir)
3498
3499 def testReplaceNoEntryPaths(self):
3500 """Test replacing an entry without an entry path"""
3501 self._DoReadFileRealDtb('143_replace_all.dts')
3502 image_fname = tools.GetOutputFilename('image.bin')
3503 with self.assertRaises(ValueError) as e:
3504 control.ReplaceEntries(image_fname, 'fname', None, [])
3505 self.assertIn('Must specify an entry path to read with -f',
3506 str(e.exception))
3507
3508 def testReplaceTooManyEntryPaths(self):
3509 """Test extracting some entries"""
3510 self._DoReadFileRealDtb('143_replace_all.dts')
3511 image_fname = tools.GetOutputFilename('image.bin')
3512 with self.assertRaises(ValueError) as e:
3513 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3514 self.assertIn('Must specify exactly one entry path to write with -f',
3515 str(e.exception))
3516
Simon Glass2250ee62019-08-24 07:22:48 -06003517 def testPackReset16(self):
3518 """Test that an image with an x86 reset16 region can be created"""
3519 data = self._DoReadFile('144_x86_reset16.dts')
3520 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3521
3522 def testPackReset16Spl(self):
3523 """Test that an image with an x86 reset16-spl region can be created"""
3524 data = self._DoReadFile('145_x86_reset16_spl.dts')
3525 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3526
3527 def testPackReset16Tpl(self):
3528 """Test that an image with an x86 reset16-tpl region can be created"""
3529 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3530 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3531
Simon Glass5af12072019-08-24 07:22:50 -06003532 def testPackIntelFit(self):
3533 """Test that an image with an Intel FIT and pointer can be created"""
3534 data = self._DoReadFile('147_intel_fit.dts')
3535 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3536 fit = data[16:32];
3537 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3538 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3539
3540 image = control.images['image']
3541 entries = image.GetEntries()
3542 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3543 self.assertEqual(expected_ptr, ptr)
3544
3545 def testPackIntelFitMissing(self):
3546 """Test detection of a FIT pointer with not FIT region"""
3547 with self.assertRaises(ValueError) as e:
3548 self._DoReadFile('148_intel_fit_missing.dts')
3549 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3550 str(e.exception))
3551
Simon Glass7c150132019-11-06 17:22:44 -07003552 def _CheckSymbolsTplSection(self, dts, expected_vals):
3553 data = self._DoReadFile(dts)
3554 sym_values = struct.pack('<LQLL', *expected_vals)
Simon Glass2090f1e2019-08-24 07:23:00 -06003555 upto1 = 4 + len(U_BOOT_SPL_DATA)
Simon Glassb87064c2019-08-24 07:23:05 -06003556 expected1 = tools.GetBytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[20:]
Simon Glass2090f1e2019-08-24 07:23:00 -06003557 self.assertEqual(expected1, data[:upto1])
3558
3559 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Simon Glassb87064c2019-08-24 07:23:05 -06003560 expected2 = tools.GetBytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[20:]
Simon Glass2090f1e2019-08-24 07:23:00 -06003561 self.assertEqual(expected2, data[upto1:upto2])
3562
Simon Glasseb0086f2019-08-24 07:23:04 -06003563 upto3 = 0x34 + len(U_BOOT_DATA)
3564 expected3 = tools.GetBytes(0xff, 1) + U_BOOT_DATA
Simon Glass2090f1e2019-08-24 07:23:00 -06003565 self.assertEqual(expected3, data[upto2:upto3])
3566
Simon Glassb87064c2019-08-24 07:23:05 -06003567 expected4 = sym_values + U_BOOT_TPL_DATA[20:]
Simon Glass7c150132019-11-06 17:22:44 -07003568 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3569
3570 def testSymbolsTplSection(self):
3571 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3572 self._SetupSplElf('u_boot_binman_syms')
3573 self._SetupTplElf('u_boot_binman_syms')
3574 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
3575 [0x04, 0x1c, 0x10 + 0x34, 0x04])
3576
3577 def testSymbolsTplSectionX86(self):
3578 """Test binman can assign symbols in a section with end-at-4gb"""
3579 self._SetupSplElf('u_boot_binman_syms_x86')
3580 self._SetupTplElf('u_boot_binman_syms_x86')
3581 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
3582 [0xffffff04, 0xffffff1c, 0xffffff34,
3583 0x04])
Simon Glass2090f1e2019-08-24 07:23:00 -06003584
Simon Glassbf4d0e22019-08-24 07:23:03 -06003585 def testPackX86RomIfwiSectiom(self):
3586 """Test that a section can be placed in an IFWI region"""
3587 self._SetupIfwi('fitimage.bin')
3588 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3589 self._CheckIfwi(data)
3590
Simon Glassea0fff92019-08-24 07:23:07 -06003591 def testPackFspM(self):
3592 """Test that an image with a FSP memory-init binary can be created"""
3593 data = self._DoReadFile('152_intel_fsp_m.dts')
3594 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3595
Simon Glassbc6a88f2019-10-20 21:31:35 -06003596 def testPackFspS(self):
3597 """Test that an image with a FSP silicon-init binary can be created"""
3598 data = self._DoReadFile('153_intel_fsp_s.dts')
3599 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassea0fff92019-08-24 07:23:07 -06003600
Simon Glass998d1482019-10-20 21:31:36 -06003601 def testPackFspT(self):
3602 """Test that an image with a FSP temp-ram-init binary can be created"""
3603 data = self._DoReadFile('154_intel_fsp_t.dts')
3604 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3605
Simon Glass0dc706f2020-07-09 18:39:31 -06003606 def testMkimage(self):
3607 """Test using mkimage to build an image"""
3608 data = self._DoReadFile('156_mkimage.dts')
3609
3610 # Just check that the data appears in the file somewhere
3611 self.assertIn(U_BOOT_SPL_DATA, data)
3612
Simon Glassce867ad2020-07-09 18:39:36 -06003613 def testExtblob(self):
3614 """Test an image with an external blob"""
3615 data = self._DoReadFile('157_blob_ext.dts')
3616 self.assertEqual(REFCODE_DATA, data)
3617
3618 def testExtblobMissing(self):
3619 """Test an image with a missing external blob"""
3620 with self.assertRaises(ValueError) as e:
3621 self._DoReadFile('158_blob_ext_missing.dts')
3622 self.assertIn("Filename 'missing-file' not found in input path",
3623 str(e.exception))
3624
Simon Glass4f9f1052020-07-09 18:39:38 -06003625 def testExtblobMissingOk(self):
3626 """Test an image with an missing external blob that is allowed"""
Simon Glassb1cca952020-07-09 18:39:40 -06003627 with test_util.capture_sys_output() as (stdout, stderr):
3628 self._DoTestFile('158_blob_ext_missing.dts', allow_missing=True)
3629 err = stderr.getvalue()
3630 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
3631
3632 def testExtblobMissingOkSect(self):
3633 """Test an image with an missing external blob that is allowed"""
3634 with test_util.capture_sys_output() as (stdout, stderr):
3635 self._DoTestFile('159_blob_ext_missing_sect.dts',
3636 allow_missing=True)
3637 err = stderr.getvalue()
3638 self.assertRegex(err, "Image 'main-section'.*missing.*: "
3639 "blob-ext blob-ext2")
Simon Glass4f9f1052020-07-09 18:39:38 -06003640
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003641 def testPackX86RomMeMissingDesc(self):
3642 """Test that an missing Intel descriptor entry is allowed"""
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003643 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass52b10dd2020-07-25 15:11:19 -06003644 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003645 err = stderr.getvalue()
3646 self.assertRegex(err,
3647 "Image 'main-section'.*missing.*: intel-descriptor")
3648
3649 def testPackX86RomMissingIfwi(self):
3650 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3651 self._SetupIfwi('fitimage.bin')
3652 pathname = os.path.join(self._indir, 'fitimage.bin')
3653 os.remove(pathname)
3654 with test_util.capture_sys_output() as (stdout, stderr):
3655 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3656 err = stderr.getvalue()
3657 self.assertRegex(err, "Image 'main-section'.*missing.*: intel-ifwi")
3658
Simon Glassb3295fd2020-07-09 18:39:42 -06003659 def testPackOverlap(self):
3660 """Test that zero-size overlapping regions are ignored"""
3661 self._DoTestFile('160_pack_overlap_zero.dts')
3662
Simon Glassfdc34362020-07-09 18:39:45 -06003663 def testSimpleFit(self):
3664 """Test an image with a FIT inside"""
3665 data = self._DoReadFile('161_fit.dts')
3666 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3667 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3668 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3669
3670 # The data should be inside the FIT
3671 dtb = fdt.Fdt.FromData(fit_data)
3672 dtb.Scan()
3673 fnode = dtb.GetNode('/images/kernel')
3674 self.assertIn('data', fnode.props)
3675
3676 fname = os.path.join(self._indir, 'fit_data.fit')
3677 tools.WriteFile(fname, fit_data)
3678 out = tools.Run('dumpimage', '-l', fname)
3679
3680 # Check a few features to make sure the plumbing works. We don't need
3681 # to test the operation of mkimage or dumpimage here. First convert the
3682 # output into a dict where the keys are the fields printed by dumpimage
3683 # and the values are a list of values for each field
3684 lines = out.splitlines()
3685
3686 # Converts "Compression: gzip compressed" into two groups:
3687 # 'Compression' and 'gzip compressed'
3688 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3689 vals = collections.defaultdict(list)
3690 for line in lines:
3691 mat = re_line.match(line)
3692 vals[mat.group(1)].append(mat.group(2))
3693
3694 self.assertEquals('FIT description: test-desc', lines[0])
3695 self.assertIn('Created:', lines[1])
3696 self.assertIn('Image 0 (kernel)', vals)
3697 self.assertIn('Hash value', vals)
3698 data_sizes = vals.get('Data Size')
3699 self.assertIsNotNone(data_sizes)
3700 self.assertEqual(2, len(data_sizes))
3701 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
3702 self.assertEqual(len(U_BOOT_DATA), int(data_sizes[0].split()[0]))
3703 self.assertEqual(len(U_BOOT_SPL_DTB_DATA), int(data_sizes[1].split()[0]))
3704
3705 def testFitExternal(self):
Simon Glasse9d336d2020-09-01 05:13:55 -06003706 """Test an image with an FIT with external images"""
Simon Glassfdc34362020-07-09 18:39:45 -06003707 data = self._DoReadFile('162_fit_external.dts')
3708 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3709
3710 # The data should be outside the FIT
3711 dtb = fdt.Fdt.FromData(fit_data)
3712 dtb.Scan()
3713 fnode = dtb.GetNode('/images/kernel')
3714 self.assertNotIn('data', fnode.props)
Simon Glass12bb1a92019-07-20 12:23:51 -06003715
Alper Nebi Yasak8001d0b2020-08-31 12:58:18 +03003716 def testSectionIgnoreHashSignature(self):
3717 """Test that sections ignore hash, signature nodes for its data"""
3718 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
3719 expected = (U_BOOT_DATA + U_BOOT_DATA)
3720 self.assertEqual(expected, data)
3721
Alper Nebi Yasak3fdeb142020-08-31 12:58:19 +03003722 def testPadInSections(self):
3723 """Test pad-before, pad-after for entries in sections"""
Simon Glassf90d9062020-10-26 17:40:09 -06003724 data, _, _, out_dtb_fname = self._DoReadFileDtb(
3725 '166_pad_in_sections.dts', update_dtb=True)
Alper Nebi Yasak3fdeb142020-08-31 12:58:19 +03003726 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
3727 U_BOOT_DATA + tools.GetBytes(ord('!'), 6) +
3728 U_BOOT_DATA)
3729 self.assertEqual(expected, data)
3730
Simon Glassf90d9062020-10-26 17:40:09 -06003731 dtb = fdt.Fdt(out_dtb_fname)
3732 dtb.Scan()
3733 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
3734 expected = {
3735 'image-pos': 0,
3736 'offset': 0,
3737 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
3738
3739 'section:image-pos': 0,
3740 'section:offset': 0,
3741 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
3742
3743 'section/before:image-pos': 0,
3744 'section/before:offset': 0,
3745 'section/before:size': len(U_BOOT_DATA),
3746
3747 'section/u-boot:image-pos': 4,
3748 'section/u-boot:offset': 4,
3749 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
3750
3751 'section/after:image-pos': 26,
3752 'section/after:offset': 26,
3753 'section/after:size': len(U_BOOT_DATA),
3754 }
3755 self.assertEqual(expected, props)
3756
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03003757 def testFitImageSubentryAlignment(self):
3758 """Test relative alignability of FIT image subentries"""
3759 entry_args = {
3760 'test-id': TEXT_DATA,
3761 }
3762 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
3763 entry_args=entry_args)
3764 dtb = fdt.Fdt.FromData(data)
3765 dtb.Scan()
3766
3767 node = dtb.GetNode('/images/kernel')
3768 data = dtb.GetProps(node)["data"].bytes
3769 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
3770 expected = (tools.GetBytes(0, 0x20) + U_BOOT_SPL_DATA +
3771 tools.GetBytes(0, align_pad) + U_BOOT_DATA)
3772 self.assertEqual(expected, data)
3773
3774 node = dtb.GetNode('/images/fdt-1')
3775 data = dtb.GetProps(node)["data"].bytes
3776 expected = (U_BOOT_SPL_DTB_DATA + tools.GetBytes(0, 20) +
3777 tools.ToBytes(TEXT_DATA) + tools.GetBytes(0, 30) +
3778 U_BOOT_DTB_DATA)
3779 self.assertEqual(expected, data)
3780
3781 def testFitExtblobMissingOk(self):
3782 """Test a FIT with a missing external blob that is allowed"""
3783 with test_util.capture_sys_output() as (stdout, stderr):
3784 self._DoTestFile('168_fit_missing_blob.dts',
3785 allow_missing=True)
3786 err = stderr.getvalue()
Simon Glassb2381432020-09-06 10:39:09 -06003787 self.assertRegex(err, "Image 'main-section'.*missing.*: atf-bl31")
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03003788
Simon Glass3decfa32020-09-01 05:13:54 -06003789 def testBlobNamedByArgMissing(self):
3790 """Test handling of a missing entry arg"""
3791 with self.assertRaises(ValueError) as e:
3792 self._DoReadFile('068_blob_named_by_arg.dts')
3793 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
3794 str(e.exception))
3795
Simon Glassdc2f81a2020-09-01 05:13:58 -06003796 def testPackBl31(self):
3797 """Test that an image with an ATF BL31 binary can be created"""
3798 data = self._DoReadFile('169_atf_bl31.dts')
3799 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
3800
Samuel Holland18bd4552020-10-21 21:12:15 -05003801 def testPackScp(self):
3802 """Test that an image with an SCP binary can be created"""
3803 data = self._DoReadFile('172_scp.dts')
3804 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
3805
Simon Glass6cf99532020-09-01 05:13:59 -06003806 def testFitFdt(self):
3807 """Test an image with an FIT with multiple FDT images"""
3808 def _CheckFdt(seq, expected_data):
3809 """Check the FDT nodes
3810
3811 Args:
3812 seq: Sequence number to check (0 or 1)
3813 expected_data: Expected contents of 'data' property
3814 """
3815 name = 'fdt-%d' % seq
3816 fnode = dtb.GetNode('/images/%s' % name)
3817 self.assertIsNotNone(fnode)
3818 self.assertEqual({'description','type', 'compression', 'data'},
3819 set(fnode.props.keys()))
3820 self.assertEqual(expected_data, fnode.props['data'].bytes)
3821 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
3822 fnode.props['description'].value)
3823
3824 def _CheckConfig(seq, expected_data):
3825 """Check the configuration nodes
3826
3827 Args:
3828 seq: Sequence number to check (0 or 1)
3829 expected_data: Expected contents of 'data' property
3830 """
3831 cnode = dtb.GetNode('/configurations')
3832 self.assertIn('default', cnode.props)
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003833 self.assertEqual('config-2', cnode.props['default'].value)
Simon Glass6cf99532020-09-01 05:13:59 -06003834
3835 name = 'config-%d' % seq
3836 fnode = dtb.GetNode('/configurations/%s' % name)
3837 self.assertIsNotNone(fnode)
3838 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
3839 set(fnode.props.keys()))
3840 self.assertEqual('conf-test-fdt%d.dtb' % seq,
3841 fnode.props['description'].value)
3842 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
3843
3844 entry_args = {
3845 'of-list': 'test-fdt1 test-fdt2',
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003846 'default-dt': 'test-fdt2',
Simon Glass6cf99532020-09-01 05:13:59 -06003847 }
3848 data = self._DoReadFileDtb(
Bin Mengaa75ce92021-05-10 20:23:32 +08003849 '170_fit_fdt.dts',
Simon Glass6cf99532020-09-01 05:13:59 -06003850 entry_args=entry_args,
3851 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3852 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3853 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3854
3855 dtb = fdt.Fdt.FromData(fit_data)
3856 dtb.Scan()
3857 fnode = dtb.GetNode('/images/kernel')
3858 self.assertIn('data', fnode.props)
3859
3860 # Check all the properties in fdt-1 and fdt-2
3861 _CheckFdt(1, TEST_FDT1_DATA)
3862 _CheckFdt(2, TEST_FDT2_DATA)
3863
3864 # Check configurations
3865 _CheckConfig(1, TEST_FDT1_DATA)
3866 _CheckConfig(2, TEST_FDT2_DATA)
3867
3868 def testFitFdtMissingList(self):
3869 """Test handling of a missing 'of-list' entry arg"""
3870 with self.assertRaises(ValueError) as e:
Bin Mengaa75ce92021-05-10 20:23:32 +08003871 self._DoReadFile('170_fit_fdt.dts')
Simon Glass6cf99532020-09-01 05:13:59 -06003872 self.assertIn("Generator node requires 'of-list' entry argument",
3873 str(e.exception))
3874
3875 def testFitFdtEmptyList(self):
3876 """Test handling of an empty 'of-list' entry arg"""
3877 entry_args = {
3878 'of-list': '',
3879 }
3880 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
3881
3882 def testFitFdtMissingProp(self):
3883 """Test handling of a missing 'fit,fdt-list' property"""
3884 with self.assertRaises(ValueError) as e:
3885 self._DoReadFile('171_fit_fdt_missing_prop.dts')
3886 self.assertIn("Generator node requires 'fit,fdt-list' property",
3887 str(e.exception))
Simon Glassdc2f81a2020-09-01 05:13:58 -06003888
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003889 def testFitFdtEmptyList(self):
3890 """Test handling of an empty 'of-list' entry arg"""
3891 entry_args = {
3892 'of-list': '',
3893 }
Bin Mengaa75ce92021-05-10 20:23:32 +08003894 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003895
3896 def testFitFdtMissing(self):
3897 """Test handling of a missing 'default-dt' entry arg"""
3898 entry_args = {
3899 'of-list': 'test-fdt1 test-fdt2',
3900 }
3901 with self.assertRaises(ValueError) as e:
3902 self._DoReadFileDtb(
Bin Mengaa75ce92021-05-10 20:23:32 +08003903 '170_fit_fdt.dts',
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003904 entry_args=entry_args,
3905 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3906 self.assertIn("Generated 'default' node requires default-dt entry argument",
3907 str(e.exception))
3908
3909 def testFitFdtNotInList(self):
3910 """Test handling of a default-dt that is not in the of-list"""
3911 entry_args = {
3912 'of-list': 'test-fdt1 test-fdt2',
3913 'default-dt': 'test-fdt3',
3914 }
3915 with self.assertRaises(ValueError) as e:
3916 self._DoReadFileDtb(
Bin Mengaa75ce92021-05-10 20:23:32 +08003917 '170_fit_fdt.dts',
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003918 entry_args=entry_args,
3919 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3920 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
3921 str(e.exception))
3922
Simon Glassb2381432020-09-06 10:39:09 -06003923 def testFitExtblobMissingHelp(self):
3924 """Test display of help messages when an external blob is missing"""
3925 control.missing_blob_help = control._ReadMissingBlobHelp()
3926 control.missing_blob_help['wibble'] = 'Wibble test'
3927 control.missing_blob_help['another'] = 'Another test'
3928 with test_util.capture_sys_output() as (stdout, stderr):
3929 self._DoTestFile('168_fit_missing_blob.dts',
3930 allow_missing=True)
3931 err = stderr.getvalue()
3932
3933 # We can get the tag from the name, the type or the missing-msg
3934 # property. Check all three.
3935 self.assertIn('You may need to build ARM Trusted', err)
3936 self.assertIn('Wibble test', err)
3937 self.assertIn('Another test', err)
3938
Simon Glass204aa782020-09-06 10:35:32 -06003939 def testMissingBlob(self):
3940 """Test handling of a blob containing a missing file"""
3941 with self.assertRaises(ValueError) as e:
3942 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
3943 self.assertIn("Filename 'missing' not found in input path",
3944 str(e.exception))
3945
Simon Glassfb91d562020-09-06 10:35:33 -06003946 def testEnvironment(self):
3947 """Test adding a U-Boot environment"""
3948 data = self._DoReadFile('174_env.dts')
3949 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3950 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3951 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3952 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
3953 env)
3954
3955 def testEnvironmentNoSize(self):
3956 """Test that a missing 'size' property is detected"""
3957 with self.assertRaises(ValueError) as e:
Simon Glassa4dfe3e2020-10-26 17:40:00 -06003958 self._DoTestFile('175_env_no_size.dts')
Simon Glassfb91d562020-09-06 10:35:33 -06003959 self.assertIn("'u-boot-env' entry must have a size property",
3960 str(e.exception))
3961
3962 def testEnvironmentTooSmall(self):
3963 """Test handling of an environment that does not fit"""
3964 with self.assertRaises(ValueError) as e:
Simon Glassa4dfe3e2020-10-26 17:40:00 -06003965 self._DoTestFile('176_env_too_small.dts')
Simon Glassfb91d562020-09-06 10:35:33 -06003966
3967 # checksum, start byte, environment with \0 terminator, final \0
3968 need = 4 + 1 + len(ENV_DATA) + 1 + 1
3969 short = need - 0x8
3970 self.assertIn("too small to hold data (need %#x more bytes)" % short,
3971 str(e.exception))
3972
Simon Glassf2c0dd82020-10-26 17:40:01 -06003973 def testSkipAtStart(self):
3974 """Test handling of skip-at-start section"""
3975 data = self._DoReadFile('177_skip_at_start.dts')
3976 self.assertEqual(U_BOOT_DATA, data)
3977
3978 image = control.images['image']
3979 entries = image.GetEntries()
3980 section = entries['section']
3981 self.assertEqual(0, section.offset)
3982 self.assertEqual(len(U_BOOT_DATA), section.size)
3983 self.assertEqual(U_BOOT_DATA, section.GetData())
3984
3985 entry = section.GetEntries()['u-boot']
3986 self.assertEqual(16, entry.offset)
3987 self.assertEqual(len(U_BOOT_DATA), entry.size)
3988 self.assertEqual(U_BOOT_DATA, entry.data)
3989
3990 def testSkipAtStartPad(self):
3991 """Test handling of skip-at-start section with padded entry"""
3992 data = self._DoReadFile('178_skip_at_start_pad.dts')
3993 before = tools.GetBytes(0, 8)
3994 after = tools.GetBytes(0, 4)
3995 all = before + U_BOOT_DATA + after
3996 self.assertEqual(all, data)
3997
3998 image = control.images['image']
3999 entries = image.GetEntries()
4000 section = entries['section']
4001 self.assertEqual(0, section.offset)
4002 self.assertEqual(len(all), section.size)
4003 self.assertEqual(all, section.GetData())
4004
4005 entry = section.GetEntries()['u-boot']
4006 self.assertEqual(16, entry.offset)
4007 self.assertEqual(len(all), entry.size)
4008 self.assertEqual(U_BOOT_DATA, entry.data)
4009
4010 def testSkipAtStartSectionPad(self):
4011 """Test handling of skip-at-start section with padding"""
4012 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
4013 before = tools.GetBytes(0, 8)
4014 after = tools.GetBytes(0, 4)
4015 all = before + U_BOOT_DATA + after
Simon Glassd1d3ad72020-10-26 17:40:13 -06004016 self.assertEqual(all, data)
Simon Glassf2c0dd82020-10-26 17:40:01 -06004017
4018 image = control.images['image']
4019 entries = image.GetEntries()
4020 section = entries['section']
4021 self.assertEqual(0, section.offset)
4022 self.assertEqual(len(all), section.size)
Simon Glass63e7ba62020-10-26 17:40:16 -06004023 self.assertEqual(U_BOOT_DATA, section.data)
Simon Glassd1d3ad72020-10-26 17:40:13 -06004024 self.assertEqual(all, section.GetPaddedData())
Simon Glassf2c0dd82020-10-26 17:40:01 -06004025
4026 entry = section.GetEntries()['u-boot']
4027 self.assertEqual(16, entry.offset)
4028 self.assertEqual(len(U_BOOT_DATA), entry.size)
4029 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassfb91d562020-09-06 10:35:33 -06004030
Simon Glass7d398bb2020-10-26 17:40:14 -06004031 def testSectionPad(self):
4032 """Testing padding with sections"""
4033 data = self._DoReadFile('180_section_pad.dts')
4034 expected = (tools.GetBytes(ord('&'), 3) +
4035 tools.GetBytes(ord('!'), 5) +
4036 U_BOOT_DATA +
4037 tools.GetBytes(ord('!'), 1) +
4038 tools.GetBytes(ord('&'), 2))
4039 self.assertEqual(expected, data)
4040
4041 def testSectionAlign(self):
4042 """Testing alignment with sections"""
4043 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4044 expected = (b'\0' + # fill section
4045 tools.GetBytes(ord('&'), 1) + # padding to section align
4046 b'\0' + # fill section
4047 tools.GetBytes(ord('!'), 3) + # padding to u-boot align
4048 U_BOOT_DATA +
4049 tools.GetBytes(ord('!'), 4) + # padding to u-boot size
4050 tools.GetBytes(ord('!'), 4)) # padding to section size
4051 self.assertEqual(expected, data)
4052
Simon Glass8f5ef892020-10-26 17:40:25 -06004053 def testCompressImage(self):
4054 """Test compression of the entire image"""
4055 self._CheckLz4()
4056 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4057 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4058 dtb = fdt.Fdt(out_dtb_fname)
4059 dtb.Scan()
4060 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4061 'uncomp-size'])
4062 orig = self._decompress(data)
4063 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4064
4065 # Do a sanity check on various fields
4066 image = control.images['image']
4067 entries = image.GetEntries()
4068 self.assertEqual(2, len(entries))
4069
4070 entry = entries['blob']
4071 self.assertEqual(COMPRESS_DATA, entry.data)
4072 self.assertEqual(len(COMPRESS_DATA), entry.size)
4073
4074 entry = entries['u-boot']
4075 self.assertEqual(U_BOOT_DATA, entry.data)
4076 self.assertEqual(len(U_BOOT_DATA), entry.size)
4077
4078 self.assertEqual(len(data), image.size)
4079 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4080 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4081 orig = self._decompress(image.data)
4082 self.assertEqual(orig, image.uncomp_data)
4083
4084 expected = {
4085 'blob:offset': 0,
4086 'blob:size': len(COMPRESS_DATA),
4087 'u-boot:offset': len(COMPRESS_DATA),
4088 'u-boot:size': len(U_BOOT_DATA),
4089 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4090 'offset': 0,
4091 'image-pos': 0,
4092 'size': len(data),
4093 }
4094 self.assertEqual(expected, props)
4095
4096 def testCompressImageLess(self):
4097 """Test compression where compression reduces the image size"""
4098 self._CheckLz4()
4099 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4100 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4101 dtb = fdt.Fdt(out_dtb_fname)
4102 dtb.Scan()
4103 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4104 'uncomp-size'])
4105 orig = self._decompress(data)
4106
4107 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
4108
4109 # Do a sanity check on various fields
4110 image = control.images['image']
4111 entries = image.GetEntries()
4112 self.assertEqual(2, len(entries))
4113
4114 entry = entries['blob']
4115 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4116 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4117
4118 entry = entries['u-boot']
4119 self.assertEqual(U_BOOT_DATA, entry.data)
4120 self.assertEqual(len(U_BOOT_DATA), entry.size)
4121
4122 self.assertEqual(len(data), image.size)
4123 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4124 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4125 image.uncomp_size)
4126 orig = self._decompress(image.data)
4127 self.assertEqual(orig, image.uncomp_data)
4128
4129 expected = {
4130 'blob:offset': 0,
4131 'blob:size': len(COMPRESS_DATA_BIG),
4132 'u-boot:offset': len(COMPRESS_DATA_BIG),
4133 'u-boot:size': len(U_BOOT_DATA),
4134 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4135 'offset': 0,
4136 'image-pos': 0,
4137 'size': len(data),
4138 }
4139 self.assertEqual(expected, props)
4140
4141 def testCompressSectionSize(self):
4142 """Test compression of a section with a fixed size"""
4143 self._CheckLz4()
4144 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4145 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4146 dtb = fdt.Fdt(out_dtb_fname)
4147 dtb.Scan()
4148 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4149 'uncomp-size'])
4150 orig = self._decompress(data)
4151 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4152 expected = {
4153 'section/blob:offset': 0,
4154 'section/blob:size': len(COMPRESS_DATA),
4155 'section/u-boot:offset': len(COMPRESS_DATA),
4156 'section/u-boot:size': len(U_BOOT_DATA),
4157 'section:offset': 0,
4158 'section:image-pos': 0,
4159 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4160 'section:size': 0x30,
4161 'offset': 0,
4162 'image-pos': 0,
4163 'size': 0x30,
4164 }
4165 self.assertEqual(expected, props)
4166
4167 def testCompressSection(self):
4168 """Test compression of a section with no fixed size"""
4169 self._CheckLz4()
4170 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4171 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4172 dtb = fdt.Fdt(out_dtb_fname)
4173 dtb.Scan()
4174 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4175 'uncomp-size'])
4176 orig = self._decompress(data)
4177 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4178 expected = {
4179 'section/blob:offset': 0,
4180 'section/blob:size': len(COMPRESS_DATA),
4181 'section/u-boot:offset': len(COMPRESS_DATA),
4182 'section/u-boot:size': len(U_BOOT_DATA),
4183 'section:offset': 0,
4184 'section:image-pos': 0,
4185 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4186 'section:size': len(data),
4187 'offset': 0,
4188 'image-pos': 0,
4189 'size': len(data),
4190 }
4191 self.assertEqual(expected, props)
4192
4193 def testCompressExtra(self):
4194 """Test compression of a section with no fixed size"""
4195 self._CheckLz4()
4196 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4197 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4198 dtb = fdt.Fdt(out_dtb_fname)
4199 dtb.Scan()
4200 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4201 'uncomp-size'])
4202
4203 base = data[len(U_BOOT_DATA):]
4204 self.assertEquals(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
4205 rest = base[len(U_BOOT_DATA):]
4206
4207 # Check compressed data
4208 section1 = self._decompress(rest)
4209 expect1 = tools.Compress(COMPRESS_DATA + U_BOOT_DATA, 'lz4')
4210 self.assertEquals(expect1, rest[:len(expect1)])
4211 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, section1)
4212 rest1 = rest[len(expect1):]
4213
4214 section2 = self._decompress(rest1)
4215 expect2 = tools.Compress(COMPRESS_DATA + COMPRESS_DATA, 'lz4')
4216 self.assertEquals(expect2, rest1[:len(expect2)])
4217 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA, section2)
4218 rest2 = rest1[len(expect2):]
4219
4220 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4221 len(expect2) + len(U_BOOT_DATA))
4222 #self.assertEquals(expect_size, len(data))
4223
4224 #self.assertEquals(U_BOOT_DATA, rest2)
4225
4226 self.maxDiff = None
4227 expected = {
4228 'u-boot:offset': 0,
4229 'u-boot:image-pos': 0,
4230 'u-boot:size': len(U_BOOT_DATA),
4231
4232 'base:offset': len(U_BOOT_DATA),
4233 'base:image-pos': len(U_BOOT_DATA),
4234 'base:size': len(data) - len(U_BOOT_DATA),
4235 'base/u-boot:offset': 0,
4236 'base/u-boot:image-pos': len(U_BOOT_DATA),
4237 'base/u-boot:size': len(U_BOOT_DATA),
4238 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4239 len(expect2),
4240 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4241 len(expect2),
4242 'base/u-boot2:size': len(U_BOOT_DATA),
4243
4244 'base/section:offset': len(U_BOOT_DATA),
4245 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4246 'base/section:size': len(expect1),
4247 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4248 'base/section/blob:offset': 0,
4249 'base/section/blob:size': len(COMPRESS_DATA),
4250 'base/section/u-boot:offset': len(COMPRESS_DATA),
4251 'base/section/u-boot:size': len(U_BOOT_DATA),
4252
4253 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4254 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4255 'base/section2:size': len(expect2),
4256 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4257 'base/section2/blob:offset': 0,
4258 'base/section2/blob:size': len(COMPRESS_DATA),
4259 'base/section2/blob2:offset': len(COMPRESS_DATA),
4260 'base/section2/blob2:size': len(COMPRESS_DATA),
4261
4262 'offset': 0,
4263 'image-pos': 0,
4264 'size': len(data),
4265 }
4266 self.assertEqual(expected, props)
4267
Simon Glass870a9ea2021-01-06 21:35:15 -07004268 def testSymbolsSubsection(self):
4269 """Test binman can assign symbols from a subsection"""
Simon Glassf5898822021-03-18 20:24:56 +13004270 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x18)
Simon Glass870a9ea2021-01-06 21:35:15 -07004271
Simon Glass939d1062021-01-06 21:35:16 -07004272 def testReadImageEntryArg(self):
4273 """Test reading an image that would need an entry arg to generate"""
4274 entry_args = {
4275 'cros-ec-rw-path': 'ecrw.bin',
4276 }
4277 data = self.data = self._DoReadFileDtb(
4278 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4279 entry_args=entry_args)
4280
4281 image_fname = tools.GetOutputFilename('image.bin')
4282 orig_image = control.images['image']
4283
4284 # This should not generate an error about the missing 'cros-ec-rw-path'
4285 # since we are reading the image from a file. Compare with
4286 # testEntryArgsRequired()
4287 image = Image.FromFile(image_fname)
4288 self.assertEqual(orig_image.GetEntries().keys(),
4289 image.GetEntries().keys())
4290
Simon Glass6eb99322021-01-06 21:35:18 -07004291 def testFilesAlign(self):
4292 """Test alignment with files"""
4293 data = self._DoReadFile('190_files_align.dts')
4294
4295 # The first string is 15 bytes so will align to 16
4296 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4297 self.assertEqual(expect, data)
4298
Simon Glass5c6ba712021-01-06 21:35:19 -07004299 def testReadImageSkip(self):
4300 """Test reading an image and accessing its FDT map"""
4301 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
4302 image_fname = tools.GetOutputFilename('image.bin')
4303 orig_image = control.images['image']
4304 image = Image.FromFile(image_fname)
4305 self.assertEqual(orig_image.GetEntries().keys(),
4306 image.GetEntries().keys())
4307
4308 orig_entry = orig_image.GetEntries()['fdtmap']
4309 entry = image.GetEntries()['fdtmap']
4310 self.assertEqual(orig_entry.offset, entry.offset)
4311 self.assertEqual(orig_entry.size, entry.size)
4312 self.assertEqual(16, entry.image_pos)
4313
4314 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4315
4316 self.assertEquals(U_BOOT_DATA, u_boot.ReadData())
4317
Simon Glass77a64e02021-03-18 20:24:57 +13004318 def testTplNoDtb(self):
4319 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
Simon Glass0fe44dc2021-04-25 08:39:32 +12004320 self._SetupTplElf()
Simon Glass77a64e02021-03-18 20:24:57 +13004321 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4322 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4323 data[:len(U_BOOT_TPL_NODTB_DATA)])
4324
Simon Glassd26efc82021-03-18 20:24:58 +13004325 def testTplBssPad(self):
4326 """Test that we can pad TPL's BSS with zeros"""
4327 # ELF file with a '__bss_size' symbol
4328 self._SetupTplElf()
4329 data = self._DoReadFile('193_tpl_bss_pad.dts')
4330 self.assertEqual(U_BOOT_TPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
4331 data)
4332
4333 def testTplBssPadMissing(self):
4334 """Test that a missing symbol is detected"""
4335 self._SetupTplElf('u_boot_ucode_ptr')
4336 with self.assertRaises(ValueError) as e:
4337 self._DoReadFile('193_tpl_bss_pad.dts')
4338 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4339 str(e.exception))
4340
Simon Glass06684922021-03-18 20:25:07 +13004341 def checkDtbSizes(self, data, pad_len, start):
4342 """Check the size arguments in a dtb embedded in an image
4343
4344 Args:
4345 data: The image data
4346 pad_len: Length of the pad section in the image, in bytes
4347 start: Start offset of the devicetree to examine, within the image
4348
4349 Returns:
4350 Size of the devicetree in bytes
4351 """
4352 dtb_data = data[start:]
4353 dtb = fdt.Fdt.FromData(dtb_data)
4354 fdt_size = dtb.GetFdtObj().totalsize()
4355 dtb.Scan()
4356 props = self._GetPropTree(dtb, 'size')
4357 self.assertEqual({
4358 'size': len(data),
4359 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4360 'u-boot-spl/u-boot-spl-dtb:size': 801,
4361 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4362 'u-boot-spl:size': 860,
4363 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4364 'u-boot/u-boot-dtb:size': 781,
4365 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4366 'u-boot:size': 827,
4367 }, props)
4368 return fdt_size
4369
4370 def testExpanded(self):
4371 """Test that an expanded entry type is selected when needed"""
4372 self._SetupSplElf()
4373 self._SetupTplElf()
4374
4375 # SPL has a devicetree, TPL does not
4376 entry_args = {
4377 'spl-dtb': '1',
4378 'spl-bss-pad': 'y',
4379 'tpl-dtb': '',
4380 }
4381 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4382 entry_args=entry_args)
4383 image = control.images['image']
4384 entries = image.GetEntries()
4385 self.assertEqual(3, len(entries))
4386
4387 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4388 self.assertIn('u-boot', entries)
4389 entry = entries['u-boot']
4390 self.assertEqual('u-boot-expanded', entry.etype)
4391 subent = entry.GetEntries()
4392 self.assertEqual(2, len(subent))
4393 self.assertIn('u-boot-nodtb', subent)
4394 self.assertIn('u-boot-dtb', subent)
4395
4396 # Second, u-boot-spl, which should be expanded into three parts
4397 self.assertIn('u-boot-spl', entries)
4398 entry = entries['u-boot-spl']
4399 self.assertEqual('u-boot-spl-expanded', entry.etype)
4400 subent = entry.GetEntries()
4401 self.assertEqual(3, len(subent))
4402 self.assertIn('u-boot-spl-nodtb', subent)
4403 self.assertIn('u-boot-spl-bss-pad', subent)
4404 self.assertIn('u-boot-spl-dtb', subent)
4405
4406 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4407 # devicetree
4408 self.assertIn('u-boot-tpl', entries)
4409 entry = entries['u-boot-tpl']
4410 self.assertEqual('u-boot-tpl', entry.etype)
4411 self.assertEqual(None, entry.GetEntries())
4412
4413 def testExpandedTpl(self):
4414 """Test that an expanded entry type is selected for TPL when needed"""
4415 self._SetupTplElf()
4416
4417 entry_args = {
4418 'tpl-bss-pad': 'y',
4419 'tpl-dtb': 'y',
4420 }
4421 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4422 entry_args=entry_args)
4423 image = control.images['image']
4424 entries = image.GetEntries()
4425 self.assertEqual(1, len(entries))
4426
4427 # We only have u-boot-tpl, which be expanded
4428 self.assertIn('u-boot-tpl', entries)
4429 entry = entries['u-boot-tpl']
4430 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4431 subent = entry.GetEntries()
4432 self.assertEqual(3, len(subent))
4433 self.assertIn('u-boot-tpl-nodtb', subent)
4434 self.assertIn('u-boot-tpl-bss-pad', subent)
4435 self.assertIn('u-boot-tpl-dtb', subent)
4436
4437 def testExpandedNoPad(self):
4438 """Test an expanded entry without BSS pad enabled"""
4439 self._SetupSplElf()
4440 self._SetupTplElf()
4441
4442 # SPL has a devicetree, TPL does not
4443 entry_args = {
4444 'spl-dtb': 'something',
4445 'spl-bss-pad': 'n',
4446 'tpl-dtb': '',
4447 }
4448 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4449 entry_args=entry_args)
4450 image = control.images['image']
4451 entries = image.GetEntries()
4452
4453 # Just check u-boot-spl, which should be expanded into two parts
4454 self.assertIn('u-boot-spl', entries)
4455 entry = entries['u-boot-spl']
4456 self.assertEqual('u-boot-spl-expanded', entry.etype)
4457 subent = entry.GetEntries()
4458 self.assertEqual(2, len(subent))
4459 self.assertIn('u-boot-spl-nodtb', subent)
4460 self.assertIn('u-boot-spl-dtb', subent)
4461
4462 def testExpandedTplNoPad(self):
4463 """Test that an expanded entry type with padding disabled in TPL"""
4464 self._SetupTplElf()
4465
4466 entry_args = {
4467 'tpl-bss-pad': '',
4468 'tpl-dtb': 'y',
4469 }
4470 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4471 entry_args=entry_args)
4472 image = control.images['image']
4473 entries = image.GetEntries()
4474 self.assertEqual(1, len(entries))
4475
4476 # We only have u-boot-tpl, which be expanded
4477 self.assertIn('u-boot-tpl', entries)
4478 entry = entries['u-boot-tpl']
4479 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4480 subent = entry.GetEntries()
4481 self.assertEqual(2, len(subent))
4482 self.assertIn('u-boot-tpl-nodtb', subent)
4483 self.assertIn('u-boot-tpl-dtb', subent)
4484
4485 def testFdtInclude(self):
4486 """Test that an Fdt is update within all binaries"""
4487 self._SetupSplElf()
4488 self._SetupTplElf()
4489
4490 # SPL has a devicetree, TPL does not
4491 self.maxDiff = None
4492 entry_args = {
4493 'spl-dtb': '1',
4494 'spl-bss-pad': 'y',
4495 'tpl-dtb': '',
4496 }
4497 # Build the image. It includes two separate devicetree binaries, each
4498 # with their own contents, but all contain the binman definition.
4499 data = self._DoReadFileDtb(
4500 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4501 update_dtb=True, entry_args=entry_args)[0]
4502 pad_len = 10
4503
4504 # Check the U-Boot dtb
4505 start = len(U_BOOT_NODTB_DATA)
4506 fdt_size = self.checkDtbSizes(data, pad_len, start)
4507
4508 # Now check SPL
4509 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4510 fdt_size = self.checkDtbSizes(data, pad_len, start)
4511
4512 # TPL has no devicetree
4513 start += fdt_size + len(U_BOOT_TPL_DATA)
4514 self.assertEqual(len(data), start)
Simon Glass7d398bb2020-10-26 17:40:14 -06004515
Simon Glass3d433382021-03-21 18:24:30 +13004516 def testSymbolsExpanded(self):
4517 """Test binman can assign symbols in expanded entries"""
4518 entry_args = {
4519 'spl-dtb': '1',
4520 }
4521 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4522 U_BOOT_SPL_DTB_DATA, 0x38,
4523 entry_args=entry_args, use_expanded=True)
4524
Simon Glass189f2912021-03-21 18:24:31 +13004525 def testCollection(self):
4526 """Test a collection"""
4527 data = self._DoReadFile('198_collection.dts')
4528 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
4529 tools.GetBytes(0xff, 2) + U_BOOT_NODTB_DATA +
4530 tools.GetBytes(0xfe, 3) + U_BOOT_DTB_DATA,
4531 data)
4532
Simon Glass631f7522021-03-21 18:24:32 +13004533 def testCollectionSection(self):
4534 """Test a collection where a section must be built first"""
4535 # Sections never have their contents when GetData() is called, but when
Simon Glassd34bcdd2021-11-23 11:03:47 -07004536 # BuildSectionData() is called with required=True, a section will force
Simon Glass631f7522021-03-21 18:24:32 +13004537 # building the contents, producing an error is anything is still
4538 # missing.
4539 data = self._DoReadFile('199_collection_section.dts')
4540 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
4541 self.assertEqual(section + U_BOOT_DATA + tools.GetBytes(0xff, 2) +
4542 section + tools.GetBytes(0xfe, 3) + U_BOOT_DATA,
4543 data)
4544
Simon Glass5ff9fed2021-03-21 18:24:33 +13004545 def testAlignDefault(self):
4546 """Test that default alignment works on sections"""
4547 data = self._DoReadFile('200_align_default.dts')
4548 expected = (U_BOOT_DATA + tools.GetBytes(0, 8 - len(U_BOOT_DATA)) +
4549 U_BOOT_DATA)
4550 # Special alignment for section
4551 expected += tools.GetBytes(0, 32 - len(expected))
4552 # No alignment within the nested section
4553 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
4554 # Now the final piece, which should be default-aligned
4555 expected += tools.GetBytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
4556 self.assertEqual(expected, data)
Simon Glass631f7522021-03-21 18:24:32 +13004557
Bin Meng4c4d6072021-05-10 20:23:33 +08004558 def testPackOpenSBI(self):
4559 """Test that an image with an OpenSBI binary can be created"""
4560 data = self._DoReadFile('201_opensbi.dts')
4561 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
4562
Simon Glassc69d19c2021-07-06 10:36:37 -06004563 def testSectionsSingleThread(self):
4564 """Test sections without multithreading"""
4565 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
4566 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
4567 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
4568 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
4569 self.assertEqual(expected, data)
4570
4571 def testThreadTimeout(self):
4572 """Test handling a thread that takes too long"""
4573 with self.assertRaises(ValueError) as e:
4574 self._DoTestFile('202_section_timeout.dts',
4575 test_section_timeout=True)
Simon Glassb2dfe832021-10-18 12:13:15 -06004576 self.assertIn("Timed out obtaining contents", str(e.exception))
Simon Glassc69d19c2021-07-06 10:36:37 -06004577
Simon Glass03ebc202021-07-06 10:36:41 -06004578 def testTiming(self):
4579 """Test output of timing information"""
4580 data = self._DoReadFile('055_sections.dts')
4581 with test_util.capture_sys_output() as (stdout, stderr):
4582 state.TimingShow()
4583 self.assertIn('read:', stdout.getvalue())
4584 self.assertIn('compress:', stdout.getvalue())
4585
Simon Glass0427bed2021-11-03 21:09:18 -06004586 def testUpdateFdtInElf(self):
4587 """Test that we can update the devicetree in an ELF file"""
4588 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4589 outfile = os.path.join(self._indir, 'u-boot.out')
4590 begin_sym = 'dtb_embed_begin'
4591 end_sym = 'dtb_embed_end'
4592 retcode = self._DoTestFile(
4593 '060_fdt_update.dts', update_dtb=True,
4594 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4595 self.assertEqual(0, retcode)
4596
4597 # Check that the output file does in fact contact a dtb with the binman
4598 # definition in the correct place
4599 syms = elf.GetSymbolFileOffset(infile,
4600 ['dtb_embed_begin', 'dtb_embed_end'])
4601 data = tools.ReadFile(outfile)
4602 dtb_data = data[syms['dtb_embed_begin'].offset:
4603 syms['dtb_embed_end'].offset]
4604
4605 dtb = fdt.Fdt.FromData(dtb_data)
4606 dtb.Scan()
4607 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4608 self.assertEqual({
4609 'image-pos': 0,
4610 'offset': 0,
4611 '_testing:offset': 32,
4612 '_testing:size': 2,
4613 '_testing:image-pos': 32,
4614 'section@0/u-boot:offset': 0,
4615 'section@0/u-boot:size': len(U_BOOT_DATA),
4616 'section@0/u-boot:image-pos': 0,
4617 'section@0:offset': 0,
4618 'section@0:size': 16,
4619 'section@0:image-pos': 0,
4620
4621 'section@1/u-boot:offset': 0,
4622 'section@1/u-boot:size': len(U_BOOT_DATA),
4623 'section@1/u-boot:image-pos': 16,
4624 'section@1:offset': 16,
4625 'section@1:size': 16,
4626 'section@1:image-pos': 16,
4627 'size': 40
4628 }, props)
4629
4630 def testUpdateFdtInElfInvalid(self):
4631 """Test that invalid args are detected with --update-fdt-in-elf"""
4632 with self.assertRaises(ValueError) as e:
4633 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
4634 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
4635 str(e.exception))
4636
4637 def testUpdateFdtInElfNoSyms(self):
4638 """Test that missing symbols are detected with --update-fdt-in-elf"""
4639 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4640 outfile = ''
4641 begin_sym = 'wrong_begin'
4642 end_sym = 'wrong_end'
4643 with self.assertRaises(ValueError) as e:
4644 self._DoTestFile(
4645 '060_fdt_update.dts',
4646 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4647 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
4648 str(e.exception))
4649
4650 def testUpdateFdtInElfTooSmall(self):
4651 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
4652 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
4653 outfile = os.path.join(self._indir, 'u-boot.out')
4654 begin_sym = 'dtb_embed_begin'
4655 end_sym = 'dtb_embed_end'
4656 with self.assertRaises(ValueError) as e:
4657 self._DoTestFile(
4658 '060_fdt_update.dts', update_dtb=True,
4659 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4660 self.assertRegex(
4661 str(e.exception),
4662 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
4663
Simon Glassc475dec2021-11-23 11:03:42 -07004664 def testVersion(self):
4665 """Test we can get the binman version"""
4666 version = '(unreleased)'
4667 self.assertEqual(version, state.GetVersion(self._indir))
4668
4669 with self.assertRaises(SystemExit):
4670 with test_util.capture_sys_output() as (_, stderr):
4671 self._DoBinman('-V')
4672 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
4673
4674 # Try running the tool too, just to be safe
4675 result = self._RunBinman('-V')
4676 self.assertEqual('Binman %s\n' % version, result.stderr)
4677
4678 # Set up a version file to make sure that works
4679 version = 'v2025.01-rc2'
4680 tools.WriteFile(os.path.join(self._indir, 'version'), version,
4681 binary=False)
4682 self.assertEqual(version, state.GetVersion(self._indir))
4683
Simon Glass943bf782021-11-23 21:09:50 -07004684 def testAltFormat(self):
4685 """Test that alternative formats can be used to extract"""
4686 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
4687
4688 try:
4689 tmpdir, updated_fname = self._SetupImageInTmpdir()
4690 with test_util.capture_sys_output() as (stdout, _):
4691 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
4692 self.assertEqual(
4693 '''Flag (-F) Entry type Description
4694fdt fdtmap Extract the devicetree blob from the fdtmap
4695''',
4696 stdout.getvalue())
4697
4698 dtb = os.path.join(tmpdir, 'fdt.dtb')
4699 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
4700 dtb, 'fdtmap')
4701
4702 # Check that we can read it and it can be scanning, meaning it does
4703 # not have a 16-byte fdtmap header
4704 data = tools.ReadFile(dtb)
4705 dtb = fdt.Fdt.FromData(data)
4706 dtb.Scan()
4707
4708 # Now check u-boot which has no alt_format
4709 fname = os.path.join(tmpdir, 'fdt.dtb')
4710 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
4711 '-f', fname, 'u-boot')
4712 data = tools.ReadFile(fname)
4713 self.assertEqual(U_BOOT_DATA, data)
4714
4715 finally:
4716 shutil.rmtree(tmpdir)
4717
Simon Glassc69d19c2021-07-06 10:36:37 -06004718
Simon Glass9fc60b42017-11-12 21:52:22 -07004719if __name__ == "__main__":
4720 unittest.main()