blob: 19461c927c3ce17f7741fa61e1cd1e962db33970 [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
Simon Glass56ee85e2022-01-09 20:13:57 -070020import unittest.mock
21import urllib.error
Simon Glass4f443042016-11-25 20:15:52 -070022
Simon Glass386c63c2022-01-09 20:13:50 -070023from binman import bintool
Simon Glass16287932020-04-17 18:09:03 -060024from binman import cbfs_util
25from binman import cmdline
Simon Glassad35ce52022-01-09 20:14:03 -070026from binman import comp_util
Simon Glass16287932020-04-17 18:09:03 -060027from binman import control
28from binman import elf
29from binman import elf_test
Simon Glass75989722021-11-23 21:08:59 -070030from binman import fip_util
Simon Glass16287932020-04-17 18:09:03 -060031from binman import fmap_util
Simon Glass16287932020-04-17 18:09:03 -060032from binman import state
33from dtoc import fdt
34from dtoc import fdt_util
35from binman.etype import fdtmap
36from binman.etype import image_header
Simon Glass07237982020-08-05 13:27:47 -060037from binman.image import Image
Simon Glassbf776672020-04-17 18:09:04 -060038from patman import command
39from patman import test_util
40from patman import tools
41from patman import tout
Simon Glass4f443042016-11-25 20:15:52 -070042
43# Contents of test files, corresponding to different entry types
Simon Glassc6c10e72019-05-17 22:00:46 -060044U_BOOT_DATA = b'1234'
45U_BOOT_IMG_DATA = b'img'
Simon Glasseb0086f2019-08-24 07:23:04 -060046U_BOOT_SPL_DATA = b'56780123456789abcdefghi'
47U_BOOT_TPL_DATA = b'tpl9876543210fedcbazyw'
Simon Glassc6c10e72019-05-17 22:00:46 -060048BLOB_DATA = b'89'
49ME_DATA = b'0abcd'
50VGA_DATA = b'vga'
51U_BOOT_DTB_DATA = b'udtb'
52U_BOOT_SPL_DTB_DATA = b'spldtb'
53U_BOOT_TPL_DTB_DATA = b'tpldtb'
54X86_START16_DATA = b'start16'
55X86_START16_SPL_DATA = b'start16spl'
56X86_START16_TPL_DATA = b'start16tpl'
Simon Glass2250ee62019-08-24 07:22:48 -060057X86_RESET16_DATA = b'reset16'
58X86_RESET16_SPL_DATA = b'reset16spl'
59X86_RESET16_TPL_DATA = b'reset16tpl'
Simon Glassc6c10e72019-05-17 22:00:46 -060060PPC_MPC85XX_BR_DATA = b'ppcmpc85xxbr'
61U_BOOT_NODTB_DATA = b'nodtb with microcode pointer somewhere in here'
62U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here'
63U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here'
64FSP_DATA = b'fsp'
65CMC_DATA = b'cmc'
66VBT_DATA = b'vbt'
67MRC_DATA = b'mrc'
Simon Glassbb748372018-07-17 13:25:33 -060068TEXT_DATA = 'text'
69TEXT_DATA2 = 'text2'
70TEXT_DATA3 = 'text3'
Simon Glassc6c10e72019-05-17 22:00:46 -060071CROS_EC_RW_DATA = b'ecrw'
72GBB_DATA = b'gbbd'
73BMPBLK_DATA = b'bmp'
74VBLOCK_DATA = b'vblk'
75FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
76 b"sorry you're alive\n")
Simon Glassff5c7e32019-07-08 13:18:42 -060077COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
Simon Glass8f5ef892020-10-26 17:40:25 -060078COMPRESS_DATA_BIG = COMPRESS_DATA * 2
Simon Glassc6c10e72019-05-17 22:00:46 -060079REFCODE_DATA = b'refcode'
Simon Glassea0fff92019-08-24 07:23:07 -060080FSP_M_DATA = b'fsp_m'
Simon Glassbc6a88f2019-10-20 21:31:35 -060081FSP_S_DATA = b'fsp_s'
Simon Glass998d1482019-10-20 21:31:36 -060082FSP_T_DATA = b'fsp_t'
Simon Glassdc2f81a2020-09-01 05:13:58 -060083ATF_BL31_DATA = b'bl31'
Simon Glass75989722021-11-23 21:08:59 -070084ATF_BL2U_DATA = b'bl2u'
Bin Meng4c4d6072021-05-10 20:23:33 +080085OPENSBI_DATA = b'opensbi'
Samuel Holland18bd4552020-10-21 21:12:15 -050086SCP_DATA = b'scp'
Simon Glass6cf99532020-09-01 05:13:59 -060087TEST_FDT1_DATA = b'fdt1'
88TEST_FDT2_DATA = b'test-fdt2'
Simon Glassfb91d562020-09-06 10:35:33 -060089ENV_DATA = b'var1=1\nvar2="2"'
Simon Glass6cf99532020-09-01 05:13:59 -060090
91# Subdirectory of the input dir to use to put test FDTs
92TEST_FDT_SUBDIR = 'fdts'
Simon Glassec127af2018-07-17 13:25:39 -060093
Simon Glass6ccbfcd2019-07-20 12:23:47 -060094# The expected size for the device tree in some tests
Simon Glassf667e452019-07-08 14:25:50 -060095EXTRACT_DTB_SIZE = 0x3c9
96
Simon Glass6ccbfcd2019-07-20 12:23:47 -060097# Properties expected to be in the device tree when update_dtb is used
98BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
99
Simon Glass12bb1a92019-07-20 12:23:51 -0600100# Extra properties expected to be in the device tree when allow-repack is used
101REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
102
Simon Glass4f443042016-11-25 20:15:52 -0700103
104class TestFunctional(unittest.TestCase):
105 """Functional tests for binman
106
107 Most of these use a sample .dts file to build an image and then check
108 that it looks correct. The sample files are in the test/ subdirectory
109 and are numbered.
110
111 For each entry type a very small test file is created using fixed
112 string contents. This makes it easy to test that things look right, and
113 debug problems.
114
115 In some cases a 'real' file must be used - these are also supplied in
116 the test/ diurectory.
117 """
118 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600119 def setUpClass(cls):
Simon Glass4d5994f2017-11-12 21:52:20 -0700120 global entry
Simon Glass16287932020-04-17 18:09:03 -0600121 from binman import entry
Simon Glass4d5994f2017-11-12 21:52:20 -0700122
Simon Glass4f443042016-11-25 20:15:52 -0700123 # Handle the case where argv[0] is 'python'
Simon Glassb986b3b2019-08-24 07:22:43 -0600124 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
125 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
Simon Glass4f443042016-11-25 20:15:52 -0700126
127 # Create a temporary directory for input files
Simon Glassb986b3b2019-08-24 07:22:43 -0600128 cls._indir = tempfile.mkdtemp(prefix='binmant.')
Simon Glass4f443042016-11-25 20:15:52 -0700129
130 # Create some test files
131 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
132 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
133 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glassb8ef5b62018-07-17 13:25:48 -0600134 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700135 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -0700136 TestFunctional._MakeInputFile('me.bin', ME_DATA)
137 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glassb986b3b2019-08-24 07:22:43 -0600138 cls._ResetDtbs()
Simon Glass2250ee62019-08-24 07:22:48 -0600139
Jagdish Gediya9d368f32018-09-03 21:35:08 +0530140 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glass2250ee62019-08-24 07:22:48 -0600141
Simon Glass5e239182019-08-24 07:22:49 -0600142 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
143 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
Simon Glass87722132017-11-12 21:52:26 -0700144 X86_START16_SPL_DATA)
Simon Glass5e239182019-08-24 07:22:49 -0600145 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
Simon Glass35b384c2018-09-14 04:57:10 -0600146 X86_START16_TPL_DATA)
Simon Glass2250ee62019-08-24 07:22:48 -0600147
148 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
149 X86_RESET16_DATA)
150 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
151 X86_RESET16_SPL_DATA)
152 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
153 X86_RESET16_TPL_DATA)
154
Simon Glass4f443042016-11-25 20:15:52 -0700155 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass6b187df2017-11-12 21:52:27 -0700156 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
157 U_BOOT_SPL_NODTB_DATA)
Simon Glassf0253632018-09-14 04:57:32 -0600158 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
159 U_BOOT_TPL_NODTB_DATA)
Simon Glassda229092016-11-25 20:15:56 -0700160 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
161 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Meng59ea8c22017-08-15 22:41:54 -0700162 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassca4f4ff2017-11-12 21:52:28 -0700163 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassec127af2018-07-17 13:25:39 -0600164 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glass0ef87aa2018-07-17 13:25:44 -0600165 TestFunctional._MakeInputDir('devkeys')
166 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass3ae192c2018-10-01 12:22:31 -0600167 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glassea0fff92019-08-24 07:23:07 -0600168 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
Simon Glassbc6a88f2019-10-20 21:31:35 -0600169 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
Simon Glass998d1482019-10-20 21:31:36 -0600170 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700171
Simon Glass53e22bf2019-08-24 07:22:53 -0600172 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
173 elf_test.BuildElfTestFiles(cls._elf_testdir)
174
Simon Glasse0ff8552016-11-25 20:15:53 -0700175 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glassf514d8f2019-08-24 07:22:54 -0600176 TestFunctional._MakeInputFile('u-boot',
177 tools.ReadFile(cls.ElfTestFile('u_boot_ucode_ptr')))
Simon Glasse0ff8552016-11-25 20:15:53 -0700178
179 # Intel flash descriptor file
Simon Glass0ba4b3d2020-07-09 18:39:41 -0600180 cls._SetupDescriptor()
Simon Glasse0ff8552016-11-25 20:15:53 -0700181
Simon Glassb986b3b2019-08-24 07:22:43 -0600182 shutil.copytree(cls.TestFile('files'),
183 os.path.join(cls._indir, 'files'))
Simon Glass0a98b282018-09-14 04:57:28 -0600184
Simon Glass83d73c22018-09-14 04:57:26 -0600185 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
Simon Glass8f5ef892020-10-26 17:40:25 -0600186 TestFunctional._MakeInputFile('compress_big', COMPRESS_DATA_BIG)
Simon Glassdc2f81a2020-09-01 05:13:58 -0600187 TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
Simon Glass75989722021-11-23 21:08:59 -0700188 TestFunctional._MakeInputFile('bl2u.bin', ATF_BL2U_DATA)
Bin Meng4c4d6072021-05-10 20:23:33 +0800189 TestFunctional._MakeInputFile('fw_dynamic.bin', OPENSBI_DATA)
Samuel Holland18bd4552020-10-21 21:12:15 -0500190 TestFunctional._MakeInputFile('scp.bin', SCP_DATA)
Simon Glass83d73c22018-09-14 04:57:26 -0600191
Simon Glass6cf99532020-09-01 05:13:59 -0600192 # Add a few .dtb files for testing
193 TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR,
194 TEST_FDT1_DATA)
195 TestFunctional._MakeInputFile('%s/test-fdt2.dtb' % TEST_FDT_SUBDIR,
196 TEST_FDT2_DATA)
197
Simon Glassfb91d562020-09-06 10:35:33 -0600198 TestFunctional._MakeInputFile('env.txt', ENV_DATA)
199
Simon Glass33ce3512022-01-09 20:14:06 -0700200 cls.have_lz4 = comp_util.HAVE_LZ4
Simon Glassac62fba2019-07-08 13:18:53 -0600201
Simon Glass4f443042016-11-25 20:15:52 -0700202 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600203 def tearDownClass(cls):
Simon Glass4f443042016-11-25 20:15:52 -0700204 """Remove the temporary input directory and its contents"""
Simon Glassb986b3b2019-08-24 07:22:43 -0600205 if cls.preserve_indir:
206 print('Preserving input dir: %s' % cls._indir)
Simon Glassd5164a72019-07-08 13:18:49 -0600207 else:
Simon Glassb986b3b2019-08-24 07:22:43 -0600208 if cls._indir:
209 shutil.rmtree(cls._indir)
210 cls._indir = None
Simon Glass4f443042016-11-25 20:15:52 -0700211
Simon Glassd5164a72019-07-08 13:18:49 -0600212 @classmethod
Simon Glass8acce602019-07-08 13:18:50 -0600213 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
Simon Glass53cd5d92019-07-08 14:25:29 -0600214 toolpath=None, verbosity=None):
Simon Glassd5164a72019-07-08 13:18:49 -0600215 """Accept arguments controlling test execution
216
217 Args:
218 preserve_indir: Preserve the shared input directory used by all
219 tests in this class.
220 preserve_outdir: Preserve the output directories used by tests. Each
221 test has its own, so this is normally only useful when running a
222 single test.
Simon Glass8acce602019-07-08 13:18:50 -0600223 toolpath: ist of paths to use for tools
Simon Glassd5164a72019-07-08 13:18:49 -0600224 """
225 cls.preserve_indir = preserve_indir
226 cls.preserve_outdirs = preserve_outdirs
Simon Glass8acce602019-07-08 13:18:50 -0600227 cls.toolpath = toolpath
Simon Glass53cd5d92019-07-08 14:25:29 -0600228 cls.verbosity = verbosity
Simon Glassd5164a72019-07-08 13:18:49 -0600229
Simon Glassac62fba2019-07-08 13:18:53 -0600230 def _CheckLz4(self):
231 if not self.have_lz4:
232 self.skipTest('lz4 --no-frame-crc not available')
233
Simon Glassbf574f12019-07-20 12:24:09 -0600234 def _CleanupOutputDir(self):
235 """Remove the temporary output directory"""
236 if self.preserve_outdirs:
237 print('Preserving output dir: %s' % tools.outdir)
238 else:
239 tools._FinaliseForTest()
240
Simon Glass4f443042016-11-25 20:15:52 -0700241 def setUp(self):
242 # Enable this to turn on debugging output
243 # tout.Init(tout.DEBUG)
244 command.test_result = None
245
246 def tearDown(self):
247 """Remove the temporary output directory"""
Simon Glassbf574f12019-07-20 12:24:09 -0600248 self._CleanupOutputDir()
Simon Glass4f443042016-11-25 20:15:52 -0700249
Simon Glassf86a7362019-07-20 12:24:10 -0600250 def _SetupImageInTmpdir(self):
251 """Set up the output image in a new temporary directory
252
253 This is used when an image has been generated in the output directory,
254 but we want to run binman again. This will create a new output
255 directory and fail to delete the original one.
256
257 This creates a new temporary directory, copies the image to it (with a
258 new name) and removes the old output directory.
259
260 Returns:
261 Tuple:
262 Temporary directory to use
263 New image filename
264 """
265 image_fname = tools.GetOutputFilename('image.bin')
266 tmpdir = tempfile.mkdtemp(prefix='binman.')
267 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
268 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
269 self._CleanupOutputDir()
270 return tmpdir, updated_fname
271
Simon Glassb8ef5b62018-07-17 13:25:48 -0600272 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600273 def _ResetDtbs(cls):
Simon Glassb8ef5b62018-07-17 13:25:48 -0600274 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
275 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
276 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
277
Simon Glass4f443042016-11-25 20:15:52 -0700278 def _RunBinman(self, *args, **kwargs):
279 """Run binman using the command line
280
281 Args:
282 Arguments to pass, as a list of strings
283 kwargs: Arguments to pass to Command.RunPipe()
284 """
285 result = command.RunPipe([[self._binman_pathname] + list(args)],
286 capture=True, capture_stderr=True, raise_on_error=False)
287 if result.return_code and kwargs.get('raise_on_error', True):
288 raise Exception("Error running '%s': %s" % (' '.join(args),
289 result.stdout + result.stderr))
290 return result
291
Simon Glass53cd5d92019-07-08 14:25:29 -0600292 def _DoBinman(self, *argv):
Simon Glass4f443042016-11-25 20:15:52 -0700293 """Run binman using directly (in the same process)
294
295 Args:
296 Arguments to pass, as a list of strings
297 Returns:
298 Return value (0 for success)
299 """
Simon Glass53cd5d92019-07-08 14:25:29 -0600300 argv = list(argv)
301 args = cmdline.ParseArgs(argv)
302 args.pager = 'binman-invalid-pager'
303 args.build_dir = self._indir
Simon Glass4f443042016-11-25 20:15:52 -0700304
305 # For testing, you can force an increase in verbosity here
Simon Glass53cd5d92019-07-08 14:25:29 -0600306 # args.verbosity = tout.DEBUG
307 return control.Binman(args)
Simon Glass4f443042016-11-25 20:15:52 -0700308
Simon Glass53af22a2018-07-17 13:25:32 -0600309 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glasseb833d82019-04-25 21:58:34 -0600310 entry_args=None, images=None, use_real_dtb=False,
Simon Glass63aeaeb2021-03-18 20:25:05 +1300311 use_expanded=False, verbosity=None, allow_missing=False,
Heiko Thierya89c8f22022-01-06 11:49:41 +0100312 allow_fake_blobs=False, extra_indirs=None, threads=None,
Simon Glass0427bed2021-11-03 21:09:18 -0600313 test_section_timeout=False, update_fdt_in_elf=None):
Simon Glass4f443042016-11-25 20:15:52 -0700314 """Run binman with a given test file
315
316 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600317 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600318 debug: True to enable debugging output
Simon Glass3b0c3822018-06-01 09:38:20 -0600319 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600320 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600321 tree before packing it into the image
Simon Glass0bfa7b02018-09-14 04:57:12 -0600322 entry_args: Dict of entry args to supply to binman
323 key: arg name
324 value: value of that arg
325 images: List of image names to build
Simon Glasse9d336d2020-09-01 05:13:55 -0600326 use_real_dtb: True to use the test file as the contents of
327 the u-boot-dtb entry. Normally this is not needed and the
328 test contents (the U_BOOT_DTB_DATA string) can be used.
329 But in some test we need the real contents.
Simon Glass63aeaeb2021-03-18 20:25:05 +1300330 use_expanded: True to use expanded entries where available, e.g.
331 'u-boot-expanded' instead of 'u-boot'
Simon Glasse9d336d2020-09-01 05:13:55 -0600332 verbosity: Verbosity level to use (0-3, None=don't set it)
333 allow_missing: Set the '--allow-missing' flag so that missing
334 external binaries just produce a warning instead of an error
Heiko Thierya89c8f22022-01-06 11:49:41 +0100335 allow_fake_blobs: Set the '--fake-ext-blobs' flag
Simon Glass6cf99532020-09-01 05:13:59 -0600336 extra_indirs: Extra input directories to add using -I
Simon Glassc69d19c2021-07-06 10:36:37 -0600337 threads: Number of threads to use (None for default, 0 for
338 single-threaded)
Simon Glass7115f002021-11-03 21:09:17 -0600339 test_section_timeout: True to force the first time to timeout, as
340 used in testThreadTimeout()
Simon Glass0427bed2021-11-03 21:09:18 -0600341 update_fdt_in_elf: Value to pass with --update-fdt-in-elf=xxx
Simon Glass7115f002021-11-03 21:09:17 -0600342
343 Returns:
344 int return code, 0 on success
Simon Glass4f443042016-11-25 20:15:52 -0700345 """
Simon Glass53cd5d92019-07-08 14:25:29 -0600346 args = []
Simon Glass7fe91732017-11-13 18:55:00 -0700347 if debug:
348 args.append('-D')
Simon Glass53cd5d92019-07-08 14:25:29 -0600349 if verbosity is not None:
350 args.append('-v%d' % verbosity)
351 elif self.verbosity:
352 args.append('-v%d' % self.verbosity)
353 if self.toolpath:
354 for path in self.toolpath:
355 args += ['--toolpath', path]
Simon Glassc69d19c2021-07-06 10:36:37 -0600356 if threads is not None:
357 args.append('-T%d' % threads)
358 if test_section_timeout:
359 args.append('--test-section-timeout')
Simon Glass53cd5d92019-07-08 14:25:29 -0600360 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass3b0c3822018-06-01 09:38:20 -0600361 if map:
362 args.append('-m')
Simon Glass16b8d6b2018-07-06 10:27:42 -0600363 if update_dtb:
Simon Glass2569e102019-07-08 13:18:47 -0600364 args.append('-u')
Simon Glass93d17412018-09-14 04:57:23 -0600365 if not use_real_dtb:
366 args.append('--fake-dtb')
Simon Glass63aeaeb2021-03-18 20:25:05 +1300367 if not use_expanded:
368 args.append('--no-expanded')
Simon Glass53af22a2018-07-17 13:25:32 -0600369 if entry_args:
Simon Glass50979152019-05-14 15:53:41 -0600370 for arg, value in entry_args.items():
Simon Glass53af22a2018-07-17 13:25:32 -0600371 args.append('-a%s=%s' % (arg, value))
Simon Glass4f9f1052020-07-09 18:39:38 -0600372 if allow_missing:
373 args.append('-M')
Heiko Thierya89c8f22022-01-06 11:49:41 +0100374 if allow_fake_blobs:
375 args.append('--fake-ext-blobs')
Simon Glass0427bed2021-11-03 21:09:18 -0600376 if update_fdt_in_elf:
377 args += ['--update-fdt-in-elf', update_fdt_in_elf]
Simon Glass0bfa7b02018-09-14 04:57:12 -0600378 if images:
379 for image in images:
380 args += ['-i', image]
Simon Glass6cf99532020-09-01 05:13:59 -0600381 if extra_indirs:
382 for indir in extra_indirs:
383 args += ['-I', indir]
Simon Glass7fe91732017-11-13 18:55:00 -0700384 return self._DoBinman(*args)
Simon Glass4f443042016-11-25 20:15:52 -0700385
386 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glasse0ff8552016-11-25 20:15:53 -0700387 """Set up a new test device-tree file
388
389 The given file is compiled and set up as the device tree to be used
390 for ths test.
391
392 Args:
393 fname: Filename of .dts file to read
Simon Glass7ae5f312018-06-01 09:38:19 -0600394 outfile: Output filename for compiled device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700395
396 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600397 Contents of device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700398 """
Simon Glassa004f292019-07-20 12:23:49 -0600399 tmpdir = tempfile.mkdtemp(prefix='binmant.')
400 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
Simon Glass1d0ebf72019-05-14 15:53:42 -0600401 with open(dtb, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700402 data = fd.read()
403 TestFunctional._MakeInputFile(outfile, data)
Simon Glassa004f292019-07-20 12:23:49 -0600404 shutil.rmtree(tmpdir)
Simon Glasse0e62752018-10-01 21:12:41 -0600405 return data
Simon Glass4f443042016-11-25 20:15:52 -0700406
Simon Glass6ed45ba2018-09-14 04:57:24 -0600407 def _GetDtbContentsForSplTpl(self, dtb_data, name):
408 """Create a version of the main DTB for SPL or SPL
409
410 For testing we don't actually have different versions of the DTB. With
411 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
412 we don't normally have any unwanted nodes.
413
414 We still want the DTBs for SPL and TPL to be different though, since
415 otherwise it is confusing to know which one we are looking at. So add
416 an 'spl' or 'tpl' property to the top-level node.
Simon Glasse9d336d2020-09-01 05:13:55 -0600417
418 Args:
419 dtb_data: dtb data to modify (this should be a value devicetree)
420 name: Name of a new property to add
421
422 Returns:
423 New dtb data with the property added
Simon Glass6ed45ba2018-09-14 04:57:24 -0600424 """
425 dtb = fdt.Fdt.FromData(dtb_data)
426 dtb.Scan()
427 dtb.GetNode('/binman').AddZeroProp(name)
428 dtb.Sync(auto_resize=True)
429 dtb.Pack()
430 return dtb.GetContents()
431
Simon Glass63aeaeb2021-03-18 20:25:05 +1300432 def _DoReadFileDtb(self, fname, use_real_dtb=False, use_expanded=False,
433 map=False, update_dtb=False, entry_args=None,
Simon Glassc69d19c2021-07-06 10:36:37 -0600434 reset_dtbs=True, extra_indirs=None, threads=None):
Simon Glass4f443042016-11-25 20:15:52 -0700435 """Run binman and return the resulting image
436
437 This runs binman with a given test file and then reads the resulting
438 output file. It is a shortcut function since most tests need to do
439 these steps.
440
441 Raises an assertion failure if binman returns a non-zero exit code.
442
443 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600444 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass4f443042016-11-25 20:15:52 -0700445 use_real_dtb: True to use the test file as the contents of
446 the u-boot-dtb entry. Normally this is not needed and the
447 test contents (the U_BOOT_DTB_DATA string) can be used.
448 But in some test we need the real contents.
Simon Glass63aeaeb2021-03-18 20:25:05 +1300449 use_expanded: True to use expanded entries where available, e.g.
450 'u-boot-expanded' instead of 'u-boot'
Simon Glass3b0c3822018-06-01 09:38:20 -0600451 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600452 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600453 tree before packing it into the image
Simon Glasse9d336d2020-09-01 05:13:55 -0600454 entry_args: Dict of entry args to supply to binman
455 key: arg name
456 value: value of that arg
457 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
458 function. If reset_dtbs is True, then the original test dtb
459 is written back before this function finishes
Simon Glass6cf99532020-09-01 05:13:59 -0600460 extra_indirs: Extra input directories to add using -I
Simon Glassc69d19c2021-07-06 10:36:37 -0600461 threads: Number of threads to use (None for default, 0 for
462 single-threaded)
Simon Glasse0ff8552016-11-25 20:15:53 -0700463
464 Returns:
465 Tuple:
466 Resulting image contents
467 Device tree contents
Simon Glass3b0c3822018-06-01 09:38:20 -0600468 Map data showing contents of image (or None if none)
Simon Glassea6922e2018-07-17 13:25:27 -0600469 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass4f443042016-11-25 20:15:52 -0700470 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700471 dtb_data = None
Simon Glass4f443042016-11-25 20:15:52 -0700472 # Use the compiled test file as the u-boot-dtb input
473 if use_real_dtb:
Simon Glasse0ff8552016-11-25 20:15:53 -0700474 dtb_data = self._SetupDtb(fname)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600475
476 # For testing purposes, make a copy of the DT for SPL and TPL. Add
477 # a node indicating which it is, so aid verification.
478 for name in ['spl', 'tpl']:
479 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
480 outfile = os.path.join(self._indir, dtb_fname)
481 TestFunctional._MakeInputFile(dtb_fname,
482 self._GetDtbContentsForSplTpl(dtb_data, name))
Simon Glass4f443042016-11-25 20:15:52 -0700483
484 try:
Simon Glass53af22a2018-07-17 13:25:32 -0600485 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glass6cf99532020-09-01 05:13:59 -0600486 entry_args=entry_args, use_real_dtb=use_real_dtb,
Simon Glassc69d19c2021-07-06 10:36:37 -0600487 use_expanded=use_expanded, extra_indirs=extra_indirs,
488 threads=threads)
Simon Glass4f443042016-11-25 20:15:52 -0700489 self.assertEqual(0, retcode)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600490 out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
Simon Glass4f443042016-11-25 20:15:52 -0700491
492 # Find the (only) image, read it and return its contents
493 image = control.images['image']
Simon Glass16b8d6b2018-07-06 10:27:42 -0600494 image_fname = tools.GetOutputFilename('image.bin')
495 self.assertTrue(os.path.exists(image_fname))
Simon Glass3b0c3822018-06-01 09:38:20 -0600496 if map:
497 map_fname = tools.GetOutputFilename('image.map')
498 with open(map_fname) as fd:
499 map_data = fd.read()
500 else:
501 map_data = None
Simon Glass1d0ebf72019-05-14 15:53:42 -0600502 with open(image_fname, 'rb') as fd:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600503 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass4f443042016-11-25 20:15:52 -0700504 finally:
505 # Put the test file back
Simon Glass6ed45ba2018-09-14 04:57:24 -0600506 if reset_dtbs and use_real_dtb:
Simon Glassb8ef5b62018-07-17 13:25:48 -0600507 self._ResetDtbs()
Simon Glass4f443042016-11-25 20:15:52 -0700508
Simon Glass3c081312019-07-08 14:25:26 -0600509 def _DoReadFileRealDtb(self, fname):
510 """Run binman with a real .dtb file and return the resulting data
511
512 Args:
513 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
514
515 Returns:
516 Resulting image contents
517 """
518 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
519
Simon Glasse0ff8552016-11-25 20:15:53 -0700520 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass7ae5f312018-06-01 09:38:19 -0600521 """Helper function which discards the device-tree binary
522
523 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600524 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600525 use_real_dtb: True to use the test file as the contents of
526 the u-boot-dtb entry. Normally this is not needed and the
527 test contents (the U_BOOT_DTB_DATA string) can be used.
528 But in some test we need the real contents.
Simon Glassea6922e2018-07-17 13:25:27 -0600529
530 Returns:
531 Resulting image contents
Simon Glass7ae5f312018-06-01 09:38:19 -0600532 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700533 return self._DoReadFileDtb(fname, use_real_dtb)[0]
534
Simon Glass4f443042016-11-25 20:15:52 -0700535 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600536 def _MakeInputFile(cls, fname, contents):
Simon Glass4f443042016-11-25 20:15:52 -0700537 """Create a new test input file, creating directories as needed
538
539 Args:
Simon Glass3ab95982018-08-01 15:22:37 -0600540 fname: Filename to create
Simon Glass4f443042016-11-25 20:15:52 -0700541 contents: File contents to write in to the file
542 Returns:
543 Full pathname of file created
544 """
Simon Glassb986b3b2019-08-24 07:22:43 -0600545 pathname = os.path.join(cls._indir, fname)
Simon Glass4f443042016-11-25 20:15:52 -0700546 dirname = os.path.dirname(pathname)
547 if dirname and not os.path.exists(dirname):
548 os.makedirs(dirname)
549 with open(pathname, 'wb') as fd:
550 fd.write(contents)
551 return pathname
552
553 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600554 def _MakeInputDir(cls, dirname):
Simon Glass0ef87aa2018-07-17 13:25:44 -0600555 """Create a new test input directory, creating directories as needed
556
557 Args:
558 dirname: Directory name to create
559
560 Returns:
561 Full pathname of directory created
562 """
Simon Glassb986b3b2019-08-24 07:22:43 -0600563 pathname = os.path.join(cls._indir, dirname)
Simon Glass0ef87aa2018-07-17 13:25:44 -0600564 if not os.path.exists(pathname):
565 os.makedirs(pathname)
566 return pathname
567
568 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600569 def _SetupSplElf(cls, src_fname='bss_data'):
Simon Glass11ae93e2018-10-01 21:12:47 -0600570 """Set up an ELF file with a '_dt_ucode_base_size' symbol
571
572 Args:
573 Filename of ELF file to use as SPL
574 """
Simon Glassc9a0b272019-08-24 07:22:59 -0600575 TestFunctional._MakeInputFile('spl/u-boot-spl',
576 tools.ReadFile(cls.ElfTestFile(src_fname)))
Simon Glass11ae93e2018-10-01 21:12:47 -0600577
578 @classmethod
Simon Glass2090f1e2019-08-24 07:23:00 -0600579 def _SetupTplElf(cls, src_fname='bss_data'):
580 """Set up an ELF file with a '_dt_ucode_base_size' symbol
581
582 Args:
583 Filename of ELF file to use as TPL
584 """
585 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
586 tools.ReadFile(cls.ElfTestFile(src_fname)))
587
588 @classmethod
Simon Glass0ba4b3d2020-07-09 18:39:41 -0600589 def _SetupDescriptor(cls):
590 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
591 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
592
593 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600594 def TestFile(cls, fname):
595 return os.path.join(cls._binman_dir, 'test', fname)
Simon Glass4f443042016-11-25 20:15:52 -0700596
Simon Glass53e22bf2019-08-24 07:22:53 -0600597 @classmethod
598 def ElfTestFile(cls, fname):
599 return os.path.join(cls._elf_testdir, fname)
600
Simon Glass4f443042016-11-25 20:15:52 -0700601 def AssertInList(self, grep_list, target):
602 """Assert that at least one of a list of things is in a target
603
604 Args:
605 grep_list: List of strings to check
606 target: Target string
607 """
608 for grep in grep_list:
609 if grep in target:
610 return
Simon Glass1fc62de2019-05-17 22:00:50 -0600611 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass4f443042016-11-25 20:15:52 -0700612
613 def CheckNoGaps(self, entries):
614 """Check that all entries fit together without gaps
615
616 Args:
617 entries: List of entries to check
618 """
Simon Glass3ab95982018-08-01 15:22:37 -0600619 offset = 0
Simon Glass4f443042016-11-25 20:15:52 -0700620 for entry in entries.values():
Simon Glass3ab95982018-08-01 15:22:37 -0600621 self.assertEqual(offset, entry.offset)
622 offset += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700623
Simon Glasse0ff8552016-11-25 20:15:53 -0700624 def GetFdtLen(self, dtb):
Simon Glass7ae5f312018-06-01 09:38:19 -0600625 """Get the totalsize field from a device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700626
627 Args:
Simon Glass7ae5f312018-06-01 09:38:19 -0600628 dtb: Device-tree binary contents
Simon Glasse0ff8552016-11-25 20:15:53 -0700629
630 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600631 Total size of device-tree binary, from the header
Simon Glasse0ff8552016-11-25 20:15:53 -0700632 """
633 return struct.unpack('>L', dtb[4:8])[0]
634
Simon Glass086cec92019-07-08 14:25:27 -0600635 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glass16b8d6b2018-07-06 10:27:42 -0600636 def AddNode(node, path):
637 if node.name != '/':
638 path += '/' + node.name
Simon Glass086cec92019-07-08 14:25:27 -0600639 for prop in node.props.values():
640 if prop.name in prop_names:
641 prop_path = path + ':' + prop.name
642 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
643 prop.value)
Simon Glass16b8d6b2018-07-06 10:27:42 -0600644 for subnode in node.subnodes:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600645 AddNode(subnode, path)
646
647 tree = {}
Simon Glass16b8d6b2018-07-06 10:27:42 -0600648 AddNode(dtb.GetRoot(), '')
649 return tree
650
Simon Glass4f443042016-11-25 20:15:52 -0700651 def testRun(self):
652 """Test a basic run with valid args"""
653 result = self._RunBinman('-h')
654
655 def testFullHelp(self):
656 """Test that the full help is displayed with -H"""
657 result = self._RunBinman('-H')
Simon Glass61adb2d2021-03-18 20:25:13 +1300658 help_file = os.path.join(self._binman_dir, 'README.rst')
Tom Rini3759df02018-01-16 15:29:50 -0500659 # Remove possible extraneous strings
660 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
661 gothelp = result.stdout.replace(extra, '')
662 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass4f443042016-11-25 20:15:52 -0700663 self.assertEqual(0, len(result.stderr))
664 self.assertEqual(0, result.return_code)
665
666 def testFullHelpInternal(self):
667 """Test that the full help is displayed with -H"""
668 try:
669 command.test_result = command.CommandResult()
670 result = self._DoBinman('-H')
Simon Glass61adb2d2021-03-18 20:25:13 +1300671 help_file = os.path.join(self._binman_dir, 'README.rst')
Simon Glass4f443042016-11-25 20:15:52 -0700672 finally:
673 command.test_result = None
674
675 def testHelp(self):
676 """Test that the basic help is displayed with -h"""
677 result = self._RunBinman('-h')
678 self.assertTrue(len(result.stdout) > 200)
679 self.assertEqual(0, len(result.stderr))
680 self.assertEqual(0, result.return_code)
681
Simon Glass4f443042016-11-25 20:15:52 -0700682 def testBoard(self):
683 """Test that we can run it with a specific board"""
Simon Glass741f2d62018-10-01 12:22:30 -0600684 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass4f443042016-11-25 20:15:52 -0700685 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glass63aeaeb2021-03-18 20:25:05 +1300686 result = self._DoBinman('build', '-n', '-b', 'sandbox')
Simon Glass4f443042016-11-25 20:15:52 -0700687 self.assertEqual(0, result)
688
689 def testNeedBoard(self):
690 """Test that we get an error when no board ius supplied"""
691 with self.assertRaises(ValueError) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600692 result = self._DoBinman('build')
Simon Glass4f443042016-11-25 20:15:52 -0700693 self.assertIn("Must provide a board to process (use -b <board>)",
694 str(e.exception))
695
696 def testMissingDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600697 """Test that an invalid device-tree file generates an error"""
Simon Glass4f443042016-11-25 20:15:52 -0700698 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600699 self._RunBinman('build', '-d', 'missing_file')
Simon Glass4f443042016-11-25 20:15:52 -0700700 # We get one error from libfdt, and a different one from fdtget.
701 self.AssertInList(["Couldn't open blob from 'missing_file'",
702 'No such file or directory'], str(e.exception))
703
704 def testBrokenDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600705 """Test that an invalid device-tree source file generates an error
Simon Glass4f443042016-11-25 20:15:52 -0700706
707 Since this is a source file it should be compiled and the error
708 will come from the device-tree compiler (dtc).
709 """
710 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600711 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700712 self.assertIn("FATAL ERROR: Unable to parse input tree",
713 str(e.exception))
714
715 def testMissingNode(self):
716 """Test that a device tree without a 'binman' node generates an error"""
717 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600718 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700719 self.assertIn("does not have a 'binman' node", str(e.exception))
720
721 def testEmpty(self):
722 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glass53cd5d92019-07-08 14:25:29 -0600723 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700724 self.assertEqual(0, len(result.stderr))
725 self.assertEqual(0, result.return_code)
726
727 def testInvalidEntry(self):
728 """Test that an invalid entry is flagged"""
729 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600730 result = self._RunBinman('build', '-d',
Simon Glass741f2d62018-10-01 12:22:30 -0600731 self.TestFile('004_invalid_entry.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700732 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
733 "'/binman/not-a-valid-type'", str(e.exception))
734
735 def testSimple(self):
736 """Test a simple binman with a single file"""
Simon Glass741f2d62018-10-01 12:22:30 -0600737 data = self._DoReadFile('005_simple.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700738 self.assertEqual(U_BOOT_DATA, data)
739
Simon Glass7fe91732017-11-13 18:55:00 -0700740 def testSimpleDebug(self):
741 """Test a simple binman run with debugging enabled"""
Simon Glasse2705fa2019-07-08 14:25:53 -0600742 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass7fe91732017-11-13 18:55:00 -0700743
Simon Glass4f443042016-11-25 20:15:52 -0700744 def testDual(self):
745 """Test that we can handle creating two images
746
747 This also tests image padding.
748 """
Simon Glass741f2d62018-10-01 12:22:30 -0600749 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700750 self.assertEqual(0, retcode)
751
752 image = control.images['image1']
Simon Glass8beb11e2019-07-08 14:25:47 -0600753 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700754 fname = tools.GetOutputFilename('image1.bin')
755 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600756 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700757 data = fd.read()
758 self.assertEqual(U_BOOT_DATA, data)
759
760 image = control.images['image2']
Simon Glass8beb11e2019-07-08 14:25:47 -0600761 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700762 fname = tools.GetOutputFilename('image2.bin')
763 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600764 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700765 data = fd.read()
766 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glasse6d85ff2019-05-14 15:53:47 -0600767 self.assertEqual(tools.GetBytes(0, 3), data[:3])
768 self.assertEqual(tools.GetBytes(0, 5), data[7:])
Simon Glass4f443042016-11-25 20:15:52 -0700769
770 def testBadAlign(self):
771 """Test that an invalid alignment value is detected"""
772 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600773 self._DoTestFile('007_bad_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700774 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
775 "of two", str(e.exception))
776
777 def testPackSimple(self):
778 """Test that packing works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600779 retcode = self._DoTestFile('008_pack.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700780 self.assertEqual(0, retcode)
781 self.assertIn('image', control.images)
782 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600783 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700784 self.assertEqual(5, len(entries))
785
786 # First u-boot
787 self.assertIn('u-boot', entries)
788 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600789 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700790 self.assertEqual(len(U_BOOT_DATA), entry.size)
791
792 # Second u-boot, aligned to 16-byte boundary
793 self.assertIn('u-boot-align', entries)
794 entry = entries['u-boot-align']
Simon Glass3ab95982018-08-01 15:22:37 -0600795 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700796 self.assertEqual(len(U_BOOT_DATA), entry.size)
797
798 # Third u-boot, size 23 bytes
799 self.assertIn('u-boot-size', entries)
800 entry = entries['u-boot-size']
Simon Glass3ab95982018-08-01 15:22:37 -0600801 self.assertEqual(20, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700802 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
803 self.assertEqual(23, entry.size)
804
805 # Fourth u-boot, placed immediate after the above
806 self.assertIn('u-boot-next', entries)
807 entry = entries['u-boot-next']
Simon Glass3ab95982018-08-01 15:22:37 -0600808 self.assertEqual(43, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700809 self.assertEqual(len(U_BOOT_DATA), entry.size)
810
Simon Glass3ab95982018-08-01 15:22:37 -0600811 # Fifth u-boot, placed at a fixed offset
Simon Glass4f443042016-11-25 20:15:52 -0700812 self.assertIn('u-boot-fixed', entries)
813 entry = entries['u-boot-fixed']
Simon Glass3ab95982018-08-01 15:22:37 -0600814 self.assertEqual(61, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700815 self.assertEqual(len(U_BOOT_DATA), entry.size)
816
Simon Glass8beb11e2019-07-08 14:25:47 -0600817 self.assertEqual(65, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700818
819 def testPackExtra(self):
820 """Test that extra packing feature works as expected"""
Simon Glass4eec34c2020-10-26 17:40:10 -0600821 data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
822 update_dtb=True)
Simon Glass4f443042016-11-25 20:15:52 -0700823
Simon Glass4f443042016-11-25 20:15:52 -0700824 self.assertIn('image', control.images)
825 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600826 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700827 self.assertEqual(5, len(entries))
828
829 # First u-boot with padding before and after
830 self.assertIn('u-boot', entries)
831 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600832 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700833 self.assertEqual(3, entry.pad_before)
834 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600835 self.assertEqual(U_BOOT_DATA, entry.data)
836 self.assertEqual(tools.GetBytes(0, 3) + U_BOOT_DATA +
837 tools.GetBytes(0, 5), data[:entry.size])
838 pos = entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700839
840 # Second u-boot has an aligned size, but it has no effect
841 self.assertIn('u-boot-align-size-nop', entries)
842 entry = entries['u-boot-align-size-nop']
Simon Glassef439ed2020-10-26 17:40:08 -0600843 self.assertEqual(pos, entry.offset)
844 self.assertEqual(len(U_BOOT_DATA), entry.size)
845 self.assertEqual(U_BOOT_DATA, entry.data)
846 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
847 pos += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700848
849 # Third u-boot has an aligned size too
850 self.assertIn('u-boot-align-size', entries)
851 entry = entries['u-boot-align-size']
Simon Glassef439ed2020-10-26 17:40:08 -0600852 self.assertEqual(pos, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700853 self.assertEqual(32, entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600854 self.assertEqual(U_BOOT_DATA, entry.data)
855 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 32 - len(U_BOOT_DATA)),
856 data[pos:pos + entry.size])
857 pos += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700858
859 # Fourth u-boot has an aligned end
860 self.assertIn('u-boot-align-end', entries)
861 entry = entries['u-boot-align-end']
Simon Glass3ab95982018-08-01 15:22:37 -0600862 self.assertEqual(48, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700863 self.assertEqual(16, entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600864 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
865 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 16 - len(U_BOOT_DATA)),
866 data[pos:pos + entry.size])
867 pos += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700868
869 # Fifth u-boot immediately afterwards
870 self.assertIn('u-boot-align-both', entries)
871 entry = entries['u-boot-align-both']
Simon Glass3ab95982018-08-01 15:22:37 -0600872 self.assertEqual(64, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700873 self.assertEqual(64, entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600874 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
875 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 64 - len(U_BOOT_DATA)),
876 data[pos:pos + entry.size])
Simon Glass4f443042016-11-25 20:15:52 -0700877
878 self.CheckNoGaps(entries)
Simon Glass8beb11e2019-07-08 14:25:47 -0600879 self.assertEqual(128, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700880
Simon Glass4eec34c2020-10-26 17:40:10 -0600881 dtb = fdt.Fdt(out_dtb_fname)
882 dtb.Scan()
883 props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
884 expected = {
885 'image-pos': 0,
886 'offset': 0,
887 'size': 128,
888
889 'u-boot:image-pos': 0,
890 'u-boot:offset': 0,
891 'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
892
893 'u-boot-align-size-nop:image-pos': 12,
894 'u-boot-align-size-nop:offset': 12,
895 'u-boot-align-size-nop:size': 4,
896
897 'u-boot-align-size:image-pos': 16,
898 'u-boot-align-size:offset': 16,
899 'u-boot-align-size:size': 32,
900
901 'u-boot-align-end:image-pos': 48,
902 'u-boot-align-end:offset': 48,
903 'u-boot-align-end:size': 16,
904
905 'u-boot-align-both:image-pos': 64,
906 'u-boot-align-both:offset': 64,
907 'u-boot-align-both:size': 64,
908 }
909 self.assertEqual(expected, props)
910
Simon Glass4f443042016-11-25 20:15:52 -0700911 def testPackAlignPowerOf2(self):
912 """Test that invalid entry alignment is detected"""
913 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600914 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700915 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
916 "of two", str(e.exception))
917
918 def testPackAlignSizePowerOf2(self):
919 """Test that invalid entry size alignment is detected"""
920 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600921 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700922 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
923 "power of two", str(e.exception))
924
925 def testPackInvalidAlign(self):
Simon Glass3ab95982018-08-01 15:22:37 -0600926 """Test detection of an offset that does not match its alignment"""
Simon Glass4f443042016-11-25 20:15:52 -0700927 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600928 self._DoTestFile('012_pack_inv_align.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600929 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700930 "align 0x4 (4)", str(e.exception))
931
932 def testPackInvalidSizeAlign(self):
933 """Test that invalid entry size alignment is detected"""
934 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600935 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700936 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
937 "align-size 0x4 (4)", str(e.exception))
938
939 def testPackOverlap(self):
940 """Test that overlapping regions are detected"""
941 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600942 self._DoTestFile('014_pack_overlap.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600943 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -0700944 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
945 str(e.exception))
946
947 def testPackEntryOverflow(self):
948 """Test that entries that overflow their size are detected"""
949 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600950 self._DoTestFile('015_pack_overflow.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700951 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
952 "but entry size is 0x3 (3)", str(e.exception))
953
954 def testPackImageOverflow(self):
955 """Test that entries which overflow the image size are detected"""
956 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600957 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600958 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass4f443042016-11-25 20:15:52 -0700959 "size 0x3 (3)", str(e.exception))
960
961 def testPackImageSize(self):
962 """Test that the image size can be set"""
Simon Glass741f2d62018-10-01 12:22:30 -0600963 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700964 self.assertEqual(0, retcode)
965 self.assertIn('image', control.images)
966 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -0600967 self.assertEqual(7, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700968
969 def testPackImageSizeAlign(self):
970 """Test that image size alignemnt works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600971 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700972 self.assertEqual(0, retcode)
973 self.assertIn('image', control.images)
974 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -0600975 self.assertEqual(16, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700976
977 def testPackInvalidImageAlign(self):
978 """Test that invalid image alignment is detected"""
979 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600980 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600981 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700982 "align-size 0x8 (8)", str(e.exception))
983
984 def testPackAlignPowerOf2(self):
985 """Test that invalid image alignment is detected"""
986 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600987 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -0600988 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass4f443042016-11-25 20:15:52 -0700989 "two", str(e.exception))
990
991 def testImagePadByte(self):
992 """Test that the image pad byte can be specified"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600993 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600994 data = self._DoReadFile('021_image_pad.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -0600995 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0xff, 1) +
996 U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -0700997
998 def testImageName(self):
999 """Test that image files can be named"""
Simon Glass741f2d62018-10-01 12:22:30 -06001000 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001001 self.assertEqual(0, retcode)
1002 image = control.images['image1']
1003 fname = tools.GetOutputFilename('test-name')
1004 self.assertTrue(os.path.exists(fname))
1005
1006 image = control.images['image2']
1007 fname = tools.GetOutputFilename('test-name.xx')
1008 self.assertTrue(os.path.exists(fname))
1009
1010 def testBlobFilename(self):
1011 """Test that generic blobs can be provided by filename"""
Simon Glass741f2d62018-10-01 12:22:30 -06001012 data = self._DoReadFile('023_blob.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001013 self.assertEqual(BLOB_DATA, data)
1014
1015 def testPackSorted(self):
1016 """Test that entries can be sorted"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001017 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001018 data = self._DoReadFile('024_sorted.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001019 self.assertEqual(tools.GetBytes(0, 1) + U_BOOT_SPL_DATA +
1020 tools.GetBytes(0, 2) + U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -07001021
Simon Glass3ab95982018-08-01 15:22:37 -06001022 def testPackZeroOffset(self):
1023 """Test that an entry at offset 0 is not given a new offset"""
Simon Glass4f443042016-11-25 20:15:52 -07001024 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001025 self._DoTestFile('025_pack_zero_size.dts')
Simon Glass3ab95982018-08-01 15:22:37 -06001026 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -07001027 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1028 str(e.exception))
1029
1030 def testPackUbootDtb(self):
1031 """Test that a device tree can be added to U-Boot"""
Simon Glass741f2d62018-10-01 12:22:30 -06001032 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001033 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glasse0ff8552016-11-25 20:15:53 -07001034
1035 def testPackX86RomNoSize(self):
1036 """Test that the end-at-4gb property requires a size property"""
1037 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001038 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -06001039 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glasse0ff8552016-11-25 20:15:53 -07001040 "using end-at-4gb", str(e.exception))
1041
Jagdish Gediya94b57db2018-09-03 21:35:07 +05301042 def test4gbAndSkipAtStartTogether(self):
1043 """Test that the end-at-4gb and skip-at-size property can't be used
1044 together"""
1045 with self.assertRaises(ValueError) as e:
Simon Glassdfdd2b62019-08-24 07:23:02 -06001046 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -06001047 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya94b57db2018-09-03 21:35:07 +05301048 "'skip-at-start'", str(e.exception))
1049
Simon Glasse0ff8552016-11-25 20:15:53 -07001050 def testPackX86RomOutside(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001051 """Test that the end-at-4gb property checks for offset boundaries"""
Simon Glasse0ff8552016-11-25 20:15:53 -07001052 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001053 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glasse6bed4f2020-10-26 17:40:05 -06001054 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
1055 "is outside the section '/binman' starting at "
1056 '0xffffffe0 (4294967264) of size 0x20 (32)',
Simon Glasse0ff8552016-11-25 20:15:53 -07001057 str(e.exception))
1058
1059 def testPackX86Rom(self):
1060 """Test that a basic x86 ROM can be created"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001061 self._SetupSplElf()
Simon Glass9255f3c2019-08-24 07:23:01 -06001062 data = self._DoReadFile('029_x86_rom.dts')
Simon Glasseb0086f2019-08-24 07:23:04 -06001063 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 3) + U_BOOT_SPL_DATA +
Simon Glasse6d85ff2019-05-14 15:53:47 -06001064 tools.GetBytes(0, 2), data)
Simon Glasse0ff8552016-11-25 20:15:53 -07001065
1066 def testPackX86RomMeNoDesc(self):
1067 """Test that an invalid Intel descriptor entry is detected"""
Simon Glass0ba4b3d2020-07-09 18:39:41 -06001068 try:
Simon Glass52b10dd2020-07-25 15:11:19 -06001069 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
Simon Glass0ba4b3d2020-07-09 18:39:41 -06001070 with self.assertRaises(ValueError) as e:
Simon Glass52b10dd2020-07-25 15:11:19 -06001071 self._DoTestFile('163_x86_rom_me_empty.dts')
Simon Glass0ba4b3d2020-07-09 18:39:41 -06001072 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1073 str(e.exception))
1074 finally:
1075 self._SetupDescriptor()
Simon Glasse0ff8552016-11-25 20:15:53 -07001076
1077 def testPackX86RomBadDesc(self):
1078 """Test that the Intel requires a descriptor entry"""
1079 with self.assertRaises(ValueError) as e:
Simon Glass9255f3c2019-08-24 07:23:01 -06001080 self._DoTestFile('030_x86_rom_me_no_desc.dts')
Simon Glass3ab95982018-08-01 15:22:37 -06001081 self.assertIn("Node '/binman/intel-me': No offset set with "
1082 "offset-unset: should another entry provide this correct "
1083 "offset?", str(e.exception))
Simon Glasse0ff8552016-11-25 20:15:53 -07001084
1085 def testPackX86RomMe(self):
1086 """Test that an x86 ROM with an ME region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001087 data = self._DoReadFile('031_x86_rom_me.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06001088 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
1089 if data[:0x1000] != expected_desc:
1090 self.fail('Expected descriptor binary at start of image')
Simon Glasse0ff8552016-11-25 20:15:53 -07001091 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1092
1093 def testPackVga(self):
1094 """Test that an image with a VGA binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001095 data = self._DoReadFile('032_intel_vga.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -07001096 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1097
1098 def testPackStart16(self):
1099 """Test that an image with an x86 start16 region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001100 data = self._DoReadFile('033_x86_start16.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -07001101 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1102
Jagdish Gediya9d368f32018-09-03 21:35:08 +05301103 def testPackPowerpcMpc85xxBootpgResetvec(self):
1104 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1105 created"""
Simon Glassdfdd2b62019-08-24 07:23:02 -06001106 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
Jagdish Gediya9d368f32018-09-03 21:35:08 +05301107 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1108
Simon Glass736bb0a2018-07-06 10:27:17 -06001109 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glassadc57012018-07-06 10:27:16 -06001110 """Handle running a test for insertion of microcode
1111
1112 Args:
1113 dts_fname: Name of test .dts file
1114 nodtb_data: Data that we expect in the first section
Simon Glass736bb0a2018-07-06 10:27:17 -06001115 ucode_second: True if the microsecond entry is second instead of
1116 third
Simon Glassadc57012018-07-06 10:27:16 -06001117
1118 Returns:
1119 Tuple:
1120 Contents of first region (U-Boot or SPL)
Simon Glass3ab95982018-08-01 15:22:37 -06001121 Offset and size components of microcode pointer, as inserted
Simon Glassadc57012018-07-06 10:27:16 -06001122 in the above (two 4-byte words)
1123 """
Simon Glass6b187df2017-11-12 21:52:27 -07001124 data = self._DoReadFile(dts_fname, True)
Simon Glasse0ff8552016-11-25 20:15:53 -07001125
1126 # Now check the device tree has no microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001127 if ucode_second:
1128 ucode_content = data[len(nodtb_data):]
1129 ucode_pos = len(nodtb_data)
1130 dtb_with_ucode = ucode_content[16:]
1131 fdt_len = self.GetFdtLen(dtb_with_ucode)
1132 else:
1133 dtb_with_ucode = data[len(nodtb_data):]
1134 fdt_len = self.GetFdtLen(dtb_with_ucode)
1135 ucode_content = dtb_with_ucode[fdt_len:]
1136 ucode_pos = len(nodtb_data) + fdt_len
Simon Glasse0ff8552016-11-25 20:15:53 -07001137 fname = tools.GetOutputFilename('test.dtb')
1138 with open(fname, 'wb') as fd:
Simon Glassadc57012018-07-06 10:27:16 -06001139 fd.write(dtb_with_ucode)
Simon Glassec3f3782017-05-27 07:38:29 -06001140 dtb = fdt.FdtScan(fname)
1141 ucode = dtb.GetNode('/microcode')
Simon Glasse0ff8552016-11-25 20:15:53 -07001142 self.assertTrue(ucode)
1143 for node in ucode.subnodes:
1144 self.assertFalse(node.props.get('data'))
1145
Simon Glasse0ff8552016-11-25 20:15:53 -07001146 # Check that the microcode appears immediately after the Fdt
1147 # This matches the concatenation of the data properties in
Simon Glass87722132017-11-12 21:52:26 -07001148 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glasse0ff8552016-11-25 20:15:53 -07001149 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1150 0x78235609)
Simon Glassadc57012018-07-06 10:27:16 -06001151 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glasse0ff8552016-11-25 20:15:53 -07001152
1153 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -06001154 # expected offset and size
Simon Glasse0ff8552016-11-25 20:15:53 -07001155 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1156 len(ucode_data))
Simon Glass736bb0a2018-07-06 10:27:17 -06001157 u_boot = data[:len(nodtb_data)]
1158 return u_boot, pos_and_size
Simon Glass6b187df2017-11-12 21:52:27 -07001159
1160 def testPackUbootMicrocode(self):
1161 """Test that x86 microcode can be handled correctly
1162
1163 We expect to see the following in the image, in order:
1164 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1165 place
1166 u-boot.dtb with the microcode removed
1167 the microcode
1168 """
Simon Glass741f2d62018-10-01 12:22:30 -06001169 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass6b187df2017-11-12 21:52:27 -07001170 U_BOOT_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001171 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1172 b' somewhere in here', first)
Simon Glasse0ff8552016-11-25 20:15:53 -07001173
Simon Glass160a7662017-05-27 07:38:26 -06001174 def _RunPackUbootSingleMicrocode(self):
Simon Glasse0ff8552016-11-25 20:15:53 -07001175 """Test that x86 microcode can be handled correctly
1176
1177 We expect to see the following in the image, in order:
1178 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1179 place
1180 u-boot.dtb with the microcode
1181 an empty microcode region
1182 """
1183 # We need the libfdt library to run this test since only that allows
1184 # finding the offset of a property. This is required by
1185 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass741f2d62018-10-01 12:22:30 -06001186 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glasse0ff8552016-11-25 20:15:53 -07001187
1188 second = data[len(U_BOOT_NODTB_DATA):]
1189
1190 fdt_len = self.GetFdtLen(second)
1191 third = second[fdt_len:]
1192 second = second[:fdt_len]
1193
Simon Glass160a7662017-05-27 07:38:26 -06001194 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1195 self.assertIn(ucode_data, second)
1196 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -07001197
Simon Glass160a7662017-05-27 07:38:26 -06001198 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -06001199 # expected offset and size
Simon Glass160a7662017-05-27 07:38:26 -06001200 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1201 len(ucode_data))
1202 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glassc6c10e72019-05-17 22:00:46 -06001203 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1204 b' somewhere in here', first)
Simon Glassc49deb82016-11-25 20:15:54 -07001205
Simon Glass75db0862016-11-25 20:15:55 -07001206 def testPackUbootSingleMicrocode(self):
1207 """Test that x86 microcode can be handled correctly with fdt_normal.
1208 """
Simon Glass160a7662017-05-27 07:38:26 -06001209 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001210
Simon Glassc49deb82016-11-25 20:15:54 -07001211 def testUBootImg(self):
1212 """Test that u-boot.img can be put in a file"""
Simon Glass741f2d62018-10-01 12:22:30 -06001213 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glassc49deb82016-11-25 20:15:54 -07001214 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glass75db0862016-11-25 20:15:55 -07001215
1216 def testNoMicrocode(self):
1217 """Test that a missing microcode region is detected"""
1218 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001219 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001220 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1221 "node found in ", str(e.exception))
1222
1223 def testMicrocodeWithoutNode(self):
1224 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1225 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001226 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001227 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1228 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1229
1230 def testMicrocodeWithoutNode2(self):
1231 """Test that a missing u-boot-ucode node is detected"""
1232 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001233 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001234 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1235 "microcode region u-boot-ucode", str(e.exception))
1236
1237 def testMicrocodeWithoutPtrInElf(self):
1238 """Test that a U-Boot binary without the microcode symbol is detected"""
1239 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glass75db0862016-11-25 20:15:55 -07001240 try:
Simon Glassbccd91d2019-08-24 07:22:55 -06001241 TestFunctional._MakeInputFile('u-boot',
1242 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass75db0862016-11-25 20:15:55 -07001243
1244 with self.assertRaises(ValueError) as e:
Simon Glass160a7662017-05-27 07:38:26 -06001245 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001246 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1247 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1248
1249 finally:
1250 # Put the original file back
Simon Glassf514d8f2019-08-24 07:22:54 -06001251 TestFunctional._MakeInputFile('u-boot',
1252 tools.ReadFile(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glass75db0862016-11-25 20:15:55 -07001253
1254 def testMicrocodeNotInImage(self):
1255 """Test that microcode must be placed within the image"""
1256 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001257 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001258 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1259 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glass25ac0e62018-06-01 09:38:14 -06001260 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glass75db0862016-11-25 20:15:55 -07001261
1262 def testWithoutMicrocode(self):
1263 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glassbccd91d2019-08-24 07:22:55 -06001264 TestFunctional._MakeInputFile('u-boot',
1265 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass741f2d62018-10-01 12:22:30 -06001266 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001267
1268 # Now check the device tree has no microcode
1269 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1270 second = data[len(U_BOOT_NODTB_DATA):]
1271
1272 fdt_len = self.GetFdtLen(second)
1273 self.assertEqual(dtb, second[:fdt_len])
1274
1275 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1276 third = data[used_len:]
Simon Glasse6d85ff2019-05-14 15:53:47 -06001277 self.assertEqual(tools.GetBytes(0, 0x200 - used_len), third)
Simon Glass75db0862016-11-25 20:15:55 -07001278
1279 def testUnknownPosSize(self):
1280 """Test that microcode must be placed within the image"""
1281 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001282 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glass3ab95982018-08-01 15:22:37 -06001283 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glass75db0862016-11-25 20:15:55 -07001284 "entry 'invalid-entry'", str(e.exception))
Simon Glassda229092016-11-25 20:15:56 -07001285
1286 def testPackFsp(self):
1287 """Test that an image with a FSP binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001288 data = self._DoReadFile('042_intel_fsp.dts')
Simon Glassda229092016-11-25 20:15:56 -07001289 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1290
1291 def testPackCmc(self):
Bin Meng59ea8c22017-08-15 22:41:54 -07001292 """Test that an image with a CMC binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001293 data = self._DoReadFile('043_intel_cmc.dts')
Simon Glassda229092016-11-25 20:15:56 -07001294 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Meng59ea8c22017-08-15 22:41:54 -07001295
1296 def testPackVbt(self):
1297 """Test that an image with a VBT binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001298 data = self._DoReadFile('046_intel_vbt.dts')
Bin Meng59ea8c22017-08-15 22:41:54 -07001299 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glass9fc60b42017-11-12 21:52:22 -07001300
Simon Glass56509842017-11-12 21:52:25 -07001301 def testSplBssPad(self):
1302 """Test that we can pad SPL's BSS with zeros"""
Simon Glass6b187df2017-11-12 21:52:27 -07001303 # ELF file with a '__bss_size' symbol
Simon Glass11ae93e2018-10-01 21:12:47 -06001304 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001305 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001306 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
1307 data)
Simon Glass56509842017-11-12 21:52:25 -07001308
Simon Glass86af5112018-10-01 21:12:42 -06001309 def testSplBssPadMissing(self):
1310 """Test that a missing symbol is detected"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001311 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glassb50e5612017-11-13 18:54:54 -07001312 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001313 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassb50e5612017-11-13 18:54:54 -07001314 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1315 str(e.exception))
1316
Simon Glass87722132017-11-12 21:52:26 -07001317 def testPackStart16Spl(self):
Simon Glass35b384c2018-09-14 04:57:10 -06001318 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001319 data = self._DoReadFile('048_x86_start16_spl.dts')
Simon Glass87722132017-11-12 21:52:26 -07001320 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1321
Simon Glass736bb0a2018-07-06 10:27:17 -06001322 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1323 """Helper function for microcode tests
Simon Glass6b187df2017-11-12 21:52:27 -07001324
1325 We expect to see the following in the image, in order:
1326 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1327 correct place
1328 u-boot.dtb with the microcode removed
1329 the microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001330
1331 Args:
1332 dts: Device tree file to use for test
1333 ucode_second: True if the microsecond entry is second instead of
1334 third
Simon Glass6b187df2017-11-12 21:52:27 -07001335 """
Simon Glass11ae93e2018-10-01 21:12:47 -06001336 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass736bb0a2018-07-06 10:27:17 -06001337 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1338 ucode_second=ucode_second)
Simon Glassc6c10e72019-05-17 22:00:46 -06001339 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1340 b'ter somewhere in here', first)
Simon Glass6b187df2017-11-12 21:52:27 -07001341
Simon Glass736bb0a2018-07-06 10:27:17 -06001342 def testPackUbootSplMicrocode(self):
1343 """Test that x86 microcode can be handled correctly in SPL"""
Simon Glass741f2d62018-10-01 12:22:30 -06001344 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass736bb0a2018-07-06 10:27:17 -06001345
1346 def testPackUbootSplMicrocodeReorder(self):
1347 """Test that order doesn't matter for microcode entries
1348
1349 This is the same as testPackUbootSplMicrocode but when we process the
1350 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1351 entry, so we reply on binman to try later.
1352 """
Simon Glass741f2d62018-10-01 12:22:30 -06001353 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass736bb0a2018-07-06 10:27:17 -06001354 ucode_second=True)
1355
Simon Glassca4f4ff2017-11-12 21:52:28 -07001356 def testPackMrc(self):
1357 """Test that an image with an MRC binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001358 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassca4f4ff2017-11-12 21:52:28 -07001359 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1360
Simon Glass47419ea2017-11-13 18:54:55 -07001361 def testSplDtb(self):
1362 """Test that an image with spl/u-boot-spl.dtb can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001363 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass47419ea2017-11-13 18:54:55 -07001364 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1365
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001366 def testSplNoDtb(self):
1367 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass0fe44dc2021-04-25 08:39:32 +12001368 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001369 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001370 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1371
Simon Glass3d433382021-03-21 18:24:30 +13001372 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
1373 use_expanded=False):
Simon Glassf5898822021-03-18 20:24:56 +13001374 """Check the image contains the expected symbol values
1375
1376 Args:
1377 dts: Device tree file to use for test
1378 base_data: Data before and after 'u-boot' section
1379 u_boot_offset: Offset of 'u-boot' section in image
Simon Glass3d433382021-03-21 18:24:30 +13001380 entry_args: Dict of entry args to supply to binman
1381 key: arg name
1382 value: value of that arg
1383 use_expanded: True to use expanded entries where available, e.g.
1384 'u-boot-expanded' instead of 'u-boot'
Simon Glassf5898822021-03-18 20:24:56 +13001385 """
Simon Glass1542c8b2019-08-24 07:22:56 -06001386 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass19790632017-11-13 18:55:01 -07001387 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1388 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Simon Glassf5898822021-03-18 20:24:56 +13001389 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
1390 addr)
Simon Glass19790632017-11-13 18:55:01 -07001391
Simon Glass11ae93e2018-10-01 21:12:47 -06001392 self._SetupSplElf('u_boot_binman_syms')
Simon Glass3d433382021-03-21 18:24:30 +13001393 data = self._DoReadFileDtb(dts, entry_args=entry_args,
1394 use_expanded=use_expanded)[0]
Simon Glassf5898822021-03-18 20:24:56 +13001395 # The image should contain the symbols from u_boot_binman_syms.c
1396 # Note that image_pos is adjusted by the base address of the image,
1397 # which is 0x10 in our test image
1398 sym_values = struct.pack('<LQLL', 0x00,
1399 u_boot_offset + len(U_BOOT_DATA),
1400 0x10 + u_boot_offset, 0x04)
1401 expected = (sym_values + base_data[20:] +
Simon Glasse6d85ff2019-05-14 15:53:47 -06001402 tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
Simon Glassf5898822021-03-18 20:24:56 +13001403 base_data[20:])
Simon Glass19790632017-11-13 18:55:01 -07001404 self.assertEqual(expected, data)
1405
Simon Glassf5898822021-03-18 20:24:56 +13001406 def testSymbols(self):
1407 """Test binman can assign symbols embedded in U-Boot"""
1408 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x18)
1409
1410 def testSymbolsNoDtb(self):
1411 """Test binman can assign symbols embedded in U-Boot SPL"""
Simon Glasse9e0db82021-03-21 18:24:29 +13001412 self.checkSymbols('196_symbols_nodtb.dts',
Simon Glassf5898822021-03-18 20:24:56 +13001413 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1414 0x38)
1415
Simon Glassdd57c132018-06-01 09:38:11 -06001416 def testPackUnitAddress(self):
1417 """Test that we support multiple binaries with the same name"""
Simon Glass741f2d62018-10-01 12:22:30 -06001418 data = self._DoReadFile('054_unit_address.dts')
Simon Glassdd57c132018-06-01 09:38:11 -06001419 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1420
Simon Glass18546952018-06-01 09:38:16 -06001421 def testSections(self):
1422 """Basic test of sections"""
Simon Glass741f2d62018-10-01 12:22:30 -06001423 data = self._DoReadFile('055_sections.dts')
Simon Glassc6c10e72019-05-17 22:00:46 -06001424 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1425 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
1426 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
Simon Glass18546952018-06-01 09:38:16 -06001427 self.assertEqual(expected, data)
Simon Glass9fc60b42017-11-12 21:52:22 -07001428
Simon Glass3b0c3822018-06-01 09:38:20 -06001429 def testMap(self):
1430 """Tests outputting a map of the images"""
Simon Glass741f2d62018-10-01 12:22:30 -06001431 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001432 self.assertEqual('''ImagePos Offset Size Name
143300000000 00000000 00000028 main-section
143400000000 00000000 00000010 section@0
143500000000 00000000 00000004 u-boot
143600000010 00000010 00000010 section@1
143700000010 00000000 00000004 u-boot
143800000020 00000020 00000004 section@2
143900000020 00000000 00000004 u-boot
Simon Glass3b0c3822018-06-01 09:38:20 -06001440''', map_data)
1441
Simon Glassc8d48ef2018-06-01 09:38:21 -06001442 def testNamePrefix(self):
1443 """Tests that name prefixes are used"""
Simon Glass741f2d62018-10-01 12:22:30 -06001444 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001445 self.assertEqual('''ImagePos Offset Size Name
144600000000 00000000 00000028 main-section
144700000000 00000000 00000010 section@0
144800000000 00000000 00000004 ro-u-boot
144900000010 00000010 00000010 section@1
145000000010 00000000 00000004 rw-u-boot
Simon Glassc8d48ef2018-06-01 09:38:21 -06001451''', map_data)
1452
Simon Glass736bb0a2018-07-06 10:27:17 -06001453 def testUnknownContents(self):
1454 """Test that obtaining the contents works as expected"""
1455 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001456 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass8beb11e2019-07-08 14:25:47 -06001457 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glass16287932020-04-17 18:09:03 -06001458 "processing of contents: remaining ["
1459 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass736bb0a2018-07-06 10:27:17 -06001460
Simon Glass5c890232018-07-06 10:27:19 -06001461 def testBadChangeSize(self):
1462 """Test that trying to change the size of an entry fails"""
Simon Glassc52c9e72019-07-08 14:25:37 -06001463 try:
1464 state.SetAllowEntryExpansion(False)
1465 with self.assertRaises(ValueError) as e:
1466 self._DoReadFile('059_change_size.dts', True)
Simon Glass79d3c582019-07-20 12:23:57 -06001467 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glassc52c9e72019-07-08 14:25:37 -06001468 str(e.exception))
1469 finally:
1470 state.SetAllowEntryExpansion(True)
Simon Glass5c890232018-07-06 10:27:19 -06001471
Simon Glass16b8d6b2018-07-06 10:27:42 -06001472 def testUpdateFdt(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001473 """Test that we can update the device tree with offset/size info"""
Simon Glass741f2d62018-10-01 12:22:30 -06001474 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glass16b8d6b2018-07-06 10:27:42 -06001475 update_dtb=True)
Simon Glasscee02e62018-07-17 13:25:52 -06001476 dtb = fdt.Fdt(out_dtb_fname)
1477 dtb.Scan()
Simon Glass12bb1a92019-07-20 12:23:51 -06001478 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001479 self.assertEqual({
Simon Glassdbf6be92018-08-01 15:22:42 -06001480 'image-pos': 0,
Simon Glass8122f392018-07-17 13:25:28 -06001481 'offset': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001482 '_testing:offset': 32,
Simon Glass79d3c582019-07-20 12:23:57 -06001483 '_testing:size': 2,
Simon Glassdbf6be92018-08-01 15:22:42 -06001484 '_testing:image-pos': 32,
Simon Glass3ab95982018-08-01 15:22:37 -06001485 'section@0/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001486 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001487 'section@0/u-boot:image-pos': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001488 'section@0:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001489 'section@0:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001490 'section@0:image-pos': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001491
Simon Glass3ab95982018-08-01 15:22:37 -06001492 'section@1/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001493 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001494 'section@1/u-boot:image-pos': 16,
Simon Glass3ab95982018-08-01 15:22:37 -06001495 'section@1:offset': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001496 'section@1:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001497 'section@1:image-pos': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001498 'size': 40
1499 }, props)
1500
1501 def testUpdateFdtBad(self):
1502 """Test that we detect when ProcessFdt never completes"""
1503 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001504 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001505 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glass16287932020-04-17 18:09:03 -06001506 '[<binman.etype._testing.Entry__testing',
1507 str(e.exception))
Simon Glass5c890232018-07-06 10:27:19 -06001508
Simon Glass53af22a2018-07-17 13:25:32 -06001509 def testEntryArgs(self):
1510 """Test passing arguments to entries from the command line"""
1511 entry_args = {
1512 'test-str-arg': 'test1',
1513 'test-int-arg': '456',
1514 }
Simon Glass741f2d62018-10-01 12:22:30 -06001515 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001516 self.assertIn('image', control.images)
1517 entry = control.images['image'].GetEntries()['_testing']
1518 self.assertEqual('test0', entry.test_str_fdt)
1519 self.assertEqual('test1', entry.test_str_arg)
1520 self.assertEqual(123, entry.test_int_fdt)
1521 self.assertEqual(456, entry.test_int_arg)
1522
1523 def testEntryArgsMissing(self):
1524 """Test missing arguments and properties"""
1525 entry_args = {
1526 'test-int-arg': '456',
1527 }
Simon Glass741f2d62018-10-01 12:22:30 -06001528 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001529 entry = control.images['image'].GetEntries()['_testing']
1530 self.assertEqual('test0', entry.test_str_fdt)
1531 self.assertEqual(None, entry.test_str_arg)
1532 self.assertEqual(None, entry.test_int_fdt)
1533 self.assertEqual(456, entry.test_int_arg)
1534
1535 def testEntryArgsRequired(self):
1536 """Test missing arguments and properties"""
1537 entry_args = {
1538 'test-int-arg': '456',
1539 }
1540 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001541 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass3decfa32020-09-01 05:13:54 -06001542 self.assertIn("Node '/binman/_testing': "
1543 'Missing required properties/entry args: test-str-arg, '
1544 'test-int-fdt, test-int-arg',
Simon Glass53af22a2018-07-17 13:25:32 -06001545 str(e.exception))
1546
1547 def testEntryArgsInvalidFormat(self):
1548 """Test that an invalid entry-argument format is detected"""
Simon Glass53cd5d92019-07-08 14:25:29 -06001549 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1550 '-ano-value']
Simon Glass53af22a2018-07-17 13:25:32 -06001551 with self.assertRaises(ValueError) as e:
1552 self._DoBinman(*args)
1553 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1554
1555 def testEntryArgsInvalidInteger(self):
1556 """Test that an invalid entry-argument integer is detected"""
1557 entry_args = {
1558 'test-int-arg': 'abc',
1559 }
1560 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001561 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001562 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1563 "'test-int-arg' (value 'abc') to integer",
1564 str(e.exception))
1565
1566 def testEntryArgsInvalidDatatype(self):
1567 """Test that an invalid entry-argument datatype is detected
1568
1569 This test could be written in entry_test.py except that it needs
1570 access to control.entry_args, which seems more than that module should
1571 be able to see.
1572 """
1573 entry_args = {
1574 'test-bad-datatype-arg': '12',
1575 }
1576 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001577 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass53af22a2018-07-17 13:25:32 -06001578 entry_args=entry_args)
1579 self.assertIn('GetArg() internal error: Unknown data type ',
1580 str(e.exception))
1581
Simon Glassbb748372018-07-17 13:25:33 -06001582 def testText(self):
1583 """Test for a text entry type"""
1584 entry_args = {
1585 'test-id': TEXT_DATA,
1586 'test-id2': TEXT_DATA2,
1587 'test-id3': TEXT_DATA3,
1588 }
Simon Glass741f2d62018-10-01 12:22:30 -06001589 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glassbb748372018-07-17 13:25:33 -06001590 entry_args=entry_args)
Simon Glassc6c10e72019-05-17 22:00:46 -06001591 expected = (tools.ToBytes(TEXT_DATA) +
1592 tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1593 tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
Simon Glassaa88b502019-07-08 13:18:40 -06001594 b'some text' + b'more text')
Simon Glassbb748372018-07-17 13:25:33 -06001595 self.assertEqual(expected, data)
1596
Simon Glassfd8d1f72018-07-17 13:25:36 -06001597 def testEntryDocs(self):
1598 """Test for creation of entry documentation"""
1599 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass87d43322020-08-05 13:27:46 -06001600 control.WriteEntryDocs(control.GetEntryModules())
Simon Glassfd8d1f72018-07-17 13:25:36 -06001601 self.assertTrue(len(stdout.getvalue()) > 0)
1602
1603 def testEntryDocsMissing(self):
1604 """Test handling of missing entry documentation"""
1605 with self.assertRaises(ValueError) as e:
1606 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass87d43322020-08-05 13:27:46 -06001607 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glassfd8d1f72018-07-17 13:25:36 -06001608 self.assertIn('Documentation is missing for modules: u_boot',
1609 str(e.exception))
1610
Simon Glass11e36cc2018-07-17 13:25:38 -06001611 def testFmap(self):
1612 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001613 data = self._DoReadFile('067_fmap.dts')
Simon Glass11e36cc2018-07-17 13:25:38 -06001614 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc6c10e72019-05-17 22:00:46 -06001615 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1616 U_BOOT_DATA + tools.GetBytes(ord('a'), 12))
Simon Glass11e36cc2018-07-17 13:25:38 -06001617 self.assertEqual(expected, data[:32])
Simon Glassc6c10e72019-05-17 22:00:46 -06001618 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass11e36cc2018-07-17 13:25:38 -06001619 self.assertEqual(1, fhdr.ver_major)
1620 self.assertEqual(0, fhdr.ver_minor)
1621 self.assertEqual(0, fhdr.base)
Simon Glass17365752021-04-03 11:05:10 +13001622 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 5
Simon Glassc7722e82021-04-03 11:05:09 +13001623 self.assertEqual(16 + 16 + expect_size, fhdr.image_size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001624 self.assertEqual(b'FMAP', fhdr.name)
Simon Glass17365752021-04-03 11:05:10 +13001625 self.assertEqual(5, fhdr.nareas)
Simon Glassc7722e82021-04-03 11:05:09 +13001626 fiter = iter(fentries)
Simon Glass11e36cc2018-07-17 13:25:38 -06001627
Simon Glassc7722e82021-04-03 11:05:09 +13001628 fentry = next(fiter)
Simon Glass17365752021-04-03 11:05:10 +13001629 self.assertEqual(b'SECTION0', fentry.name)
1630 self.assertEqual(0, fentry.offset)
1631 self.assertEqual(16, fentry.size)
1632 self.assertEqual(0, fentry.flags)
1633
1634 fentry = next(fiter)
Simon Glassc7722e82021-04-03 11:05:09 +13001635 self.assertEqual(b'RO_U_BOOT', fentry.name)
1636 self.assertEqual(0, fentry.offset)
1637 self.assertEqual(4, fentry.size)
1638 self.assertEqual(0, fentry.flags)
Simon Glass11e36cc2018-07-17 13:25:38 -06001639
Simon Glassc7722e82021-04-03 11:05:09 +13001640 fentry = next(fiter)
Simon Glass17365752021-04-03 11:05:10 +13001641 self.assertEqual(b'SECTION1', fentry.name)
1642 self.assertEqual(16, fentry.offset)
1643 self.assertEqual(16, fentry.size)
1644 self.assertEqual(0, fentry.flags)
1645
1646 fentry = next(fiter)
Simon Glassc7722e82021-04-03 11:05:09 +13001647 self.assertEqual(b'RW_U_BOOT', fentry.name)
1648 self.assertEqual(16, fentry.offset)
1649 self.assertEqual(4, fentry.size)
1650 self.assertEqual(0, fentry.flags)
Simon Glass11e36cc2018-07-17 13:25:38 -06001651
Simon Glassc7722e82021-04-03 11:05:09 +13001652 fentry = next(fiter)
1653 self.assertEqual(b'FMAP', fentry.name)
1654 self.assertEqual(32, fentry.offset)
1655 self.assertEqual(expect_size, fentry.size)
1656 self.assertEqual(0, fentry.flags)
Simon Glass11e36cc2018-07-17 13:25:38 -06001657
Simon Glassec127af2018-07-17 13:25:39 -06001658 def testBlobNamedByArg(self):
1659 """Test we can add a blob with the filename coming from an entry arg"""
1660 entry_args = {
1661 'cros-ec-rw-path': 'ecrw.bin',
1662 }
Simon Glass3decfa32020-09-01 05:13:54 -06001663 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassec127af2018-07-17 13:25:39 -06001664
Simon Glass3af8e492018-07-17 13:25:40 -06001665 def testFill(self):
1666 """Test for an fill entry type"""
Simon Glass741f2d62018-10-01 12:22:30 -06001667 data = self._DoReadFile('069_fill.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001668 expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
Simon Glass3af8e492018-07-17 13:25:40 -06001669 self.assertEqual(expected, data)
1670
1671 def testFillNoSize(self):
1672 """Test for an fill entry type with no size"""
1673 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001674 self._DoReadFile('070_fill_no_size.dts')
Simon Glass3af8e492018-07-17 13:25:40 -06001675 self.assertIn("'fill' entry must have a size property",
1676 str(e.exception))
1677
Simon Glass0ef87aa2018-07-17 13:25:44 -06001678 def _HandleGbbCommand(self, pipe_list):
1679 """Fake calls to the futility utility"""
1680 if pipe_list[0][0] == 'futility':
1681 fname = pipe_list[0][-1]
1682 # Append our GBB data to the file, which will happen every time the
1683 # futility command is called.
Simon Glass1d0ebf72019-05-14 15:53:42 -06001684 with open(fname, 'ab') as fd:
Simon Glass0ef87aa2018-07-17 13:25:44 -06001685 fd.write(GBB_DATA)
1686 return command.CommandResult()
1687
1688 def testGbb(self):
1689 """Test for the Chromium OS Google Binary Block"""
1690 command.test_result = self._HandleGbbCommand
1691 entry_args = {
1692 'keydir': 'devkeys',
1693 'bmpblk': 'bmpblk.bin',
1694 }
Simon Glass741f2d62018-10-01 12:22:30 -06001695 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glass0ef87aa2018-07-17 13:25:44 -06001696
1697 # Since futility
Simon Glasse6d85ff2019-05-14 15:53:47 -06001698 expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1699 tools.GetBytes(0, 0x2180 - 16))
Simon Glass0ef87aa2018-07-17 13:25:44 -06001700 self.assertEqual(expected, data)
1701
1702 def testGbbTooSmall(self):
1703 """Test for the Chromium OS Google Binary Block being large enough"""
1704 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001705 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001706 self.assertIn("Node '/binman/gbb': GBB is too small",
1707 str(e.exception))
1708
1709 def testGbbNoSize(self):
1710 """Test for the Chromium OS Google Binary Block having a size"""
1711 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001712 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001713 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1714 str(e.exception))
1715
Simon Glass24d0d3c2018-07-17 13:25:47 -06001716 def _HandleVblockCommand(self, pipe_list):
Simon Glass5af9ebc2021-01-06 21:35:17 -07001717 """Fake calls to the futility utility
1718
1719 The expected pipe is:
1720
1721 [('futility', 'vbutil_firmware', '--vblock',
1722 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1723 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1724 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1725 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1726
1727 This writes to the output file (here, 'vblock.vblock'). If
1728 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1729 of the input data (here, 'input.vblock').
1730 """
Simon Glass24d0d3c2018-07-17 13:25:47 -06001731 if pipe_list[0][0] == 'futility':
1732 fname = pipe_list[0][3]
Simon Glassa326b492018-09-14 04:57:11 -06001733 with open(fname, 'wb') as fd:
Simon Glass5af9ebc2021-01-06 21:35:17 -07001734 if self._hash_data:
1735 infile = pipe_list[0][11]
1736 m = hashlib.sha256()
1737 data = tools.ReadFile(infile)
1738 m.update(data)
1739 fd.write(m.digest())
1740 else:
1741 fd.write(VBLOCK_DATA)
1742
Simon Glass24d0d3c2018-07-17 13:25:47 -06001743 return command.CommandResult()
1744
1745 def testVblock(self):
1746 """Test for the Chromium OS Verified Boot Block"""
Simon Glass5af9ebc2021-01-06 21:35:17 -07001747 self._hash_data = False
Simon Glass24d0d3c2018-07-17 13:25:47 -06001748 command.test_result = self._HandleVblockCommand
1749 entry_args = {
1750 'keydir': 'devkeys',
1751 }
Simon Glass741f2d62018-10-01 12:22:30 -06001752 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass24d0d3c2018-07-17 13:25:47 -06001753 entry_args=entry_args)
1754 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1755 self.assertEqual(expected, data)
1756
1757 def testVblockNoContent(self):
1758 """Test we detect a vblock which has no content to sign"""
1759 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001760 self._DoReadFile('075_vblock_no_content.dts')
Simon Glass189f2912021-03-21 18:24:31 +13001761 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
Simon Glass24d0d3c2018-07-17 13:25:47 -06001762 'property', str(e.exception))
1763
1764 def testVblockBadPhandle(self):
1765 """Test that we detect a vblock with an invalid phandle in contents"""
1766 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001767 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001768 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1769 '1000', str(e.exception))
1770
1771 def testVblockBadEntry(self):
1772 """Test that we detect an entry that points to a non-entry"""
1773 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001774 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001775 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1776 "'other'", str(e.exception))
1777
Simon Glass5af9ebc2021-01-06 21:35:17 -07001778 def testVblockContent(self):
1779 """Test that the vblock signs the right data"""
1780 self._hash_data = True
1781 command.test_result = self._HandleVblockCommand
1782 entry_args = {
1783 'keydir': 'devkeys',
1784 }
1785 data = self._DoReadFileDtb(
1786 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1787 entry_args=entry_args)[0]
1788 hashlen = 32 # SHA256 hash is 32 bytes
1789 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1790 hashval = data[-hashlen:]
1791 dtb = data[len(U_BOOT_DATA):-hashlen]
1792
1793 expected_data = U_BOOT_DATA + dtb
1794
1795 # The hashval should be a hash of the dtb
1796 m = hashlib.sha256()
1797 m.update(expected_data)
1798 expected_hashval = m.digest()
1799 self.assertEqual(expected_hashval, hashval)
1800
Simon Glassb8ef5b62018-07-17 13:25:48 -06001801 def testTpl(self):
Simon Glass2090f1e2019-08-24 07:23:00 -06001802 """Test that an image with TPL and its device tree can be created"""
Simon Glassb8ef5b62018-07-17 13:25:48 -06001803 # ELF file with a '__bss_size' symbol
Simon Glass2090f1e2019-08-24 07:23:00 -06001804 self._SetupTplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001805 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glassb8ef5b62018-07-17 13:25:48 -06001806 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1807
Simon Glass15a587c2018-07-17 13:25:51 -06001808 def testUsesPos(self):
1809 """Test that the 'pos' property cannot be used anymore"""
1810 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001811 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass15a587c2018-07-17 13:25:51 -06001812 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1813 "'pos'", str(e.exception))
1814
Simon Glassd178eab2018-09-14 04:57:08 -06001815 def testFillZero(self):
1816 """Test for an fill entry type with a size of 0"""
Simon Glass741f2d62018-10-01 12:22:30 -06001817 data = self._DoReadFile('080_fill_empty.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001818 self.assertEqual(tools.GetBytes(0, 16), data)
Simon Glassd178eab2018-09-14 04:57:08 -06001819
Simon Glass0b489362018-09-14 04:57:09 -06001820 def testTextMissing(self):
1821 """Test for a text entry type where there is no text"""
1822 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001823 self._DoReadFileDtb('066_text.dts',)
Simon Glass0b489362018-09-14 04:57:09 -06001824 self.assertIn("Node '/binman/text': No value provided for text label "
1825 "'test-id'", str(e.exception))
1826
Simon Glass35b384c2018-09-14 04:57:10 -06001827 def testPackStart16Tpl(self):
1828 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001829 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glass35b384c2018-09-14 04:57:10 -06001830 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1831
Simon Glass0bfa7b02018-09-14 04:57:12 -06001832 def testSelectImage(self):
1833 """Test that we can select which images to build"""
Simon Glasseb833d82019-04-25 21:58:34 -06001834 expected = 'Skipping images: image1'
Simon Glass0bfa7b02018-09-14 04:57:12 -06001835
Simon Glasseb833d82019-04-25 21:58:34 -06001836 # We should only get the expected message in verbose mode
Simon Glassee0c9a72019-07-08 13:18:48 -06001837 for verbosity in (0, 2):
Simon Glasseb833d82019-04-25 21:58:34 -06001838 with test_util.capture_sys_output() as (stdout, stderr):
1839 retcode = self._DoTestFile('006_dual_image.dts',
1840 verbosity=verbosity,
1841 images=['image2'])
1842 self.assertEqual(0, retcode)
1843 if verbosity:
1844 self.assertIn(expected, stdout.getvalue())
1845 else:
1846 self.assertNotIn(expected, stdout.getvalue())
1847
1848 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1849 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
Simon Glassf86a7362019-07-20 12:24:10 -06001850 self._CleanupOutputDir()
Simon Glass0bfa7b02018-09-14 04:57:12 -06001851
Simon Glass6ed45ba2018-09-14 04:57:24 -06001852 def testUpdateFdtAll(self):
1853 """Test that all device trees are updated with offset/size info"""
Simon Glass3c081312019-07-08 14:25:26 -06001854 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glass6ed45ba2018-09-14 04:57:24 -06001855
1856 base_expected = {
1857 'section:image-pos': 0,
1858 'u-boot-tpl-dtb:size': 513,
1859 'u-boot-spl-dtb:size': 513,
1860 'u-boot-spl-dtb:offset': 493,
1861 'image-pos': 0,
1862 'section/u-boot-dtb:image-pos': 0,
1863 'u-boot-spl-dtb:image-pos': 493,
1864 'section/u-boot-dtb:size': 493,
1865 'u-boot-tpl-dtb:image-pos': 1006,
1866 'section/u-boot-dtb:offset': 0,
1867 'section:size': 493,
1868 'offset': 0,
1869 'section:offset': 0,
1870 'u-boot-tpl-dtb:offset': 1006,
1871 'size': 1519
1872 }
1873
1874 # We expect three device-tree files in the output, one after the other.
1875 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1876 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1877 # main U-Boot tree. All three should have the same postions and offset.
1878 start = 0
1879 for item in ['', 'spl', 'tpl']:
1880 dtb = fdt.Fdt.FromData(data[start:])
1881 dtb.Scan()
Simon Glass12bb1a92019-07-20 12:23:51 -06001882 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
1883 ['spl', 'tpl'])
Simon Glass6ed45ba2018-09-14 04:57:24 -06001884 expected = dict(base_expected)
1885 if item:
1886 expected[item] = 0
1887 self.assertEqual(expected, props)
1888 start += dtb._fdt_obj.totalsize()
1889
1890 def testUpdateFdtOutput(self):
1891 """Test that output DTB files are updated"""
1892 try:
Simon Glass741f2d62018-10-01 12:22:30 -06001893 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glass6ed45ba2018-09-14 04:57:24 -06001894 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1895
1896 # Unfortunately, compiling a source file always results in a file
1897 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass741f2d62018-10-01 12:22:30 -06001898 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glass6ed45ba2018-09-14 04:57:24 -06001899 # binman as a file called u-boot.dtb. To fix this, copy the file
1900 # over to the expected place.
Simon Glass6ed45ba2018-09-14 04:57:24 -06001901 start = 0
1902 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1903 'tpl/u-boot-tpl.dtb.out']:
1904 dtb = fdt.Fdt.FromData(data[start:])
1905 size = dtb._fdt_obj.totalsize()
1906 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1907 outdata = tools.ReadFile(pathname)
1908 name = os.path.split(fname)[0]
1909
1910 if name:
1911 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1912 else:
1913 orig_indata = dtb_data
1914 self.assertNotEqual(outdata, orig_indata,
1915 "Expected output file '%s' be updated" % pathname)
1916 self.assertEqual(outdata, data[start:start + size],
1917 "Expected output file '%s' to match output image" %
1918 pathname)
1919 start += size
1920 finally:
1921 self._ResetDtbs()
1922
Simon Glass83d73c22018-09-14 04:57:26 -06001923 def _decompress(self, data):
Simon Glass0d1e95a2022-01-09 20:14:04 -07001924 return comp_util.decompress(data, 'lz4')
Simon Glass83d73c22018-09-14 04:57:26 -06001925
1926 def testCompress(self):
1927 """Test compression of blobs"""
Simon Glassac62fba2019-07-08 13:18:53 -06001928 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06001929 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass83d73c22018-09-14 04:57:26 -06001930 use_real_dtb=True, update_dtb=True)
1931 dtb = fdt.Fdt(out_dtb_fname)
1932 dtb.Scan()
1933 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1934 orig = self._decompress(data)
1935 self.assertEquals(COMPRESS_DATA, orig)
Simon Glass97c3e9a2020-10-26 17:40:15 -06001936
1937 # Do a sanity check on various fields
1938 image = control.images['image']
1939 entries = image.GetEntries()
1940 self.assertEqual(1, len(entries))
1941
1942 entry = entries['blob']
1943 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
1944 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
1945 orig = self._decompress(entry.data)
1946 self.assertEqual(orig, entry.uncomp_data)
1947
Simon Glass63e7ba62020-10-26 17:40:16 -06001948 self.assertEqual(image.data, entry.data)
1949
Simon Glass83d73c22018-09-14 04:57:26 -06001950 expected = {
1951 'blob:uncomp-size': len(COMPRESS_DATA),
1952 'blob:size': len(data),
1953 'size': len(data),
1954 }
1955 self.assertEqual(expected, props)
1956
Simon Glass0a98b282018-09-14 04:57:28 -06001957 def testFiles(self):
1958 """Test bringing in multiple files"""
Simon Glass741f2d62018-10-01 12:22:30 -06001959 data = self._DoReadFile('084_files.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001960 self.assertEqual(FILES_DATA, data)
1961
1962 def testFilesCompress(self):
1963 """Test bringing in multiple files and compressing them"""
Simon Glassac62fba2019-07-08 13:18:53 -06001964 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06001965 data = self._DoReadFile('085_files_compress.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001966
1967 image = control.images['image']
1968 entries = image.GetEntries()
1969 files = entries['files']
Simon Glass8beb11e2019-07-08 14:25:47 -06001970 entries = files._entries
Simon Glass0a98b282018-09-14 04:57:28 -06001971
Simon Glassc6c10e72019-05-17 22:00:46 -06001972 orig = b''
Simon Glass0a98b282018-09-14 04:57:28 -06001973 for i in range(1, 3):
1974 key = '%d.dat' % i
1975 start = entries[key].image_pos
1976 len = entries[key].size
1977 chunk = data[start:start + len]
1978 orig += self._decompress(chunk)
1979
1980 self.assertEqual(FILES_DATA, orig)
1981
1982 def testFilesMissing(self):
1983 """Test missing files"""
1984 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001985 data = self._DoReadFile('086_files_none.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001986 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1987 'no files', str(e.exception))
1988
1989 def testFilesNoPattern(self):
1990 """Test missing files"""
1991 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001992 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001993 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1994 str(e.exception))
1995
Simon Glassba64a0b2018-09-14 04:57:29 -06001996 def testExpandSize(self):
1997 """Test an expanding entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001998 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
Simon Glassba64a0b2018-09-14 04:57:29 -06001999 map=True)
Simon Glassc6c10e72019-05-17 22:00:46 -06002000 expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA +
2001 MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA +
2002 tools.GetBytes(ord('c'), 8) + U_BOOT_DATA +
2003 tools.GetBytes(ord('d'), 8))
Simon Glassba64a0b2018-09-14 04:57:29 -06002004 self.assertEqual(expect, data)
2005 self.assertEqual('''ImagePos Offset Size Name
200600000000 00000000 00000028 main-section
200700000000 00000000 00000008 fill
200800000008 00000008 00000004 u-boot
20090000000c 0000000c 00000004 section
20100000000c 00000000 00000003 intel-mrc
201100000010 00000010 00000004 u-boot2
201200000014 00000014 0000000c section2
201300000014 00000000 00000008 fill
20140000001c 00000008 00000004 u-boot
201500000020 00000020 00000008 fill2
2016''', map_data)
2017
2018 def testExpandSizeBad(self):
2019 """Test an expanding entry which fails to provide contents"""
Simon Glass163ed6c2018-09-14 04:57:36 -06002020 with test_util.capture_sys_output() as (stdout, stderr):
2021 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002022 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
Simon Glassba64a0b2018-09-14 04:57:29 -06002023 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
2024 'expanding entry', str(e.exception))
2025
Simon Glasse0e5df92018-09-14 04:57:31 -06002026 def testHash(self):
2027 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06002028 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06002029 use_real_dtb=True, update_dtb=True)
2030 dtb = fdt.Fdt(out_dtb_fname)
2031 dtb.Scan()
2032 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
2033 m = hashlib.sha256()
2034 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06002035 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06002036
2037 def testHashNoAlgo(self):
2038 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002039 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06002040 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2041 'hash node', str(e.exception))
2042
2043 def testHashBadAlgo(self):
2044 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002045 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06002046 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
2047 str(e.exception))
2048
2049 def testHashSection(self):
2050 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06002051 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06002052 use_real_dtb=True, update_dtb=True)
2053 dtb = fdt.Fdt(out_dtb_fname)
2054 dtb.Scan()
2055 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2056 m = hashlib.sha256()
2057 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06002058 m.update(tools.GetBytes(ord('a'), 16))
2059 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06002060
Simon Glassf0253632018-09-14 04:57:32 -06002061 def testPackUBootTplMicrocode(self):
2062 """Test that x86 microcode can be handled correctly in TPL
2063
2064 We expect to see the following in the image, in order:
2065 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2066 place
2067 u-boot-tpl.dtb with the microcode removed
2068 the microcode
2069 """
Simon Glass2090f1e2019-08-24 07:23:00 -06002070 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass741f2d62018-10-01 12:22:30 -06002071 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glassf0253632018-09-14 04:57:32 -06002072 U_BOOT_TPL_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06002073 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2074 b'ter somewhere in here', first)
Simon Glassf0253632018-09-14 04:57:32 -06002075
Simon Glassf8f8df62018-09-14 04:57:34 -06002076 def testFmapX86(self):
2077 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06002078 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassf8f8df62018-09-14 04:57:34 -06002079 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc6c10e72019-05-17 22:00:46 -06002080 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06002081 self.assertEqual(expected, data[:32])
2082 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2083
2084 self.assertEqual(0x100, fhdr.image_size)
2085
2086 self.assertEqual(0, fentries[0].offset)
2087 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06002088 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06002089
2090 self.assertEqual(4, fentries[1].offset)
2091 self.assertEqual(3, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06002092 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06002093
2094 self.assertEqual(32, fentries[2].offset)
2095 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2096 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06002097 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06002098
2099 def testFmapX86Section(self):
2100 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06002101 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glassc6c10e72019-05-17 22:00:46 -06002102 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06002103 self.assertEqual(expected, data[:32])
2104 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2105
Simon Glass17365752021-04-03 11:05:10 +13002106 self.assertEqual(0x180, fhdr.image_size)
2107 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
Simon Glassc7722e82021-04-03 11:05:09 +13002108 fiter = iter(fentries)
Simon Glassf8f8df62018-09-14 04:57:34 -06002109
Simon Glassc7722e82021-04-03 11:05:09 +13002110 fentry = next(fiter)
2111 self.assertEqual(b'U_BOOT', fentry.name)
2112 self.assertEqual(0, fentry.offset)
2113 self.assertEqual(4, fentry.size)
Simon Glassf8f8df62018-09-14 04:57:34 -06002114
Simon Glassc7722e82021-04-03 11:05:09 +13002115 fentry = next(fiter)
Simon Glass17365752021-04-03 11:05:10 +13002116 self.assertEqual(b'SECTION', fentry.name)
2117 self.assertEqual(4, fentry.offset)
2118 self.assertEqual(0x20 + expect_size, fentry.size)
2119
2120 fentry = next(fiter)
Simon Glassc7722e82021-04-03 11:05:09 +13002121 self.assertEqual(b'INTEL_MRC', fentry.name)
2122 self.assertEqual(4, fentry.offset)
2123 self.assertEqual(3, fentry.size)
Simon Glassf8f8df62018-09-14 04:57:34 -06002124
Simon Glassc7722e82021-04-03 11:05:09 +13002125 fentry = next(fiter)
2126 self.assertEqual(b'FMAP', fentry.name)
2127 self.assertEqual(36, fentry.offset)
2128 self.assertEqual(expect_size, fentry.size)
Simon Glassf8f8df62018-09-14 04:57:34 -06002129
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002130 def testElf(self):
2131 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06002132 self._SetupSplElf()
Simon Glass2090f1e2019-08-24 07:23:00 -06002133 self._SetupTplElf()
Simon Glass53e22bf2019-08-24 07:22:53 -06002134 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002135 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06002136 data = self._DoReadFile('096_elf.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002137
Simon Glass093d1682019-07-08 13:18:25 -06002138 def testElfStrip(self):
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002139 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06002140 self._SetupSplElf()
Simon Glass53e22bf2019-08-24 07:22:53 -06002141 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002142 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06002143 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002144
Simon Glass163ed6c2018-09-14 04:57:36 -06002145 def testPackOverlapMap(self):
2146 """Test that overlapping regions are detected"""
2147 with test_util.capture_sys_output() as (stdout, stderr):
2148 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002149 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glass163ed6c2018-09-14 04:57:36 -06002150 map_fname = tools.GetOutputFilename('image.map')
2151 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2152 stdout.getvalue())
2153
2154 # We should not get an inmage, but there should be a map file
2155 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
2156 self.assertTrue(os.path.exists(map_fname))
Simon Glasseb546ac2019-05-17 22:00:51 -06002157 map_data = tools.ReadFile(map_fname, binary=False)
Simon Glass163ed6c2018-09-14 04:57:36 -06002158 self.assertEqual('''ImagePos Offset Size Name
Simon Glass0ff83da2020-10-26 17:40:24 -06002159<none> 00000000 00000008 main-section
Simon Glass163ed6c2018-09-14 04:57:36 -06002160<none> 00000000 00000004 u-boot
2161<none> 00000003 00000004 u-boot-align
2162''', map_data)
2163
Simon Glass093d1682019-07-08 13:18:25 -06002164 def testPackRefCode(self):
Simon Glass3ae192c2018-10-01 12:22:31 -06002165 """Test that an image with an Intel Reference code binary works"""
2166 data = self._DoReadFile('100_intel_refcode.dts')
2167 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2168
Simon Glass9481c802019-04-25 21:58:39 -06002169 def testSectionOffset(self):
2170 """Tests use of a section with an offset"""
2171 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2172 map=True)
2173 self.assertEqual('''ImagePos Offset Size Name
217400000000 00000000 00000038 main-section
217500000004 00000004 00000010 section@0
217600000004 00000000 00000004 u-boot
217700000018 00000018 00000010 section@1
217800000018 00000000 00000004 u-boot
21790000002c 0000002c 00000004 section@2
21800000002c 00000000 00000004 u-boot
2181''', map_data)
2182 self.assertEqual(data,
Simon Glasse6d85ff2019-05-14 15:53:47 -06002183 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2184 tools.GetBytes(0x21, 12) +
2185 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2186 tools.GetBytes(0x61, 12) +
2187 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2188 tools.GetBytes(0x26, 8))
Simon Glass9481c802019-04-25 21:58:39 -06002189
Simon Glassac62fba2019-07-08 13:18:53 -06002190 def testCbfsRaw(self):
2191 """Test base handling of a Coreboot Filesystem (CBFS)
2192
2193 The exact contents of the CBFS is verified by similar tests in
2194 cbfs_util_test.py. The tests here merely check that the files added to
2195 the CBFS can be found in the final image.
2196 """
2197 data = self._DoReadFile('102_cbfs_raw.dts')
2198 size = 0xb0
2199
2200 cbfs = cbfs_util.CbfsReader(data)
2201 self.assertEqual(size, cbfs.rom_size)
2202
2203 self.assertIn('u-boot-dtb', cbfs.files)
2204 cfile = cbfs.files['u-boot-dtb']
2205 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2206
2207 def testCbfsArch(self):
2208 """Test on non-x86 architecture"""
2209 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2210 size = 0x100
2211
2212 cbfs = cbfs_util.CbfsReader(data)
2213 self.assertEqual(size, cbfs.rom_size)
2214
2215 self.assertIn('u-boot-dtb', cbfs.files)
2216 cfile = cbfs.files['u-boot-dtb']
2217 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2218
2219 def testCbfsStage(self):
2220 """Tests handling of a Coreboot Filesystem (CBFS)"""
2221 if not elf.ELF_TOOLS:
2222 self.skipTest('Python elftools not available')
2223 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2224 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2225 size = 0xb0
2226
2227 data = self._DoReadFile('104_cbfs_stage.dts')
2228 cbfs = cbfs_util.CbfsReader(data)
2229 self.assertEqual(size, cbfs.rom_size)
2230
2231 self.assertIn('u-boot', cbfs.files)
2232 cfile = cbfs.files['u-boot']
2233 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2234
2235 def testCbfsRawCompress(self):
2236 """Test handling of compressing raw files"""
2237 self._CheckLz4()
2238 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2239 size = 0x140
2240
2241 cbfs = cbfs_util.CbfsReader(data)
2242 self.assertIn('u-boot', cbfs.files)
2243 cfile = cbfs.files['u-boot']
2244 self.assertEqual(COMPRESS_DATA, cfile.data)
2245
2246 def testCbfsBadArch(self):
2247 """Test handling of a bad architecture"""
2248 with self.assertRaises(ValueError) as e:
2249 self._DoReadFile('106_cbfs_bad_arch.dts')
2250 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2251
2252 def testCbfsNoSize(self):
2253 """Test handling of a missing size property"""
2254 with self.assertRaises(ValueError) as e:
2255 self._DoReadFile('107_cbfs_no_size.dts')
2256 self.assertIn('entry must have a size property', str(e.exception))
2257
Simon Glasse2f04742021-11-23 11:03:54 -07002258 def testCbfsNoContents(self):
Simon Glassac62fba2019-07-08 13:18:53 -06002259 """Test handling of a CBFS entry which does not provide contentsy"""
2260 with self.assertRaises(ValueError) as e:
2261 self._DoReadFile('108_cbfs_no_contents.dts')
2262 self.assertIn('Could not complete processing of contents',
2263 str(e.exception))
2264
2265 def testCbfsBadCompress(self):
2266 """Test handling of a bad architecture"""
2267 with self.assertRaises(ValueError) as e:
2268 self._DoReadFile('109_cbfs_bad_compress.dts')
2269 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2270 str(e.exception))
2271
2272 def testCbfsNamedEntries(self):
2273 """Test handling of named entries"""
2274 data = self._DoReadFile('110_cbfs_name.dts')
2275
2276 cbfs = cbfs_util.CbfsReader(data)
2277 self.assertIn('FRED', cbfs.files)
2278 cfile1 = cbfs.files['FRED']
2279 self.assertEqual(U_BOOT_DATA, cfile1.data)
2280
2281 self.assertIn('hello', cbfs.files)
2282 cfile2 = cbfs.files['hello']
2283 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2284
Simon Glassc5ac1382019-07-08 13:18:54 -06002285 def _SetupIfwi(self, fname):
2286 """Set up to run an IFWI test
2287
2288 Args:
2289 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2290 """
2291 self._SetupSplElf()
Simon Glass2090f1e2019-08-24 07:23:00 -06002292 self._SetupTplElf()
Simon Glassc5ac1382019-07-08 13:18:54 -06002293
2294 # Intel Integrated Firmware Image (IFWI) file
2295 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2296 data = fd.read()
2297 TestFunctional._MakeInputFile(fname,data)
2298
2299 def _CheckIfwi(self, data):
2300 """Check that an image with an IFWI contains the correct output
2301
2302 Args:
2303 data: Conents of output file
2304 """
2305 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
2306 if data[:0x1000] != expected_desc:
2307 self.fail('Expected descriptor binary at start of image')
2308
2309 # We expect to find the TPL wil in subpart IBBP entry IBBL
2310 image_fname = tools.GetOutputFilename('image.bin')
2311 tpl_fname = tools.GetOutputFilename('tpl.out')
Simon Glass532ae702022-01-09 20:14:01 -07002312 ifwitool = bintool.Bintool.create('ifwitool')
2313 ifwitool.extract(image_fname, 'IBBP', 'IBBL', tpl_fname)
Simon Glassc5ac1382019-07-08 13:18:54 -06002314
2315 tpl_data = tools.ReadFile(tpl_fname)
Simon Glasse95be632019-08-24 07:22:51 -06002316 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glassc5ac1382019-07-08 13:18:54 -06002317
2318 def testPackX86RomIfwi(self):
2319 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2320 self._SetupIfwi('fitimage.bin')
Simon Glass9255f3c2019-08-24 07:23:01 -06002321 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002322 self._CheckIfwi(data)
2323
2324 def testPackX86RomIfwiNoDesc(self):
2325 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2326 self._SetupIfwi('ifwi.bin')
Simon Glass9255f3c2019-08-24 07:23:01 -06002327 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002328 self._CheckIfwi(data)
2329
2330 def testPackX86RomIfwiNoData(self):
2331 """Test that an x86 ROM with IFWI handles missing data"""
2332 self._SetupIfwi('ifwi.bin')
2333 with self.assertRaises(ValueError) as e:
Simon Glass9255f3c2019-08-24 07:23:01 -06002334 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002335 self.assertIn('Could not complete processing of contents',
2336 str(e.exception))
Simon Glass53af22a2018-07-17 13:25:32 -06002337
Simon Glasse073d4e2019-07-08 13:18:56 -06002338 def testCbfsOffset(self):
2339 """Test a CBFS with files at particular offsets
2340
2341 Like all CFBS tests, this is just checking the logic that calls
2342 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2343 """
2344 data = self._DoReadFile('114_cbfs_offset.dts')
2345 size = 0x200
2346
2347 cbfs = cbfs_util.CbfsReader(data)
2348 self.assertEqual(size, cbfs.rom_size)
2349
2350 self.assertIn('u-boot', cbfs.files)
2351 cfile = cbfs.files['u-boot']
2352 self.assertEqual(U_BOOT_DATA, cfile.data)
2353 self.assertEqual(0x40, cfile.cbfs_offset)
2354
2355 self.assertIn('u-boot-dtb', cbfs.files)
2356 cfile2 = cbfs.files['u-boot-dtb']
2357 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2358 self.assertEqual(0x140, cfile2.cbfs_offset)
2359
Simon Glass086cec92019-07-08 14:25:27 -06002360 def testFdtmap(self):
2361 """Test an FDT map can be inserted in the image"""
2362 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2363 fdtmap_data = data[len(U_BOOT_DATA):]
2364 magic = fdtmap_data[:8]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002365 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass086cec92019-07-08 14:25:27 -06002366 self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
2367
2368 fdt_data = fdtmap_data[16:]
2369 dtb = fdt.Fdt.FromData(fdt_data)
2370 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002371 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass086cec92019-07-08 14:25:27 -06002372 self.assertEqual({
2373 'image-pos': 0,
2374 'offset': 0,
2375 'u-boot:offset': 0,
2376 'u-boot:size': len(U_BOOT_DATA),
2377 'u-boot:image-pos': 0,
2378 'fdtmap:image-pos': 4,
2379 'fdtmap:offset': 4,
2380 'fdtmap:size': len(fdtmap_data),
2381 'size': len(data),
2382 }, props)
2383
2384 def testFdtmapNoMatch(self):
2385 """Check handling of an FDT map when the section cannot be found"""
2386 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2387
2388 # Mangle the section name, which should cause a mismatch between the
2389 # correct FDT path and the one expected by the section
2390 image = control.images['image']
Simon Glasscf228942019-07-08 14:25:28 -06002391 image._node.path += '-suffix'
Simon Glass086cec92019-07-08 14:25:27 -06002392 entries = image.GetEntries()
2393 fdtmap = entries['fdtmap']
2394 with self.assertRaises(ValueError) as e:
2395 fdtmap._GetFdtmap()
2396 self.assertIn("Cannot locate node for path '/binman-suffix'",
2397 str(e.exception))
2398
Simon Glasscf228942019-07-08 14:25:28 -06002399 def testFdtmapHeader(self):
2400 """Test an FDT map and image header can be inserted in the image"""
2401 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2402 fdtmap_pos = len(U_BOOT_DATA)
2403 fdtmap_data = data[fdtmap_pos:]
2404 fdt_data = fdtmap_data[16:]
2405 dtb = fdt.Fdt.FromData(fdt_data)
2406 fdt_size = dtb.GetFdtObj().totalsize()
2407 hdr_data = data[-8:]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002408 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002409 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2410 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2411
2412 def testFdtmapHeaderStart(self):
2413 """Test an image header can be inserted at the image start"""
2414 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2415 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2416 hdr_data = data[:8]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002417 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002418 offset = struct.unpack('<I', hdr_data[4:])[0]
2419 self.assertEqual(fdtmap_pos, offset)
2420
2421 def testFdtmapHeaderPos(self):
2422 """Test an image header can be inserted at a chosen position"""
2423 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2424 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2425 hdr_data = data[0x80:0x88]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002426 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002427 offset = struct.unpack('<I', hdr_data[4:])[0]
2428 self.assertEqual(fdtmap_pos, offset)
2429
2430 def testHeaderMissingFdtmap(self):
2431 """Test an image header requires an fdtmap"""
2432 with self.assertRaises(ValueError) as e:
2433 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2434 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2435 str(e.exception))
2436
2437 def testHeaderNoLocation(self):
2438 """Test an image header with a no specified location is detected"""
2439 with self.assertRaises(ValueError) as e:
2440 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2441 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2442 str(e.exception))
2443
Simon Glassc52c9e72019-07-08 14:25:37 -06002444 def testEntryExpand(self):
2445 """Test expanding an entry after it is packed"""
2446 data = self._DoReadFile('121_entry_expand.dts')
Simon Glass79d3c582019-07-20 12:23:57 -06002447 self.assertEqual(b'aaa', data[:3])
2448 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2449 self.assertEqual(b'aaa', data[-3:])
Simon Glassc52c9e72019-07-08 14:25:37 -06002450
2451 def testEntryExpandBad(self):
2452 """Test expanding an entry after it is packed, twice"""
2453 with self.assertRaises(ValueError) as e:
2454 self._DoReadFile('122_entry_expand_twice.dts')
Simon Glass61ec04f2019-07-20 12:23:58 -06002455 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glassc52c9e72019-07-08 14:25:37 -06002456 str(e.exception))
2457
2458 def testEntryExpandSection(self):
2459 """Test expanding an entry within a section after it is packed"""
2460 data = self._DoReadFile('123_entry_expand_section.dts')
Simon Glass79d3c582019-07-20 12:23:57 -06002461 self.assertEqual(b'aaa', data[:3])
2462 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2463 self.assertEqual(b'aaa', data[-3:])
Simon Glassc52c9e72019-07-08 14:25:37 -06002464
Simon Glass6c223fd2019-07-08 14:25:38 -06002465 def testCompressDtb(self):
2466 """Test that compress of device-tree files is supported"""
2467 self._CheckLz4()
2468 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2469 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2470 comp_data = data[len(U_BOOT_DATA):]
2471 orig = self._decompress(comp_data)
2472 dtb = fdt.Fdt.FromData(orig)
2473 dtb.Scan()
2474 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2475 expected = {
2476 'u-boot:size': len(U_BOOT_DATA),
2477 'u-boot-dtb:uncomp-size': len(orig),
2478 'u-boot-dtb:size': len(comp_data),
2479 'size': len(data),
2480 }
2481 self.assertEqual(expected, props)
2482
Simon Glass69f7cb32019-07-08 14:25:41 -06002483 def testCbfsUpdateFdt(self):
2484 """Test that we can update the device tree with CBFS offset/size info"""
2485 self._CheckLz4()
2486 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2487 update_dtb=True)
2488 dtb = fdt.Fdt(out_dtb_fname)
2489 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002490 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass69f7cb32019-07-08 14:25:41 -06002491 del props['cbfs/u-boot:size']
2492 self.assertEqual({
2493 'offset': 0,
2494 'size': len(data),
2495 'image-pos': 0,
2496 'cbfs:offset': 0,
2497 'cbfs:size': len(data),
2498 'cbfs:image-pos': 0,
2499 'cbfs/u-boot:offset': 0x38,
2500 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2501 'cbfs/u-boot:image-pos': 0x38,
2502 'cbfs/u-boot-dtb:offset': 0xb8,
2503 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2504 'cbfs/u-boot-dtb:image-pos': 0xb8,
2505 }, props)
2506
Simon Glass8a1ad062019-07-08 14:25:42 -06002507 def testCbfsBadType(self):
2508 """Test an image header with a no specified location is detected"""
2509 with self.assertRaises(ValueError) as e:
2510 self._DoReadFile('126_cbfs_bad_type.dts')
2511 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2512
Simon Glass41b8ba02019-07-08 14:25:43 -06002513 def testList(self):
2514 """Test listing the files in an image"""
2515 self._CheckLz4()
2516 data = self._DoReadFile('127_list.dts')
2517 image = control.images['image']
2518 entries = image.BuildEntryList()
2519 self.assertEqual(7, len(entries))
2520
2521 ent = entries[0]
2522 self.assertEqual(0, ent.indent)
2523 self.assertEqual('main-section', ent.name)
2524 self.assertEqual('section', ent.etype)
2525 self.assertEqual(len(data), ent.size)
2526 self.assertEqual(0, ent.image_pos)
2527 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002528 self.assertEqual(0, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002529
2530 ent = entries[1]
2531 self.assertEqual(1, ent.indent)
2532 self.assertEqual('u-boot', ent.name)
2533 self.assertEqual('u-boot', ent.etype)
2534 self.assertEqual(len(U_BOOT_DATA), ent.size)
2535 self.assertEqual(0, ent.image_pos)
2536 self.assertEqual(None, ent.uncomp_size)
2537 self.assertEqual(0, ent.offset)
2538
2539 ent = entries[2]
2540 self.assertEqual(1, ent.indent)
2541 self.assertEqual('section', ent.name)
2542 self.assertEqual('section', ent.etype)
2543 section_size = ent.size
2544 self.assertEqual(0x100, ent.image_pos)
2545 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002546 self.assertEqual(0x100, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002547
2548 ent = entries[3]
2549 self.assertEqual(2, ent.indent)
2550 self.assertEqual('cbfs', ent.name)
2551 self.assertEqual('cbfs', ent.etype)
2552 self.assertEqual(0x400, ent.size)
2553 self.assertEqual(0x100, ent.image_pos)
2554 self.assertEqual(None, ent.uncomp_size)
2555 self.assertEqual(0, ent.offset)
2556
2557 ent = entries[4]
2558 self.assertEqual(3, ent.indent)
2559 self.assertEqual('u-boot', ent.name)
2560 self.assertEqual('u-boot', ent.etype)
2561 self.assertEqual(len(U_BOOT_DATA), ent.size)
2562 self.assertEqual(0x138, ent.image_pos)
2563 self.assertEqual(None, ent.uncomp_size)
2564 self.assertEqual(0x38, ent.offset)
2565
2566 ent = entries[5]
2567 self.assertEqual(3, ent.indent)
2568 self.assertEqual('u-boot-dtb', ent.name)
2569 self.assertEqual('text', ent.etype)
2570 self.assertGreater(len(COMPRESS_DATA), ent.size)
2571 self.assertEqual(0x178, ent.image_pos)
2572 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2573 self.assertEqual(0x78, ent.offset)
2574
2575 ent = entries[6]
2576 self.assertEqual(2, ent.indent)
2577 self.assertEqual('u-boot-dtb', ent.name)
2578 self.assertEqual('u-boot-dtb', ent.etype)
2579 self.assertEqual(0x500, ent.image_pos)
2580 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2581 dtb_size = ent.size
2582 # Compressing this data expands it since headers are added
2583 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2584 self.assertEqual(0x400, ent.offset)
2585
2586 self.assertEqual(len(data), 0x100 + section_size)
2587 self.assertEqual(section_size, 0x400 + dtb_size)
2588
Simon Glasse1925fa2019-07-08 14:25:44 -06002589 def testFindFdtmap(self):
2590 """Test locating an FDT map in an image"""
2591 self._CheckLz4()
2592 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2593 image = control.images['image']
2594 entries = image.GetEntries()
2595 entry = entries['fdtmap']
2596 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2597
2598 def testFindFdtmapMissing(self):
2599 """Test failing to locate an FDP map"""
2600 data = self._DoReadFile('005_simple.dts')
2601 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2602
Simon Glass2d260032019-07-08 14:25:45 -06002603 def testFindImageHeader(self):
2604 """Test locating a image header"""
2605 self._CheckLz4()
Simon Glassffded752019-07-08 14:25:46 -06002606 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002607 image = control.images['image']
2608 entries = image.GetEntries()
2609 entry = entries['fdtmap']
2610 # The header should point to the FDT map
2611 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2612
2613 def testFindImageHeaderStart(self):
2614 """Test locating a image header located at the start of an image"""
Simon Glassffded752019-07-08 14:25:46 -06002615 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002616 image = control.images['image']
2617 entries = image.GetEntries()
2618 entry = entries['fdtmap']
2619 # The header should point to the FDT map
2620 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2621
2622 def testFindImageHeaderMissing(self):
2623 """Test failing to locate an image header"""
2624 data = self._DoReadFile('005_simple.dts')
2625 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2626
Simon Glassffded752019-07-08 14:25:46 -06002627 def testReadImage(self):
2628 """Test reading an image and accessing its FDT map"""
2629 self._CheckLz4()
2630 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2631 image_fname = tools.GetOutputFilename('image.bin')
2632 orig_image = control.images['image']
2633 image = Image.FromFile(image_fname)
2634 self.assertEqual(orig_image.GetEntries().keys(),
2635 image.GetEntries().keys())
2636
2637 orig_entry = orig_image.GetEntries()['fdtmap']
2638 entry = image.GetEntries()['fdtmap']
2639 self.assertEquals(orig_entry.offset, entry.offset)
2640 self.assertEquals(orig_entry.size, entry.size)
2641 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2642
2643 def testReadImageNoHeader(self):
2644 """Test accessing an image's FDT map without an image header"""
2645 self._CheckLz4()
2646 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
2647 image_fname = tools.GetOutputFilename('image.bin')
2648 image = Image.FromFile(image_fname)
2649 self.assertTrue(isinstance(image, Image))
Simon Glass10f9d002019-07-20 12:23:50 -06002650 self.assertEqual('image', image.image_name[-5:])
Simon Glassffded752019-07-08 14:25:46 -06002651
2652 def testReadImageFail(self):
2653 """Test failing to read an image image's FDT map"""
2654 self._DoReadFile('005_simple.dts')
2655 image_fname = tools.GetOutputFilename('image.bin')
2656 with self.assertRaises(ValueError) as e:
2657 image = Image.FromFile(image_fname)
2658 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glasse073d4e2019-07-08 13:18:56 -06002659
Simon Glass61f564d2019-07-08 14:25:48 -06002660 def testListCmd(self):
2661 """Test listing the files in an image using an Fdtmap"""
2662 self._CheckLz4()
2663 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2664
2665 # lz4 compression size differs depending on the version
2666 image = control.images['image']
2667 entries = image.GetEntries()
2668 section_size = entries['section'].size
2669 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2670 fdtmap_offset = entries['fdtmap'].offset
2671
Simon Glassf86a7362019-07-20 12:24:10 -06002672 try:
2673 tmpdir, updated_fname = self._SetupImageInTmpdir()
2674 with test_util.capture_sys_output() as (stdout, stderr):
2675 self._DoBinman('ls', '-i', updated_fname)
2676 finally:
2677 shutil.rmtree(tmpdir)
Simon Glass61f564d2019-07-08 14:25:48 -06002678 lines = stdout.getvalue().splitlines()
2679 expected = [
2680'Name Image-pos Size Entry-type Offset Uncomp-size',
2681'----------------------------------------------------------------------',
2682'main-section 0 c00 section 0',
2683' u-boot 0 4 u-boot 0',
2684' section 100 %x section 100' % section_size,
2685' cbfs 100 400 cbfs 0',
2686' u-boot 138 4 u-boot 38',
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002687' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glass61f564d2019-07-08 14:25:48 -06002688' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002689' fdtmap %x 3bd fdtmap %x' %
Simon Glass61f564d2019-07-08 14:25:48 -06002690 (fdtmap_offset, fdtmap_offset),
2691' image-header bf8 8 image-header bf8',
2692 ]
2693 self.assertEqual(expected, lines)
2694
2695 def testListCmdFail(self):
2696 """Test failing to list an image"""
2697 self._DoReadFile('005_simple.dts')
Simon Glassf86a7362019-07-20 12:24:10 -06002698 try:
2699 tmpdir, updated_fname = self._SetupImageInTmpdir()
2700 with self.assertRaises(ValueError) as e:
2701 self._DoBinman('ls', '-i', updated_fname)
2702 finally:
2703 shutil.rmtree(tmpdir)
Simon Glass61f564d2019-07-08 14:25:48 -06002704 self.assertIn("Cannot find FDT map in image", str(e.exception))
2705
2706 def _RunListCmd(self, paths, expected):
2707 """List out entries and check the result
2708
2709 Args:
2710 paths: List of paths to pass to the list command
2711 expected: Expected list of filenames to be returned, in order
2712 """
2713 self._CheckLz4()
2714 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2715 image_fname = tools.GetOutputFilename('image.bin')
2716 image = Image.FromFile(image_fname)
2717 lines = image.GetListEntries(paths)[1]
2718 files = [line[0].strip() for line in lines[1:]]
2719 self.assertEqual(expected, files)
2720
2721 def testListCmdSection(self):
2722 """Test listing the files in a section"""
2723 self._RunListCmd(['section'],
2724 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2725
2726 def testListCmdFile(self):
2727 """Test listing a particular file"""
2728 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2729
2730 def testListCmdWildcard(self):
2731 """Test listing a wildcarded file"""
2732 self._RunListCmd(['*boot*'],
2733 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2734
2735 def testListCmdWildcardMulti(self):
2736 """Test listing a wildcarded file"""
2737 self._RunListCmd(['*cb*', '*head*'],
2738 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2739
2740 def testListCmdEmpty(self):
2741 """Test listing a wildcarded file"""
2742 self._RunListCmd(['nothing'], [])
2743
2744 def testListCmdPath(self):
2745 """Test listing the files in a sub-entry of a section"""
2746 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2747
Simon Glassf667e452019-07-08 14:25:50 -06002748 def _RunExtractCmd(self, entry_name, decomp=True):
2749 """Extract an entry from an image
2750
2751 Args:
2752 entry_name: Entry name to extract
2753 decomp: True to decompress the data if compressed, False to leave
2754 it in its raw uncompressed format
2755
2756 Returns:
2757 data from entry
2758 """
2759 self._CheckLz4()
2760 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2761 image_fname = tools.GetOutputFilename('image.bin')
2762 return control.ReadEntry(image_fname, entry_name, decomp)
2763
2764 def testExtractSimple(self):
2765 """Test extracting a single file"""
2766 data = self._RunExtractCmd('u-boot')
2767 self.assertEqual(U_BOOT_DATA, data)
2768
Simon Glass71ce0ba2019-07-08 14:25:52 -06002769 def testExtractSection(self):
2770 """Test extracting the files in a section"""
2771 data = self._RunExtractCmd('section')
2772 cbfs_data = data[:0x400]
2773 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002774 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass71ce0ba2019-07-08 14:25:52 -06002775 dtb_data = data[0x400:]
2776 dtb = self._decompress(dtb_data)
2777 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2778
2779 def testExtractCompressed(self):
2780 """Test extracting compressed data"""
2781 data = self._RunExtractCmd('section/u-boot-dtb')
2782 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2783
2784 def testExtractRaw(self):
2785 """Test extracting compressed data without decompressing it"""
2786 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2787 dtb = self._decompress(data)
2788 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2789
2790 def testExtractCbfs(self):
2791 """Test extracting CBFS data"""
2792 data = self._RunExtractCmd('section/cbfs/u-boot')
2793 self.assertEqual(U_BOOT_DATA, data)
2794
2795 def testExtractCbfsCompressed(self):
2796 """Test extracting CBFS compressed data"""
2797 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2798 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2799
2800 def testExtractCbfsRaw(self):
2801 """Test extracting CBFS compressed data without decompressing it"""
2802 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Simon Glass0d1e95a2022-01-09 20:14:04 -07002803 dtb = comp_util.decompress(data, 'lzma', with_header=False)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002804 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2805
Simon Glassf667e452019-07-08 14:25:50 -06002806 def testExtractBadEntry(self):
2807 """Test extracting a bad section path"""
2808 with self.assertRaises(ValueError) as e:
2809 self._RunExtractCmd('section/does-not-exist')
2810 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2811 str(e.exception))
2812
2813 def testExtractMissingFile(self):
2814 """Test extracting file that does not exist"""
2815 with self.assertRaises(IOError) as e:
2816 control.ReadEntry('missing-file', 'name')
2817
2818 def testExtractBadFile(self):
2819 """Test extracting an invalid file"""
2820 fname = os.path.join(self._indir, 'badfile')
2821 tools.WriteFile(fname, b'')
2822 with self.assertRaises(ValueError) as e:
2823 control.ReadEntry(fname, 'name')
2824
Simon Glass71ce0ba2019-07-08 14:25:52 -06002825 def testExtractCmd(self):
2826 """Test extracting a file fron an image on the command line"""
2827 self._CheckLz4()
2828 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass71ce0ba2019-07-08 14:25:52 -06002829 fname = os.path.join(self._indir, 'output.extact')
Simon Glassf86a7362019-07-20 12:24:10 -06002830 try:
2831 tmpdir, updated_fname = self._SetupImageInTmpdir()
2832 with test_util.capture_sys_output() as (stdout, stderr):
2833 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2834 '-f', fname)
2835 finally:
2836 shutil.rmtree(tmpdir)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002837 data = tools.ReadFile(fname)
2838 self.assertEqual(U_BOOT_DATA, data)
2839
2840 def testExtractOneEntry(self):
2841 """Test extracting a single entry fron an image """
2842 self._CheckLz4()
2843 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2844 image_fname = tools.GetOutputFilename('image.bin')
2845 fname = os.path.join(self._indir, 'output.extact')
2846 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
2847 data = tools.ReadFile(fname)
2848 self.assertEqual(U_BOOT_DATA, data)
2849
2850 def _CheckExtractOutput(self, decomp):
2851 """Helper to test file output with and without decompression
2852
2853 Args:
2854 decomp: True to decompress entry data, False to output it raw
2855 """
2856 def _CheckPresent(entry_path, expect_data, expect_size=None):
2857 """Check and remove expected file
2858
2859 This checks the data/size of a file and removes the file both from
2860 the outfiles set and from the output directory. Once all files are
2861 processed, both the set and directory should be empty.
2862
2863 Args:
2864 entry_path: Entry path
2865 expect_data: Data to expect in file, or None to skip check
2866 expect_size: Size of data to expect in file, or None to skip
2867 """
2868 path = os.path.join(outdir, entry_path)
2869 data = tools.ReadFile(path)
2870 os.remove(path)
2871 if expect_data:
2872 self.assertEqual(expect_data, data)
2873 elif expect_size:
2874 self.assertEqual(expect_size, len(data))
2875 outfiles.remove(path)
2876
2877 def _CheckDirPresent(name):
2878 """Remove expected directory
2879
2880 This gives an error if the directory does not exist as expected
2881
2882 Args:
2883 name: Name of directory to remove
2884 """
2885 path = os.path.join(outdir, name)
2886 os.rmdir(path)
2887
2888 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2889 image_fname = tools.GetOutputFilename('image.bin')
2890 outdir = os.path.join(self._indir, 'extract')
2891 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2892
2893 # Create a set of all file that were output (should be 9)
2894 outfiles = set()
2895 for root, dirs, files in os.walk(outdir):
2896 outfiles |= set([os.path.join(root, fname) for fname in files])
2897 self.assertEqual(9, len(outfiles))
2898 self.assertEqual(9, len(einfos))
2899
2900 image = control.images['image']
2901 entries = image.GetEntries()
2902
2903 # Check the 9 files in various ways
2904 section = entries['section']
2905 section_entries = section.GetEntries()
2906 cbfs_entries = section_entries['cbfs'].GetEntries()
2907 _CheckPresent('u-boot', U_BOOT_DATA)
2908 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
2909 dtb_len = EXTRACT_DTB_SIZE
2910 if not decomp:
2911 dtb_len = cbfs_entries['u-boot-dtb'].size
2912 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
2913 if not decomp:
2914 dtb_len = section_entries['u-boot-dtb'].size
2915 _CheckPresent('section/u-boot-dtb', None, dtb_len)
2916
2917 fdtmap = entries['fdtmap']
2918 _CheckPresent('fdtmap', fdtmap.data)
2919 hdr = entries['image-header']
2920 _CheckPresent('image-header', hdr.data)
2921
2922 _CheckPresent('section/root', section.data)
2923 cbfs = section_entries['cbfs']
2924 _CheckPresent('section/cbfs/root', cbfs.data)
2925 data = tools.ReadFile(image_fname)
2926 _CheckPresent('root', data)
2927
2928 # There should be no files left. Remove all the directories to check.
2929 # If there are any files/dirs remaining, one of these checks will fail.
2930 self.assertEqual(0, len(outfiles))
2931 _CheckDirPresent('section/cbfs')
2932 _CheckDirPresent('section')
2933 _CheckDirPresent('')
2934 self.assertFalse(os.path.exists(outdir))
2935
2936 def testExtractAllEntries(self):
2937 """Test extracting all entries"""
2938 self._CheckLz4()
2939 self._CheckExtractOutput(decomp=True)
2940
2941 def testExtractAllEntriesRaw(self):
2942 """Test extracting all entries without decompressing them"""
2943 self._CheckLz4()
2944 self._CheckExtractOutput(decomp=False)
2945
2946 def testExtractSelectedEntries(self):
2947 """Test extracting some entries"""
2948 self._CheckLz4()
2949 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2950 image_fname = tools.GetOutputFilename('image.bin')
2951 outdir = os.path.join(self._indir, 'extract')
2952 einfos = control.ExtractEntries(image_fname, None, outdir,
2953 ['*cb*', '*head*'])
2954
2955 # File output is tested by testExtractAllEntries(), so just check that
2956 # the expected entries are selected
2957 names = [einfo.name for einfo in einfos]
2958 self.assertEqual(names,
2959 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2960
2961 def testExtractNoEntryPaths(self):
2962 """Test extracting some entries"""
2963 self._CheckLz4()
2964 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2965 image_fname = tools.GetOutputFilename('image.bin')
2966 with self.assertRaises(ValueError) as e:
2967 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassbb5edc12019-07-20 12:24:14 -06002968 self.assertIn('Must specify an entry path to write with -f',
Simon Glass71ce0ba2019-07-08 14:25:52 -06002969 str(e.exception))
2970
2971 def testExtractTooManyEntryPaths(self):
2972 """Test extracting some entries"""
2973 self._CheckLz4()
2974 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2975 image_fname = tools.GetOutputFilename('image.bin')
2976 with self.assertRaises(ValueError) as e:
2977 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassbb5edc12019-07-20 12:24:14 -06002978 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass71ce0ba2019-07-08 14:25:52 -06002979 str(e.exception))
2980
Simon Glasse2705fa2019-07-08 14:25:53 -06002981 def testPackAlignSection(self):
2982 """Test that sections can have alignment"""
2983 self._DoReadFile('131_pack_align_section.dts')
2984
2985 self.assertIn('image', control.images)
2986 image = control.images['image']
2987 entries = image.GetEntries()
2988 self.assertEqual(3, len(entries))
2989
2990 # First u-boot
2991 self.assertIn('u-boot', entries)
2992 entry = entries['u-boot']
2993 self.assertEqual(0, entry.offset)
2994 self.assertEqual(0, entry.image_pos)
2995 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2996 self.assertEqual(len(U_BOOT_DATA), entry.size)
2997
2998 # Section0
2999 self.assertIn('section0', entries)
3000 section0 = entries['section0']
3001 self.assertEqual(0x10, section0.offset)
3002 self.assertEqual(0x10, section0.image_pos)
3003 self.assertEqual(len(U_BOOT_DATA), section0.size)
3004
3005 # Second u-boot
3006 section_entries = section0.GetEntries()
3007 self.assertIn('u-boot', section_entries)
3008 entry = section_entries['u-boot']
3009 self.assertEqual(0, entry.offset)
3010 self.assertEqual(0x10, entry.image_pos)
3011 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3012 self.assertEqual(len(U_BOOT_DATA), entry.size)
3013
3014 # Section1
3015 self.assertIn('section1', entries)
3016 section1 = entries['section1']
3017 self.assertEqual(0x14, section1.offset)
3018 self.assertEqual(0x14, section1.image_pos)
3019 self.assertEqual(0x20, section1.size)
3020
3021 # Second u-boot
3022 section_entries = section1.GetEntries()
3023 self.assertIn('u-boot', section_entries)
3024 entry = section_entries['u-boot']
3025 self.assertEqual(0, entry.offset)
3026 self.assertEqual(0x14, entry.image_pos)
3027 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3028 self.assertEqual(len(U_BOOT_DATA), entry.size)
3029
3030 # Section2
3031 self.assertIn('section2', section_entries)
3032 section2 = section_entries['section2']
3033 self.assertEqual(0x4, section2.offset)
3034 self.assertEqual(0x18, section2.image_pos)
3035 self.assertEqual(4, section2.size)
3036
3037 # Third u-boot
3038 section_entries = section2.GetEntries()
3039 self.assertIn('u-boot', section_entries)
3040 entry = section_entries['u-boot']
3041 self.assertEqual(0, entry.offset)
3042 self.assertEqual(0x18, entry.image_pos)
3043 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3044 self.assertEqual(len(U_BOOT_DATA), entry.size)
3045
Simon Glass51014aa2019-07-20 12:23:56 -06003046 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3047 dts='132_replace.dts'):
Simon Glass10f9d002019-07-20 12:23:50 -06003048 """Replace an entry in an image
3049
3050 This writes the entry data to update it, then opens the updated file and
3051 returns the value that it now finds there.
3052
3053 Args:
3054 entry_name: Entry name to replace
3055 data: Data to replace it with
3056 decomp: True to compress the data if needed, False if data is
3057 already compressed so should be used as is
Simon Glass51014aa2019-07-20 12:23:56 -06003058 allow_resize: True to allow entries to change size, False to raise
3059 an exception
Simon Glass10f9d002019-07-20 12:23:50 -06003060
3061 Returns:
3062 Tuple:
3063 data from entry
3064 data from fdtmap (excluding header)
Simon Glass51014aa2019-07-20 12:23:56 -06003065 Image object that was modified
Simon Glass10f9d002019-07-20 12:23:50 -06003066 """
Simon Glass51014aa2019-07-20 12:23:56 -06003067 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass10f9d002019-07-20 12:23:50 -06003068 update_dtb=True)[1]
3069
3070 self.assertIn('image', control.images)
3071 image = control.images['image']
3072 entries = image.GetEntries()
3073 orig_dtb_data = entries['u-boot-dtb'].data
3074 orig_fdtmap_data = entries['fdtmap'].data
3075
3076 image_fname = tools.GetOutputFilename('image.bin')
3077 updated_fname = tools.GetOutputFilename('image-updated.bin')
3078 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
Simon Glass51014aa2019-07-20 12:23:56 -06003079 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3080 allow_resize)
Simon Glass10f9d002019-07-20 12:23:50 -06003081 data = control.ReadEntry(updated_fname, entry_name, decomp)
3082
Simon Glass51014aa2019-07-20 12:23:56 -06003083 # The DT data should not change unless resized:
3084 if not allow_resize:
3085 new_dtb_data = entries['u-boot-dtb'].data
3086 self.assertEqual(new_dtb_data, orig_dtb_data)
3087 new_fdtmap_data = entries['fdtmap'].data
3088 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass10f9d002019-07-20 12:23:50 -06003089
Simon Glass51014aa2019-07-20 12:23:56 -06003090 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass10f9d002019-07-20 12:23:50 -06003091
3092 def testReplaceSimple(self):
3093 """Test replacing a single file"""
3094 expected = b'x' * len(U_BOOT_DATA)
Simon Glass51014aa2019-07-20 12:23:56 -06003095 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3096 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06003097 self.assertEqual(expected, data)
3098
3099 # Test that the state looks right. There should be an FDT for the fdtmap
3100 # that we jsut read back in, and it should match what we find in the
3101 # 'control' tables. Checking for an FDT that does not exist should
3102 # return None.
3103 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glass51014aa2019-07-20 12:23:56 -06003104 self.assertIsNotNone(path)
Simon Glass10f9d002019-07-20 12:23:50 -06003105 self.assertEqual(expected_fdtmap, fdtmap)
3106
3107 dtb = state.GetFdtForEtype('fdtmap')
3108 self.assertEqual(dtb.GetContents(), fdtmap)
3109
3110 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3111 self.assertIsNone(missing_path)
3112 self.assertIsNone(missing_fdtmap)
3113
3114 missing_dtb = state.GetFdtForEtype('missing')
3115 self.assertIsNone(missing_dtb)
3116
3117 self.assertEqual('/binman', state.fdt_path_prefix)
3118
3119 def testReplaceResizeFail(self):
3120 """Test replacing a file by something larger"""
3121 expected = U_BOOT_DATA + b'x'
3122 with self.assertRaises(ValueError) as e:
Simon Glass51014aa2019-07-20 12:23:56 -06003123 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3124 dts='139_replace_repack.dts')
Simon Glass10f9d002019-07-20 12:23:50 -06003125 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3126 str(e.exception))
3127
3128 def testReplaceMulti(self):
3129 """Test replacing entry data where multiple images are generated"""
3130 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3131 update_dtb=True)[0]
3132 expected = b'x' * len(U_BOOT_DATA)
3133 updated_fname = tools.GetOutputFilename('image-updated.bin')
3134 tools.WriteFile(updated_fname, data)
3135 entry_name = 'u-boot'
Simon Glass51014aa2019-07-20 12:23:56 -06003136 control.WriteEntry(updated_fname, entry_name, expected,
3137 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06003138 data = control.ReadEntry(updated_fname, entry_name)
3139 self.assertEqual(expected, data)
3140
3141 # Check the state looks right.
3142 self.assertEqual('/binman/image', state.fdt_path_prefix)
3143
3144 # Now check we can write the first image
3145 image_fname = tools.GetOutputFilename('first-image.bin')
3146 updated_fname = tools.GetOutputFilename('first-updated.bin')
3147 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
3148 entry_name = 'u-boot'
Simon Glass51014aa2019-07-20 12:23:56 -06003149 control.WriteEntry(updated_fname, entry_name, expected,
3150 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06003151 data = control.ReadEntry(updated_fname, entry_name)
3152 self.assertEqual(expected, data)
3153
3154 # Check the state looks right.
3155 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass8beb11e2019-07-08 14:25:47 -06003156
Simon Glass12bb1a92019-07-20 12:23:51 -06003157 def testUpdateFdtAllRepack(self):
3158 """Test that all device trees are updated with offset/size info"""
3159 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3160 SECTION_SIZE = 0x300
3161 DTB_SIZE = 602
3162 FDTMAP_SIZE = 608
3163 base_expected = {
3164 'offset': 0,
3165 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3166 'image-pos': 0,
3167 'section:offset': 0,
3168 'section:size': SECTION_SIZE,
3169 'section:image-pos': 0,
3170 'section/u-boot-dtb:offset': 4,
3171 'section/u-boot-dtb:size': 636,
3172 'section/u-boot-dtb:image-pos': 4,
3173 'u-boot-spl-dtb:offset': SECTION_SIZE,
3174 'u-boot-spl-dtb:size': DTB_SIZE,
3175 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3176 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3177 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3178 'u-boot-tpl-dtb:size': DTB_SIZE,
3179 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3180 'fdtmap:size': FDTMAP_SIZE,
3181 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3182 }
3183 main_expected = {
3184 'section:orig-size': SECTION_SIZE,
3185 'section/u-boot-dtb:orig-offset': 4,
3186 }
3187
3188 # We expect three device-tree files in the output, with the first one
3189 # within a fixed-size section.
3190 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3191 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3192 # main U-Boot tree. All three should have the same positions and offset
3193 # except that the main tree should include the main_expected properties
3194 start = 4
3195 for item in ['', 'spl', 'tpl', None]:
3196 if item is None:
3197 start += 16 # Move past fdtmap header
3198 dtb = fdt.Fdt.FromData(data[start:])
3199 dtb.Scan()
3200 props = self._GetPropTree(dtb,
3201 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3202 prefix='/' if item is None else '/binman/')
3203 expected = dict(base_expected)
3204 if item:
3205 expected[item] = 0
3206 else:
3207 # Main DTB and fdtdec should include the 'orig-' properties
3208 expected.update(main_expected)
3209 # Helpful for debugging:
3210 #for prop in sorted(props):
3211 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3212 self.assertEqual(expected, props)
3213 if item == '':
3214 start = SECTION_SIZE
3215 else:
3216 start += dtb._fdt_obj.totalsize()
3217
Simon Glasseba1f0c2019-07-20 12:23:55 -06003218 def testFdtmapHeaderMiddle(self):
3219 """Test an FDT map in the middle of an image when it should be at end"""
3220 with self.assertRaises(ValueError) as e:
3221 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3222 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3223 str(e.exception))
3224
3225 def testFdtmapHeaderStartBad(self):
3226 """Test an FDT map in middle of an image when it should be at start"""
3227 with self.assertRaises(ValueError) as e:
3228 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3229 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3230 str(e.exception))
3231
3232 def testFdtmapHeaderEndBad(self):
3233 """Test an FDT map at the start of an image when it should be at end"""
3234 with self.assertRaises(ValueError) as e:
3235 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3236 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3237 str(e.exception))
3238
3239 def testFdtmapHeaderNoSize(self):
3240 """Test an image header at the end of an image with undefined size"""
3241 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3242
Simon Glass51014aa2019-07-20 12:23:56 -06003243 def testReplaceResize(self):
3244 """Test replacing a single file in an entry with a larger file"""
3245 expected = U_BOOT_DATA + b'x'
3246 data, _, image = self._RunReplaceCmd('u-boot', expected,
3247 dts='139_replace_repack.dts')
3248 self.assertEqual(expected, data)
3249
3250 entries = image.GetEntries()
3251 dtb_data = entries['u-boot-dtb'].data
3252 dtb = fdt.Fdt.FromData(dtb_data)
3253 dtb.Scan()
3254
3255 # The u-boot section should now be larger in the dtb
3256 node = dtb.GetNode('/binman/u-boot')
3257 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3258
3259 # Same for the fdtmap
3260 fdata = entries['fdtmap'].data
3261 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3262 fdtb.Scan()
3263 fnode = fdtb.GetNode('/u-boot')
3264 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3265
3266 def testReplaceResizeNoRepack(self):
3267 """Test replacing an entry with a larger file when not allowed"""
3268 expected = U_BOOT_DATA + b'x'
3269 with self.assertRaises(ValueError) as e:
3270 self._RunReplaceCmd('u-boot', expected)
3271 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3272 str(e.exception))
3273
Simon Glass61ec04f2019-07-20 12:23:58 -06003274 def testEntryShrink(self):
3275 """Test contracting an entry after it is packed"""
3276 try:
3277 state.SetAllowEntryContraction(True)
3278 data = self._DoReadFileDtb('140_entry_shrink.dts',
3279 update_dtb=True)[0]
3280 finally:
3281 state.SetAllowEntryContraction(False)
3282 self.assertEqual(b'a', data[:1])
3283 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3284 self.assertEqual(b'a', data[-1:])
3285
3286 def testEntryShrinkFail(self):
3287 """Test not being allowed to contract an entry after it is packed"""
3288 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3289
3290 # In this case there is a spare byte at the end of the data. The size of
3291 # the contents is only 1 byte but we still have the size before it
3292 # shrunk.
3293 self.assertEqual(b'a\0', data[:2])
3294 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3295 self.assertEqual(b'a\0', data[-2:])
3296
Simon Glass27145fd2019-07-20 12:24:01 -06003297 def testDescriptorOffset(self):
3298 """Test that the Intel descriptor is always placed at at the start"""
3299 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3300 image = control.images['image']
3301 entries = image.GetEntries()
3302 desc = entries['intel-descriptor']
3303 self.assertEqual(0xff800000, desc.offset);
3304 self.assertEqual(0xff800000, desc.image_pos);
3305
Simon Glasseb0f4a42019-07-20 12:24:06 -06003306 def testReplaceCbfs(self):
3307 """Test replacing a single file in CBFS without changing the size"""
3308 self._CheckLz4()
3309 expected = b'x' * len(U_BOOT_DATA)
3310 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3311 updated_fname = tools.GetOutputFilename('image-updated.bin')
3312 tools.WriteFile(updated_fname, data)
3313 entry_name = 'section/cbfs/u-boot'
3314 control.WriteEntry(updated_fname, entry_name, expected,
3315 allow_resize=True)
3316 data = control.ReadEntry(updated_fname, entry_name)
3317 self.assertEqual(expected, data)
3318
3319 def testReplaceResizeCbfs(self):
3320 """Test replacing a single file in CBFS with one of a different size"""
3321 self._CheckLz4()
3322 expected = U_BOOT_DATA + b'x'
3323 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3324 updated_fname = tools.GetOutputFilename('image-updated.bin')
3325 tools.WriteFile(updated_fname, data)
3326 entry_name = 'section/cbfs/u-boot'
3327 control.WriteEntry(updated_fname, entry_name, expected,
3328 allow_resize=True)
3329 data = control.ReadEntry(updated_fname, entry_name)
3330 self.assertEqual(expected, data)
3331
Simon Glassa6cb9952019-07-20 12:24:15 -06003332 def _SetupForReplace(self):
3333 """Set up some files to use to replace entries
3334
3335 This generates an image, copies it to a new file, extracts all the files
3336 in it and updates some of them
3337
3338 Returns:
3339 List
3340 Image filename
3341 Output directory
3342 Expected values for updated entries, each a string
3343 """
3344 data = self._DoReadFileRealDtb('143_replace_all.dts')
3345
3346 updated_fname = tools.GetOutputFilename('image-updated.bin')
3347 tools.WriteFile(updated_fname, data)
3348
3349 outdir = os.path.join(self._indir, 'extract')
3350 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3351
3352 expected1 = b'x' + U_BOOT_DATA + b'y'
3353 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3354 tools.WriteFile(u_boot_fname1, expected1)
3355
3356 expected2 = b'a' + U_BOOT_DATA + b'b'
3357 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
3358 tools.WriteFile(u_boot_fname2, expected2)
3359
3360 expected_text = b'not the same text'
3361 text_fname = os.path.join(outdir, 'text')
3362 tools.WriteFile(text_fname, expected_text)
3363
3364 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3365 dtb = fdt.FdtScan(dtb_fname)
3366 node = dtb.GetNode('/binman/text')
3367 node.AddString('my-property', 'the value')
3368 dtb.Sync(auto_resize=True)
3369 dtb.Flush()
3370
3371 return updated_fname, outdir, expected1, expected2, expected_text
3372
3373 def _CheckReplaceMultiple(self, entry_paths):
3374 """Handle replacing the contents of multiple entries
3375
3376 Args:
3377 entry_paths: List of entry paths to replace
3378
3379 Returns:
3380 List
3381 Dict of entries in the image:
3382 key: Entry name
3383 Value: Entry object
3384 Expected values for updated entries, each a string
3385 """
3386 updated_fname, outdir, expected1, expected2, expected_text = (
3387 self._SetupForReplace())
3388 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3389
3390 image = Image.FromFile(updated_fname)
3391 image.LoadData()
3392 return image.GetEntries(), expected1, expected2, expected_text
3393
3394 def testReplaceAll(self):
3395 """Test replacing the contents of all entries"""
3396 entries, expected1, expected2, expected_text = (
3397 self._CheckReplaceMultiple([]))
3398 data = entries['u-boot'].data
3399 self.assertEqual(expected1, data)
3400
3401 data = entries['u-boot2'].data
3402 self.assertEqual(expected2, data)
3403
3404 data = entries['text'].data
3405 self.assertEqual(expected_text, data)
3406
3407 # Check that the device tree is updated
3408 data = entries['u-boot-dtb'].data
3409 dtb = fdt.Fdt.FromData(data)
3410 dtb.Scan()
3411 node = dtb.GetNode('/binman/text')
3412 self.assertEqual('the value', node.props['my-property'].value)
3413
3414 def testReplaceSome(self):
3415 """Test replacing the contents of a few entries"""
3416 entries, expected1, expected2, expected_text = (
3417 self._CheckReplaceMultiple(['u-boot2', 'text']))
3418
3419 # This one should not change
3420 data = entries['u-boot'].data
3421 self.assertEqual(U_BOOT_DATA, data)
3422
3423 data = entries['u-boot2'].data
3424 self.assertEqual(expected2, data)
3425
3426 data = entries['text'].data
3427 self.assertEqual(expected_text, data)
3428
3429 def testReplaceCmd(self):
3430 """Test replacing a file fron an image on the command line"""
3431 self._DoReadFileRealDtb('143_replace_all.dts')
3432
3433 try:
3434 tmpdir, updated_fname = self._SetupImageInTmpdir()
3435
3436 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3437 expected = b'x' * len(U_BOOT_DATA)
3438 tools.WriteFile(fname, expected)
3439
3440 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
3441 data = tools.ReadFile(updated_fname)
3442 self.assertEqual(expected, data[:len(expected)])
3443 map_fname = os.path.join(tmpdir, 'image-updated.map')
3444 self.assertFalse(os.path.exists(map_fname))
3445 finally:
3446 shutil.rmtree(tmpdir)
3447
3448 def testReplaceCmdSome(self):
3449 """Test replacing some files fron an image on the command line"""
3450 updated_fname, outdir, expected1, expected2, expected_text = (
3451 self._SetupForReplace())
3452
3453 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3454 'u-boot2', 'text')
3455
3456 tools.PrepareOutputDir(None)
3457 image = Image.FromFile(updated_fname)
3458 image.LoadData()
3459 entries = image.GetEntries()
3460
3461 # This one should not change
3462 data = entries['u-boot'].data
3463 self.assertEqual(U_BOOT_DATA, data)
3464
3465 data = entries['u-boot2'].data
3466 self.assertEqual(expected2, data)
3467
3468 data = entries['text'].data
3469 self.assertEqual(expected_text, data)
3470
3471 def testReplaceMissing(self):
3472 """Test replacing entries where the file is missing"""
3473 updated_fname, outdir, expected1, expected2, expected_text = (
3474 self._SetupForReplace())
3475
3476 # Remove one of the files, to generate a warning
3477 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3478 os.remove(u_boot_fname1)
3479
3480 with test_util.capture_sys_output() as (stdout, stderr):
3481 control.ReplaceEntries(updated_fname, None, outdir, [])
3482 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass38fdb4c2020-07-09 18:39:39 -06003483 stderr.getvalue())
Simon Glassa6cb9952019-07-20 12:24:15 -06003484
3485 def testReplaceCmdMap(self):
3486 """Test replacing a file fron an image on the command line"""
3487 self._DoReadFileRealDtb('143_replace_all.dts')
3488
3489 try:
3490 tmpdir, updated_fname = self._SetupImageInTmpdir()
3491
3492 fname = os.path.join(self._indir, 'update-u-boot.bin')
3493 expected = b'x' * len(U_BOOT_DATA)
3494 tools.WriteFile(fname, expected)
3495
3496 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3497 '-f', fname, '-m')
3498 map_fname = os.path.join(tmpdir, 'image-updated.map')
3499 self.assertTrue(os.path.exists(map_fname))
3500 finally:
3501 shutil.rmtree(tmpdir)
3502
3503 def testReplaceNoEntryPaths(self):
3504 """Test replacing an entry without an entry path"""
3505 self._DoReadFileRealDtb('143_replace_all.dts')
3506 image_fname = tools.GetOutputFilename('image.bin')
3507 with self.assertRaises(ValueError) as e:
3508 control.ReplaceEntries(image_fname, 'fname', None, [])
3509 self.assertIn('Must specify an entry path to read with -f',
3510 str(e.exception))
3511
3512 def testReplaceTooManyEntryPaths(self):
3513 """Test extracting some entries"""
3514 self._DoReadFileRealDtb('143_replace_all.dts')
3515 image_fname = tools.GetOutputFilename('image.bin')
3516 with self.assertRaises(ValueError) as e:
3517 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3518 self.assertIn('Must specify exactly one entry path to write with -f',
3519 str(e.exception))
3520
Simon Glass2250ee62019-08-24 07:22:48 -06003521 def testPackReset16(self):
3522 """Test that an image with an x86 reset16 region can be created"""
3523 data = self._DoReadFile('144_x86_reset16.dts')
3524 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3525
3526 def testPackReset16Spl(self):
3527 """Test that an image with an x86 reset16-spl region can be created"""
3528 data = self._DoReadFile('145_x86_reset16_spl.dts')
3529 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3530
3531 def testPackReset16Tpl(self):
3532 """Test that an image with an x86 reset16-tpl region can be created"""
3533 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3534 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3535
Simon Glass5af12072019-08-24 07:22:50 -06003536 def testPackIntelFit(self):
3537 """Test that an image with an Intel FIT and pointer can be created"""
3538 data = self._DoReadFile('147_intel_fit.dts')
3539 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3540 fit = data[16:32];
3541 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3542 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3543
3544 image = control.images['image']
3545 entries = image.GetEntries()
3546 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3547 self.assertEqual(expected_ptr, ptr)
3548
3549 def testPackIntelFitMissing(self):
3550 """Test detection of a FIT pointer with not FIT region"""
3551 with self.assertRaises(ValueError) as e:
3552 self._DoReadFile('148_intel_fit_missing.dts')
3553 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3554 str(e.exception))
3555
Simon Glass7c150132019-11-06 17:22:44 -07003556 def _CheckSymbolsTplSection(self, dts, expected_vals):
3557 data = self._DoReadFile(dts)
3558 sym_values = struct.pack('<LQLL', *expected_vals)
Simon Glass2090f1e2019-08-24 07:23:00 -06003559 upto1 = 4 + len(U_BOOT_SPL_DATA)
Simon Glassb87064c2019-08-24 07:23:05 -06003560 expected1 = tools.GetBytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[20:]
Simon Glass2090f1e2019-08-24 07:23:00 -06003561 self.assertEqual(expected1, data[:upto1])
3562
3563 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Simon Glassb87064c2019-08-24 07:23:05 -06003564 expected2 = tools.GetBytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[20:]
Simon Glass2090f1e2019-08-24 07:23:00 -06003565 self.assertEqual(expected2, data[upto1:upto2])
3566
Simon Glasseb0086f2019-08-24 07:23:04 -06003567 upto3 = 0x34 + len(U_BOOT_DATA)
3568 expected3 = tools.GetBytes(0xff, 1) + U_BOOT_DATA
Simon Glass2090f1e2019-08-24 07:23:00 -06003569 self.assertEqual(expected3, data[upto2:upto3])
3570
Simon Glassb87064c2019-08-24 07:23:05 -06003571 expected4 = sym_values + U_BOOT_TPL_DATA[20:]
Simon Glass7c150132019-11-06 17:22:44 -07003572 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3573
3574 def testSymbolsTplSection(self):
3575 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3576 self._SetupSplElf('u_boot_binman_syms')
3577 self._SetupTplElf('u_boot_binman_syms')
3578 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
3579 [0x04, 0x1c, 0x10 + 0x34, 0x04])
3580
3581 def testSymbolsTplSectionX86(self):
3582 """Test binman can assign symbols in a section with end-at-4gb"""
3583 self._SetupSplElf('u_boot_binman_syms_x86')
3584 self._SetupTplElf('u_boot_binman_syms_x86')
3585 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
3586 [0xffffff04, 0xffffff1c, 0xffffff34,
3587 0x04])
Simon Glass2090f1e2019-08-24 07:23:00 -06003588
Simon Glassbf4d0e22019-08-24 07:23:03 -06003589 def testPackX86RomIfwiSectiom(self):
3590 """Test that a section can be placed in an IFWI region"""
3591 self._SetupIfwi('fitimage.bin')
3592 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3593 self._CheckIfwi(data)
3594
Simon Glassea0fff92019-08-24 07:23:07 -06003595 def testPackFspM(self):
3596 """Test that an image with a FSP memory-init binary can be created"""
3597 data = self._DoReadFile('152_intel_fsp_m.dts')
3598 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3599
Simon Glassbc6a88f2019-10-20 21:31:35 -06003600 def testPackFspS(self):
3601 """Test that an image with a FSP silicon-init binary can be created"""
3602 data = self._DoReadFile('153_intel_fsp_s.dts')
3603 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassea0fff92019-08-24 07:23:07 -06003604
Simon Glass998d1482019-10-20 21:31:36 -06003605 def testPackFspT(self):
3606 """Test that an image with a FSP temp-ram-init binary can be created"""
3607 data = self._DoReadFile('154_intel_fsp_t.dts')
3608 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3609
Simon Glass0dc706f2020-07-09 18:39:31 -06003610 def testMkimage(self):
3611 """Test using mkimage to build an image"""
3612 data = self._DoReadFile('156_mkimage.dts')
3613
3614 # Just check that the data appears in the file somewhere
3615 self.assertIn(U_BOOT_SPL_DATA, data)
3616
Simon Glassce867ad2020-07-09 18:39:36 -06003617 def testExtblob(self):
3618 """Test an image with an external blob"""
3619 data = self._DoReadFile('157_blob_ext.dts')
3620 self.assertEqual(REFCODE_DATA, data)
3621
3622 def testExtblobMissing(self):
3623 """Test an image with a missing external blob"""
3624 with self.assertRaises(ValueError) as e:
3625 self._DoReadFile('158_blob_ext_missing.dts')
3626 self.assertIn("Filename 'missing-file' not found in input path",
3627 str(e.exception))
3628
Simon Glass4f9f1052020-07-09 18:39:38 -06003629 def testExtblobMissingOk(self):
3630 """Test an image with an missing external blob that is allowed"""
Simon Glassb1cca952020-07-09 18:39:40 -06003631 with test_util.capture_sys_output() as (stdout, stderr):
3632 self._DoTestFile('158_blob_ext_missing.dts', allow_missing=True)
3633 err = stderr.getvalue()
3634 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
3635
3636 def testExtblobMissingOkSect(self):
3637 """Test an image with an missing external blob that is allowed"""
3638 with test_util.capture_sys_output() as (stdout, stderr):
3639 self._DoTestFile('159_blob_ext_missing_sect.dts',
3640 allow_missing=True)
3641 err = stderr.getvalue()
3642 self.assertRegex(err, "Image 'main-section'.*missing.*: "
3643 "blob-ext blob-ext2")
Simon Glass4f9f1052020-07-09 18:39:38 -06003644
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003645 def testPackX86RomMeMissingDesc(self):
3646 """Test that an missing Intel descriptor entry is allowed"""
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003647 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass52b10dd2020-07-25 15:11:19 -06003648 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003649 err = stderr.getvalue()
3650 self.assertRegex(err,
3651 "Image 'main-section'.*missing.*: intel-descriptor")
3652
3653 def testPackX86RomMissingIfwi(self):
3654 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3655 self._SetupIfwi('fitimage.bin')
3656 pathname = os.path.join(self._indir, 'fitimage.bin')
3657 os.remove(pathname)
3658 with test_util.capture_sys_output() as (stdout, stderr):
3659 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3660 err = stderr.getvalue()
3661 self.assertRegex(err, "Image 'main-section'.*missing.*: intel-ifwi")
3662
Simon Glassb3295fd2020-07-09 18:39:42 -06003663 def testPackOverlap(self):
3664 """Test that zero-size overlapping regions are ignored"""
3665 self._DoTestFile('160_pack_overlap_zero.dts')
3666
Simon Glassfdc34362020-07-09 18:39:45 -06003667 def testSimpleFit(self):
3668 """Test an image with a FIT inside"""
3669 data = self._DoReadFile('161_fit.dts')
3670 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3671 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3672 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3673
3674 # The data should be inside the FIT
3675 dtb = fdt.Fdt.FromData(fit_data)
3676 dtb.Scan()
3677 fnode = dtb.GetNode('/images/kernel')
3678 self.assertIn('data', fnode.props)
3679
3680 fname = os.path.join(self._indir, 'fit_data.fit')
3681 tools.WriteFile(fname, fit_data)
3682 out = tools.Run('dumpimage', '-l', fname)
3683
3684 # Check a few features to make sure the plumbing works. We don't need
3685 # to test the operation of mkimage or dumpimage here. First convert the
3686 # output into a dict where the keys are the fields printed by dumpimage
3687 # and the values are a list of values for each field
3688 lines = out.splitlines()
3689
3690 # Converts "Compression: gzip compressed" into two groups:
3691 # 'Compression' and 'gzip compressed'
3692 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3693 vals = collections.defaultdict(list)
3694 for line in lines:
3695 mat = re_line.match(line)
3696 vals[mat.group(1)].append(mat.group(2))
3697
3698 self.assertEquals('FIT description: test-desc', lines[0])
3699 self.assertIn('Created:', lines[1])
3700 self.assertIn('Image 0 (kernel)', vals)
3701 self.assertIn('Hash value', vals)
3702 data_sizes = vals.get('Data Size')
3703 self.assertIsNotNone(data_sizes)
3704 self.assertEqual(2, len(data_sizes))
3705 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
3706 self.assertEqual(len(U_BOOT_DATA), int(data_sizes[0].split()[0]))
3707 self.assertEqual(len(U_BOOT_SPL_DTB_DATA), int(data_sizes[1].split()[0]))
3708
3709 def testFitExternal(self):
Simon Glasse9d336d2020-09-01 05:13:55 -06003710 """Test an image with an FIT with external images"""
Simon Glassfdc34362020-07-09 18:39:45 -06003711 data = self._DoReadFile('162_fit_external.dts')
3712 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3713
Simon Glass8bc78b72022-01-09 20:13:39 -07003714 # Size of the external-data region as set up by mkimage
3715 external_data_size = len(U_BOOT_DATA) + 2
3716 expected_size = (len(U_BOOT_DATA) + 0x400 +
3717 tools.Align(external_data_size, 4) +
3718 len(U_BOOT_NODTB_DATA))
3719
Simon Glassfdc34362020-07-09 18:39:45 -06003720 # The data should be outside the FIT
3721 dtb = fdt.Fdt.FromData(fit_data)
3722 dtb.Scan()
3723 fnode = dtb.GetNode('/images/kernel')
3724 self.assertNotIn('data', fnode.props)
Simon Glass8bc78b72022-01-09 20:13:39 -07003725 self.assertEqual(len(U_BOOT_DATA),
3726 fdt_util.fdt32_to_cpu(fnode.props['data-size'].value))
3727 fit_pos = 0x400;
3728 self.assertEqual(
3729 fit_pos,
3730 fdt_util.fdt32_to_cpu(fnode.props['data-position'].value))
3731
3732 self.assertEquals(expected_size, len(data))
3733 actual_pos = len(U_BOOT_DATA) + fit_pos
3734 self.assertEqual(U_BOOT_DATA + b'aa',
3735 data[actual_pos:actual_pos + external_data_size])
Simon Glass12bb1a92019-07-20 12:23:51 -06003736
Alper Nebi Yasak8001d0b2020-08-31 12:58:18 +03003737 def testSectionIgnoreHashSignature(self):
3738 """Test that sections ignore hash, signature nodes for its data"""
3739 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
3740 expected = (U_BOOT_DATA + U_BOOT_DATA)
3741 self.assertEqual(expected, data)
3742
Alper Nebi Yasak3fdeb142020-08-31 12:58:19 +03003743 def testPadInSections(self):
3744 """Test pad-before, pad-after for entries in sections"""
Simon Glassf90d9062020-10-26 17:40:09 -06003745 data, _, _, out_dtb_fname = self._DoReadFileDtb(
3746 '166_pad_in_sections.dts', update_dtb=True)
Alper Nebi Yasak3fdeb142020-08-31 12:58:19 +03003747 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
3748 U_BOOT_DATA + tools.GetBytes(ord('!'), 6) +
3749 U_BOOT_DATA)
3750 self.assertEqual(expected, data)
3751
Simon Glassf90d9062020-10-26 17:40:09 -06003752 dtb = fdt.Fdt(out_dtb_fname)
3753 dtb.Scan()
3754 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
3755 expected = {
3756 'image-pos': 0,
3757 'offset': 0,
3758 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
3759
3760 'section:image-pos': 0,
3761 'section:offset': 0,
3762 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
3763
3764 'section/before:image-pos': 0,
3765 'section/before:offset': 0,
3766 'section/before:size': len(U_BOOT_DATA),
3767
3768 'section/u-boot:image-pos': 4,
3769 'section/u-boot:offset': 4,
3770 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
3771
3772 'section/after:image-pos': 26,
3773 'section/after:offset': 26,
3774 'section/after:size': len(U_BOOT_DATA),
3775 }
3776 self.assertEqual(expected, props)
3777
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03003778 def testFitImageSubentryAlignment(self):
3779 """Test relative alignability of FIT image subentries"""
3780 entry_args = {
3781 'test-id': TEXT_DATA,
3782 }
3783 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
3784 entry_args=entry_args)
3785 dtb = fdt.Fdt.FromData(data)
3786 dtb.Scan()
3787
3788 node = dtb.GetNode('/images/kernel')
3789 data = dtb.GetProps(node)["data"].bytes
3790 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
3791 expected = (tools.GetBytes(0, 0x20) + U_BOOT_SPL_DATA +
3792 tools.GetBytes(0, align_pad) + U_BOOT_DATA)
3793 self.assertEqual(expected, data)
3794
3795 node = dtb.GetNode('/images/fdt-1')
3796 data = dtb.GetProps(node)["data"].bytes
3797 expected = (U_BOOT_SPL_DTB_DATA + tools.GetBytes(0, 20) +
3798 tools.ToBytes(TEXT_DATA) + tools.GetBytes(0, 30) +
3799 U_BOOT_DTB_DATA)
3800 self.assertEqual(expected, data)
3801
3802 def testFitExtblobMissingOk(self):
3803 """Test a FIT with a missing external blob that is allowed"""
3804 with test_util.capture_sys_output() as (stdout, stderr):
3805 self._DoTestFile('168_fit_missing_blob.dts',
3806 allow_missing=True)
3807 err = stderr.getvalue()
Simon Glassb2381432020-09-06 10:39:09 -06003808 self.assertRegex(err, "Image 'main-section'.*missing.*: atf-bl31")
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03003809
Simon Glass3decfa32020-09-01 05:13:54 -06003810 def testBlobNamedByArgMissing(self):
3811 """Test handling of a missing entry arg"""
3812 with self.assertRaises(ValueError) as e:
3813 self._DoReadFile('068_blob_named_by_arg.dts')
3814 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
3815 str(e.exception))
3816
Simon Glassdc2f81a2020-09-01 05:13:58 -06003817 def testPackBl31(self):
3818 """Test that an image with an ATF BL31 binary can be created"""
3819 data = self._DoReadFile('169_atf_bl31.dts')
3820 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
3821
Samuel Holland18bd4552020-10-21 21:12:15 -05003822 def testPackScp(self):
3823 """Test that an image with an SCP binary can be created"""
3824 data = self._DoReadFile('172_scp.dts')
3825 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
3826
Simon Glass6cf99532020-09-01 05:13:59 -06003827 def testFitFdt(self):
3828 """Test an image with an FIT with multiple FDT images"""
3829 def _CheckFdt(seq, expected_data):
3830 """Check the FDT nodes
3831
3832 Args:
3833 seq: Sequence number to check (0 or 1)
3834 expected_data: Expected contents of 'data' property
3835 """
3836 name = 'fdt-%d' % seq
3837 fnode = dtb.GetNode('/images/%s' % name)
3838 self.assertIsNotNone(fnode)
3839 self.assertEqual({'description','type', 'compression', 'data'},
3840 set(fnode.props.keys()))
3841 self.assertEqual(expected_data, fnode.props['data'].bytes)
3842 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
3843 fnode.props['description'].value)
3844
3845 def _CheckConfig(seq, expected_data):
3846 """Check the configuration nodes
3847
3848 Args:
3849 seq: Sequence number to check (0 or 1)
3850 expected_data: Expected contents of 'data' property
3851 """
3852 cnode = dtb.GetNode('/configurations')
3853 self.assertIn('default', cnode.props)
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003854 self.assertEqual('config-2', cnode.props['default'].value)
Simon Glass6cf99532020-09-01 05:13:59 -06003855
3856 name = 'config-%d' % seq
3857 fnode = dtb.GetNode('/configurations/%s' % name)
3858 self.assertIsNotNone(fnode)
3859 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
3860 set(fnode.props.keys()))
3861 self.assertEqual('conf-test-fdt%d.dtb' % seq,
3862 fnode.props['description'].value)
3863 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
3864
3865 entry_args = {
3866 'of-list': 'test-fdt1 test-fdt2',
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003867 'default-dt': 'test-fdt2',
Simon Glass6cf99532020-09-01 05:13:59 -06003868 }
3869 data = self._DoReadFileDtb(
Bin Mengaa75ce92021-05-10 20:23:32 +08003870 '170_fit_fdt.dts',
Simon Glass6cf99532020-09-01 05:13:59 -06003871 entry_args=entry_args,
3872 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3873 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3874 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3875
3876 dtb = fdt.Fdt.FromData(fit_data)
3877 dtb.Scan()
3878 fnode = dtb.GetNode('/images/kernel')
3879 self.assertIn('data', fnode.props)
3880
3881 # Check all the properties in fdt-1 and fdt-2
3882 _CheckFdt(1, TEST_FDT1_DATA)
3883 _CheckFdt(2, TEST_FDT2_DATA)
3884
3885 # Check configurations
3886 _CheckConfig(1, TEST_FDT1_DATA)
3887 _CheckConfig(2, TEST_FDT2_DATA)
3888
3889 def testFitFdtMissingList(self):
3890 """Test handling of a missing 'of-list' entry arg"""
3891 with self.assertRaises(ValueError) as e:
Bin Mengaa75ce92021-05-10 20:23:32 +08003892 self._DoReadFile('170_fit_fdt.dts')
Simon Glass6cf99532020-09-01 05:13:59 -06003893 self.assertIn("Generator node requires 'of-list' entry argument",
3894 str(e.exception))
3895
3896 def testFitFdtEmptyList(self):
3897 """Test handling of an empty 'of-list' entry arg"""
3898 entry_args = {
3899 'of-list': '',
3900 }
3901 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
3902
3903 def testFitFdtMissingProp(self):
3904 """Test handling of a missing 'fit,fdt-list' property"""
3905 with self.assertRaises(ValueError) as e:
3906 self._DoReadFile('171_fit_fdt_missing_prop.dts')
3907 self.assertIn("Generator node requires 'fit,fdt-list' property",
3908 str(e.exception))
Simon Glassdc2f81a2020-09-01 05:13:58 -06003909
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003910 def testFitFdtEmptyList(self):
3911 """Test handling of an empty 'of-list' entry arg"""
3912 entry_args = {
3913 'of-list': '',
3914 }
Bin Mengaa75ce92021-05-10 20:23:32 +08003915 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003916
3917 def testFitFdtMissing(self):
3918 """Test handling of a missing 'default-dt' entry arg"""
3919 entry_args = {
3920 'of-list': 'test-fdt1 test-fdt2',
3921 }
3922 with self.assertRaises(ValueError) as e:
3923 self._DoReadFileDtb(
Bin Mengaa75ce92021-05-10 20:23:32 +08003924 '170_fit_fdt.dts',
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003925 entry_args=entry_args,
3926 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3927 self.assertIn("Generated 'default' node requires default-dt entry argument",
3928 str(e.exception))
3929
3930 def testFitFdtNotInList(self):
3931 """Test handling of a default-dt that is not in the of-list"""
3932 entry_args = {
3933 'of-list': 'test-fdt1 test-fdt2',
3934 'default-dt': 'test-fdt3',
3935 }
3936 with self.assertRaises(ValueError) as e:
3937 self._DoReadFileDtb(
Bin Mengaa75ce92021-05-10 20:23:32 +08003938 '170_fit_fdt.dts',
Simon Glassc0f1ebe2020-09-06 10:39:08 -06003939 entry_args=entry_args,
3940 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3941 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
3942 str(e.exception))
3943
Simon Glassb2381432020-09-06 10:39:09 -06003944 def testFitExtblobMissingHelp(self):
3945 """Test display of help messages when an external blob is missing"""
3946 control.missing_blob_help = control._ReadMissingBlobHelp()
3947 control.missing_blob_help['wibble'] = 'Wibble test'
3948 control.missing_blob_help['another'] = 'Another test'
3949 with test_util.capture_sys_output() as (stdout, stderr):
3950 self._DoTestFile('168_fit_missing_blob.dts',
3951 allow_missing=True)
3952 err = stderr.getvalue()
3953
3954 # We can get the tag from the name, the type or the missing-msg
3955 # property. Check all three.
3956 self.assertIn('You may need to build ARM Trusted', err)
3957 self.assertIn('Wibble test', err)
3958 self.assertIn('Another test', err)
3959
Simon Glass204aa782020-09-06 10:35:32 -06003960 def testMissingBlob(self):
3961 """Test handling of a blob containing a missing file"""
3962 with self.assertRaises(ValueError) as e:
3963 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
3964 self.assertIn("Filename 'missing' not found in input path",
3965 str(e.exception))
3966
Simon Glassfb91d562020-09-06 10:35:33 -06003967 def testEnvironment(self):
3968 """Test adding a U-Boot environment"""
3969 data = self._DoReadFile('174_env.dts')
3970 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3971 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3972 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3973 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
3974 env)
3975
3976 def testEnvironmentNoSize(self):
3977 """Test that a missing 'size' property is detected"""
3978 with self.assertRaises(ValueError) as e:
Simon Glassa4dfe3e2020-10-26 17:40:00 -06003979 self._DoTestFile('175_env_no_size.dts')
Simon Glassfb91d562020-09-06 10:35:33 -06003980 self.assertIn("'u-boot-env' entry must have a size property",
3981 str(e.exception))
3982
3983 def testEnvironmentTooSmall(self):
3984 """Test handling of an environment that does not fit"""
3985 with self.assertRaises(ValueError) as e:
Simon Glassa4dfe3e2020-10-26 17:40:00 -06003986 self._DoTestFile('176_env_too_small.dts')
Simon Glassfb91d562020-09-06 10:35:33 -06003987
3988 # checksum, start byte, environment with \0 terminator, final \0
3989 need = 4 + 1 + len(ENV_DATA) + 1 + 1
3990 short = need - 0x8
3991 self.assertIn("too small to hold data (need %#x more bytes)" % short,
3992 str(e.exception))
3993
Simon Glassf2c0dd82020-10-26 17:40:01 -06003994 def testSkipAtStart(self):
3995 """Test handling of skip-at-start section"""
3996 data = self._DoReadFile('177_skip_at_start.dts')
3997 self.assertEqual(U_BOOT_DATA, data)
3998
3999 image = control.images['image']
4000 entries = image.GetEntries()
4001 section = entries['section']
4002 self.assertEqual(0, section.offset)
4003 self.assertEqual(len(U_BOOT_DATA), section.size)
4004 self.assertEqual(U_BOOT_DATA, section.GetData())
4005
4006 entry = section.GetEntries()['u-boot']
4007 self.assertEqual(16, entry.offset)
4008 self.assertEqual(len(U_BOOT_DATA), entry.size)
4009 self.assertEqual(U_BOOT_DATA, entry.data)
4010
4011 def testSkipAtStartPad(self):
4012 """Test handling of skip-at-start section with padded entry"""
4013 data = self._DoReadFile('178_skip_at_start_pad.dts')
4014 before = tools.GetBytes(0, 8)
4015 after = tools.GetBytes(0, 4)
4016 all = before + U_BOOT_DATA + after
4017 self.assertEqual(all, data)
4018
4019 image = control.images['image']
4020 entries = image.GetEntries()
4021 section = entries['section']
4022 self.assertEqual(0, section.offset)
4023 self.assertEqual(len(all), section.size)
4024 self.assertEqual(all, section.GetData())
4025
4026 entry = section.GetEntries()['u-boot']
4027 self.assertEqual(16, entry.offset)
4028 self.assertEqual(len(all), entry.size)
4029 self.assertEqual(U_BOOT_DATA, entry.data)
4030
4031 def testSkipAtStartSectionPad(self):
4032 """Test handling of skip-at-start section with padding"""
4033 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
4034 before = tools.GetBytes(0, 8)
4035 after = tools.GetBytes(0, 4)
4036 all = before + U_BOOT_DATA + after
Simon Glassd1d3ad72020-10-26 17:40:13 -06004037 self.assertEqual(all, data)
Simon Glassf2c0dd82020-10-26 17:40:01 -06004038
4039 image = control.images['image']
4040 entries = image.GetEntries()
4041 section = entries['section']
4042 self.assertEqual(0, section.offset)
4043 self.assertEqual(len(all), section.size)
Simon Glass63e7ba62020-10-26 17:40:16 -06004044 self.assertEqual(U_BOOT_DATA, section.data)
Simon Glassd1d3ad72020-10-26 17:40:13 -06004045 self.assertEqual(all, section.GetPaddedData())
Simon Glassf2c0dd82020-10-26 17:40:01 -06004046
4047 entry = section.GetEntries()['u-boot']
4048 self.assertEqual(16, entry.offset)
4049 self.assertEqual(len(U_BOOT_DATA), entry.size)
4050 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassfb91d562020-09-06 10:35:33 -06004051
Simon Glass7d398bb2020-10-26 17:40:14 -06004052 def testSectionPad(self):
4053 """Testing padding with sections"""
4054 data = self._DoReadFile('180_section_pad.dts')
4055 expected = (tools.GetBytes(ord('&'), 3) +
4056 tools.GetBytes(ord('!'), 5) +
4057 U_BOOT_DATA +
4058 tools.GetBytes(ord('!'), 1) +
4059 tools.GetBytes(ord('&'), 2))
4060 self.assertEqual(expected, data)
4061
4062 def testSectionAlign(self):
4063 """Testing alignment with sections"""
4064 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4065 expected = (b'\0' + # fill section
4066 tools.GetBytes(ord('&'), 1) + # padding to section align
4067 b'\0' + # fill section
4068 tools.GetBytes(ord('!'), 3) + # padding to u-boot align
4069 U_BOOT_DATA +
4070 tools.GetBytes(ord('!'), 4) + # padding to u-boot size
4071 tools.GetBytes(ord('!'), 4)) # padding to section size
4072 self.assertEqual(expected, data)
4073
Simon Glass8f5ef892020-10-26 17:40:25 -06004074 def testCompressImage(self):
4075 """Test compression of the entire image"""
4076 self._CheckLz4()
4077 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4078 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4079 dtb = fdt.Fdt(out_dtb_fname)
4080 dtb.Scan()
4081 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4082 'uncomp-size'])
4083 orig = self._decompress(data)
4084 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4085
4086 # Do a sanity check on various fields
4087 image = control.images['image']
4088 entries = image.GetEntries()
4089 self.assertEqual(2, len(entries))
4090
4091 entry = entries['blob']
4092 self.assertEqual(COMPRESS_DATA, entry.data)
4093 self.assertEqual(len(COMPRESS_DATA), entry.size)
4094
4095 entry = entries['u-boot']
4096 self.assertEqual(U_BOOT_DATA, entry.data)
4097 self.assertEqual(len(U_BOOT_DATA), entry.size)
4098
4099 self.assertEqual(len(data), image.size)
4100 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4101 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4102 orig = self._decompress(image.data)
4103 self.assertEqual(orig, image.uncomp_data)
4104
4105 expected = {
4106 'blob:offset': 0,
4107 'blob:size': len(COMPRESS_DATA),
4108 'u-boot:offset': len(COMPRESS_DATA),
4109 'u-boot:size': len(U_BOOT_DATA),
4110 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4111 'offset': 0,
4112 'image-pos': 0,
4113 'size': len(data),
4114 }
4115 self.assertEqual(expected, props)
4116
4117 def testCompressImageLess(self):
4118 """Test compression where compression reduces the image size"""
4119 self._CheckLz4()
4120 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4121 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4122 dtb = fdt.Fdt(out_dtb_fname)
4123 dtb.Scan()
4124 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4125 'uncomp-size'])
4126 orig = self._decompress(data)
4127
4128 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
4129
4130 # Do a sanity check on various fields
4131 image = control.images['image']
4132 entries = image.GetEntries()
4133 self.assertEqual(2, len(entries))
4134
4135 entry = entries['blob']
4136 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4137 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4138
4139 entry = entries['u-boot']
4140 self.assertEqual(U_BOOT_DATA, entry.data)
4141 self.assertEqual(len(U_BOOT_DATA), entry.size)
4142
4143 self.assertEqual(len(data), image.size)
4144 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4145 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4146 image.uncomp_size)
4147 orig = self._decompress(image.data)
4148 self.assertEqual(orig, image.uncomp_data)
4149
4150 expected = {
4151 'blob:offset': 0,
4152 'blob:size': len(COMPRESS_DATA_BIG),
4153 'u-boot:offset': len(COMPRESS_DATA_BIG),
4154 'u-boot:size': len(U_BOOT_DATA),
4155 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4156 'offset': 0,
4157 'image-pos': 0,
4158 'size': len(data),
4159 }
4160 self.assertEqual(expected, props)
4161
4162 def testCompressSectionSize(self):
4163 """Test compression of a section with a fixed size"""
4164 self._CheckLz4()
4165 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4166 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4167 dtb = fdt.Fdt(out_dtb_fname)
4168 dtb.Scan()
4169 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4170 'uncomp-size'])
4171 orig = self._decompress(data)
4172 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4173 expected = {
4174 'section/blob:offset': 0,
4175 'section/blob:size': len(COMPRESS_DATA),
4176 'section/u-boot:offset': len(COMPRESS_DATA),
4177 'section/u-boot:size': len(U_BOOT_DATA),
4178 'section:offset': 0,
4179 'section:image-pos': 0,
4180 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4181 'section:size': 0x30,
4182 'offset': 0,
4183 'image-pos': 0,
4184 'size': 0x30,
4185 }
4186 self.assertEqual(expected, props)
4187
4188 def testCompressSection(self):
4189 """Test compression of a section with no fixed size"""
4190 self._CheckLz4()
4191 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4192 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4193 dtb = fdt.Fdt(out_dtb_fname)
4194 dtb.Scan()
4195 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4196 'uncomp-size'])
4197 orig = self._decompress(data)
4198 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4199 expected = {
4200 'section/blob:offset': 0,
4201 'section/blob:size': len(COMPRESS_DATA),
4202 'section/u-boot:offset': len(COMPRESS_DATA),
4203 'section/u-boot:size': len(U_BOOT_DATA),
4204 'section:offset': 0,
4205 'section:image-pos': 0,
4206 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4207 'section:size': len(data),
4208 'offset': 0,
4209 'image-pos': 0,
4210 'size': len(data),
4211 }
4212 self.assertEqual(expected, props)
4213
4214 def testCompressExtra(self):
4215 """Test compression of a section with no fixed size"""
4216 self._CheckLz4()
4217 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4218 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4219 dtb = fdt.Fdt(out_dtb_fname)
4220 dtb.Scan()
4221 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4222 'uncomp-size'])
4223
4224 base = data[len(U_BOOT_DATA):]
4225 self.assertEquals(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
4226 rest = base[len(U_BOOT_DATA):]
4227
4228 # Check compressed data
4229 section1 = self._decompress(rest)
Simon Glass0d1e95a2022-01-09 20:14:04 -07004230 expect1 = comp_util.compress(COMPRESS_DATA + U_BOOT_DATA, 'lz4')
Simon Glass8f5ef892020-10-26 17:40:25 -06004231 self.assertEquals(expect1, rest[:len(expect1)])
4232 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, section1)
4233 rest1 = rest[len(expect1):]
4234
4235 section2 = self._decompress(rest1)
Simon Glass0d1e95a2022-01-09 20:14:04 -07004236 expect2 = comp_util.compress(COMPRESS_DATA + COMPRESS_DATA, 'lz4')
Simon Glass8f5ef892020-10-26 17:40:25 -06004237 self.assertEquals(expect2, rest1[:len(expect2)])
4238 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA, section2)
4239 rest2 = rest1[len(expect2):]
4240
4241 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4242 len(expect2) + len(U_BOOT_DATA))
4243 #self.assertEquals(expect_size, len(data))
4244
4245 #self.assertEquals(U_BOOT_DATA, rest2)
4246
4247 self.maxDiff = None
4248 expected = {
4249 'u-boot:offset': 0,
4250 'u-boot:image-pos': 0,
4251 'u-boot:size': len(U_BOOT_DATA),
4252
4253 'base:offset': len(U_BOOT_DATA),
4254 'base:image-pos': len(U_BOOT_DATA),
4255 'base:size': len(data) - len(U_BOOT_DATA),
4256 'base/u-boot:offset': 0,
4257 'base/u-boot:image-pos': len(U_BOOT_DATA),
4258 'base/u-boot:size': len(U_BOOT_DATA),
4259 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4260 len(expect2),
4261 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4262 len(expect2),
4263 'base/u-boot2:size': len(U_BOOT_DATA),
4264
4265 'base/section:offset': len(U_BOOT_DATA),
4266 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4267 'base/section:size': len(expect1),
4268 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4269 'base/section/blob:offset': 0,
4270 'base/section/blob:size': len(COMPRESS_DATA),
4271 'base/section/u-boot:offset': len(COMPRESS_DATA),
4272 'base/section/u-boot:size': len(U_BOOT_DATA),
4273
4274 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4275 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4276 'base/section2:size': len(expect2),
4277 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4278 'base/section2/blob:offset': 0,
4279 'base/section2/blob:size': len(COMPRESS_DATA),
4280 'base/section2/blob2:offset': len(COMPRESS_DATA),
4281 'base/section2/blob2:size': len(COMPRESS_DATA),
4282
4283 'offset': 0,
4284 'image-pos': 0,
4285 'size': len(data),
4286 }
4287 self.assertEqual(expected, props)
4288
Simon Glass870a9ea2021-01-06 21:35:15 -07004289 def testSymbolsSubsection(self):
4290 """Test binman can assign symbols from a subsection"""
Simon Glassf5898822021-03-18 20:24:56 +13004291 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x18)
Simon Glass870a9ea2021-01-06 21:35:15 -07004292
Simon Glass939d1062021-01-06 21:35:16 -07004293 def testReadImageEntryArg(self):
4294 """Test reading an image that would need an entry arg to generate"""
4295 entry_args = {
4296 'cros-ec-rw-path': 'ecrw.bin',
4297 }
4298 data = self.data = self._DoReadFileDtb(
4299 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4300 entry_args=entry_args)
4301
4302 image_fname = tools.GetOutputFilename('image.bin')
4303 orig_image = control.images['image']
4304
4305 # This should not generate an error about the missing 'cros-ec-rw-path'
4306 # since we are reading the image from a file. Compare with
4307 # testEntryArgsRequired()
4308 image = Image.FromFile(image_fname)
4309 self.assertEqual(orig_image.GetEntries().keys(),
4310 image.GetEntries().keys())
4311
Simon Glass6eb99322021-01-06 21:35:18 -07004312 def testFilesAlign(self):
4313 """Test alignment with files"""
4314 data = self._DoReadFile('190_files_align.dts')
4315
4316 # The first string is 15 bytes so will align to 16
4317 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4318 self.assertEqual(expect, data)
4319
Simon Glass5c6ba712021-01-06 21:35:19 -07004320 def testReadImageSkip(self):
4321 """Test reading an image and accessing its FDT map"""
4322 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
4323 image_fname = tools.GetOutputFilename('image.bin')
4324 orig_image = control.images['image']
4325 image = Image.FromFile(image_fname)
4326 self.assertEqual(orig_image.GetEntries().keys(),
4327 image.GetEntries().keys())
4328
4329 orig_entry = orig_image.GetEntries()['fdtmap']
4330 entry = image.GetEntries()['fdtmap']
4331 self.assertEqual(orig_entry.offset, entry.offset)
4332 self.assertEqual(orig_entry.size, entry.size)
4333 self.assertEqual(16, entry.image_pos)
4334
4335 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4336
4337 self.assertEquals(U_BOOT_DATA, u_boot.ReadData())
4338
Simon Glass77a64e02021-03-18 20:24:57 +13004339 def testTplNoDtb(self):
4340 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
Simon Glass0fe44dc2021-04-25 08:39:32 +12004341 self._SetupTplElf()
Simon Glass77a64e02021-03-18 20:24:57 +13004342 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4343 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4344 data[:len(U_BOOT_TPL_NODTB_DATA)])
4345
Simon Glassd26efc82021-03-18 20:24:58 +13004346 def testTplBssPad(self):
4347 """Test that we can pad TPL's BSS with zeros"""
4348 # ELF file with a '__bss_size' symbol
4349 self._SetupTplElf()
4350 data = self._DoReadFile('193_tpl_bss_pad.dts')
4351 self.assertEqual(U_BOOT_TPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
4352 data)
4353
4354 def testTplBssPadMissing(self):
4355 """Test that a missing symbol is detected"""
4356 self._SetupTplElf('u_boot_ucode_ptr')
4357 with self.assertRaises(ValueError) as e:
4358 self._DoReadFile('193_tpl_bss_pad.dts')
4359 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4360 str(e.exception))
4361
Simon Glass06684922021-03-18 20:25:07 +13004362 def checkDtbSizes(self, data, pad_len, start):
4363 """Check the size arguments in a dtb embedded in an image
4364
4365 Args:
4366 data: The image data
4367 pad_len: Length of the pad section in the image, in bytes
4368 start: Start offset of the devicetree to examine, within the image
4369
4370 Returns:
4371 Size of the devicetree in bytes
4372 """
4373 dtb_data = data[start:]
4374 dtb = fdt.Fdt.FromData(dtb_data)
4375 fdt_size = dtb.GetFdtObj().totalsize()
4376 dtb.Scan()
4377 props = self._GetPropTree(dtb, 'size')
4378 self.assertEqual({
4379 'size': len(data),
4380 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4381 'u-boot-spl/u-boot-spl-dtb:size': 801,
4382 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4383 'u-boot-spl:size': 860,
4384 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4385 'u-boot/u-boot-dtb:size': 781,
4386 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4387 'u-boot:size': 827,
4388 }, props)
4389 return fdt_size
4390
4391 def testExpanded(self):
4392 """Test that an expanded entry type is selected when needed"""
4393 self._SetupSplElf()
4394 self._SetupTplElf()
4395
4396 # SPL has a devicetree, TPL does not
4397 entry_args = {
4398 'spl-dtb': '1',
4399 'spl-bss-pad': 'y',
4400 'tpl-dtb': '',
4401 }
4402 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4403 entry_args=entry_args)
4404 image = control.images['image']
4405 entries = image.GetEntries()
4406 self.assertEqual(3, len(entries))
4407
4408 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4409 self.assertIn('u-boot', entries)
4410 entry = entries['u-boot']
4411 self.assertEqual('u-boot-expanded', entry.etype)
4412 subent = entry.GetEntries()
4413 self.assertEqual(2, len(subent))
4414 self.assertIn('u-boot-nodtb', subent)
4415 self.assertIn('u-boot-dtb', subent)
4416
4417 # Second, u-boot-spl, which should be expanded into three parts
4418 self.assertIn('u-boot-spl', entries)
4419 entry = entries['u-boot-spl']
4420 self.assertEqual('u-boot-spl-expanded', entry.etype)
4421 subent = entry.GetEntries()
4422 self.assertEqual(3, len(subent))
4423 self.assertIn('u-boot-spl-nodtb', subent)
4424 self.assertIn('u-boot-spl-bss-pad', subent)
4425 self.assertIn('u-boot-spl-dtb', subent)
4426
4427 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4428 # devicetree
4429 self.assertIn('u-boot-tpl', entries)
4430 entry = entries['u-boot-tpl']
4431 self.assertEqual('u-boot-tpl', entry.etype)
4432 self.assertEqual(None, entry.GetEntries())
4433
4434 def testExpandedTpl(self):
4435 """Test that an expanded entry type is selected for TPL when needed"""
4436 self._SetupTplElf()
4437
4438 entry_args = {
4439 'tpl-bss-pad': 'y',
4440 'tpl-dtb': 'y',
4441 }
4442 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4443 entry_args=entry_args)
4444 image = control.images['image']
4445 entries = image.GetEntries()
4446 self.assertEqual(1, len(entries))
4447
4448 # We only have u-boot-tpl, which be expanded
4449 self.assertIn('u-boot-tpl', entries)
4450 entry = entries['u-boot-tpl']
4451 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4452 subent = entry.GetEntries()
4453 self.assertEqual(3, len(subent))
4454 self.assertIn('u-boot-tpl-nodtb', subent)
4455 self.assertIn('u-boot-tpl-bss-pad', subent)
4456 self.assertIn('u-boot-tpl-dtb', subent)
4457
4458 def testExpandedNoPad(self):
4459 """Test an expanded entry without BSS pad enabled"""
4460 self._SetupSplElf()
4461 self._SetupTplElf()
4462
4463 # SPL has a devicetree, TPL does not
4464 entry_args = {
4465 'spl-dtb': 'something',
4466 'spl-bss-pad': 'n',
4467 'tpl-dtb': '',
4468 }
4469 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4470 entry_args=entry_args)
4471 image = control.images['image']
4472 entries = image.GetEntries()
4473
4474 # Just check u-boot-spl, which should be expanded into two parts
4475 self.assertIn('u-boot-spl', entries)
4476 entry = entries['u-boot-spl']
4477 self.assertEqual('u-boot-spl-expanded', entry.etype)
4478 subent = entry.GetEntries()
4479 self.assertEqual(2, len(subent))
4480 self.assertIn('u-boot-spl-nodtb', subent)
4481 self.assertIn('u-boot-spl-dtb', subent)
4482
4483 def testExpandedTplNoPad(self):
4484 """Test that an expanded entry type with padding disabled in TPL"""
4485 self._SetupTplElf()
4486
4487 entry_args = {
4488 'tpl-bss-pad': '',
4489 'tpl-dtb': 'y',
4490 }
4491 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4492 entry_args=entry_args)
4493 image = control.images['image']
4494 entries = image.GetEntries()
4495 self.assertEqual(1, len(entries))
4496
4497 # We only have u-boot-tpl, which be expanded
4498 self.assertIn('u-boot-tpl', entries)
4499 entry = entries['u-boot-tpl']
4500 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4501 subent = entry.GetEntries()
4502 self.assertEqual(2, len(subent))
4503 self.assertIn('u-boot-tpl-nodtb', subent)
4504 self.assertIn('u-boot-tpl-dtb', subent)
4505
4506 def testFdtInclude(self):
4507 """Test that an Fdt is update within all binaries"""
4508 self._SetupSplElf()
4509 self._SetupTplElf()
4510
4511 # SPL has a devicetree, TPL does not
4512 self.maxDiff = None
4513 entry_args = {
4514 'spl-dtb': '1',
4515 'spl-bss-pad': 'y',
4516 'tpl-dtb': '',
4517 }
4518 # Build the image. It includes two separate devicetree binaries, each
4519 # with their own contents, but all contain the binman definition.
4520 data = self._DoReadFileDtb(
4521 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4522 update_dtb=True, entry_args=entry_args)[0]
4523 pad_len = 10
4524
4525 # Check the U-Boot dtb
4526 start = len(U_BOOT_NODTB_DATA)
4527 fdt_size = self.checkDtbSizes(data, pad_len, start)
4528
4529 # Now check SPL
4530 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4531 fdt_size = self.checkDtbSizes(data, pad_len, start)
4532
4533 # TPL has no devicetree
4534 start += fdt_size + len(U_BOOT_TPL_DATA)
4535 self.assertEqual(len(data), start)
Simon Glass7d398bb2020-10-26 17:40:14 -06004536
Simon Glass3d433382021-03-21 18:24:30 +13004537 def testSymbolsExpanded(self):
4538 """Test binman can assign symbols in expanded entries"""
4539 entry_args = {
4540 'spl-dtb': '1',
4541 }
4542 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4543 U_BOOT_SPL_DTB_DATA, 0x38,
4544 entry_args=entry_args, use_expanded=True)
4545
Simon Glass189f2912021-03-21 18:24:31 +13004546 def testCollection(self):
4547 """Test a collection"""
4548 data = self._DoReadFile('198_collection.dts')
4549 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
4550 tools.GetBytes(0xff, 2) + U_BOOT_NODTB_DATA +
4551 tools.GetBytes(0xfe, 3) + U_BOOT_DTB_DATA,
4552 data)
4553
Simon Glass631f7522021-03-21 18:24:32 +13004554 def testCollectionSection(self):
4555 """Test a collection where a section must be built first"""
4556 # Sections never have their contents when GetData() is called, but when
Simon Glassd34bcdd2021-11-23 11:03:47 -07004557 # BuildSectionData() is called with required=True, a section will force
Simon Glass631f7522021-03-21 18:24:32 +13004558 # building the contents, producing an error is anything is still
4559 # missing.
4560 data = self._DoReadFile('199_collection_section.dts')
4561 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
4562 self.assertEqual(section + U_BOOT_DATA + tools.GetBytes(0xff, 2) +
4563 section + tools.GetBytes(0xfe, 3) + U_BOOT_DATA,
4564 data)
4565
Simon Glass5ff9fed2021-03-21 18:24:33 +13004566 def testAlignDefault(self):
4567 """Test that default alignment works on sections"""
4568 data = self._DoReadFile('200_align_default.dts')
4569 expected = (U_BOOT_DATA + tools.GetBytes(0, 8 - len(U_BOOT_DATA)) +
4570 U_BOOT_DATA)
4571 # Special alignment for section
4572 expected += tools.GetBytes(0, 32 - len(expected))
4573 # No alignment within the nested section
4574 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
4575 # Now the final piece, which should be default-aligned
4576 expected += tools.GetBytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
4577 self.assertEqual(expected, data)
Simon Glass631f7522021-03-21 18:24:32 +13004578
Bin Meng4c4d6072021-05-10 20:23:33 +08004579 def testPackOpenSBI(self):
4580 """Test that an image with an OpenSBI binary can be created"""
4581 data = self._DoReadFile('201_opensbi.dts')
4582 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
4583
Simon Glassc69d19c2021-07-06 10:36:37 -06004584 def testSectionsSingleThread(self):
4585 """Test sections without multithreading"""
4586 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
4587 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
4588 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
4589 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
4590 self.assertEqual(expected, data)
4591
4592 def testThreadTimeout(self):
4593 """Test handling a thread that takes too long"""
4594 with self.assertRaises(ValueError) as e:
4595 self._DoTestFile('202_section_timeout.dts',
4596 test_section_timeout=True)
Simon Glassb2dfe832021-10-18 12:13:15 -06004597 self.assertIn("Timed out obtaining contents", str(e.exception))
Simon Glassc69d19c2021-07-06 10:36:37 -06004598
Simon Glass03ebc202021-07-06 10:36:41 -06004599 def testTiming(self):
4600 """Test output of timing information"""
4601 data = self._DoReadFile('055_sections.dts')
4602 with test_util.capture_sys_output() as (stdout, stderr):
4603 state.TimingShow()
4604 self.assertIn('read:', stdout.getvalue())
4605 self.assertIn('compress:', stdout.getvalue())
4606
Simon Glass0427bed2021-11-03 21:09:18 -06004607 def testUpdateFdtInElf(self):
4608 """Test that we can update the devicetree in an ELF file"""
4609 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4610 outfile = os.path.join(self._indir, 'u-boot.out')
4611 begin_sym = 'dtb_embed_begin'
4612 end_sym = 'dtb_embed_end'
4613 retcode = self._DoTestFile(
4614 '060_fdt_update.dts', update_dtb=True,
4615 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4616 self.assertEqual(0, retcode)
4617
4618 # Check that the output file does in fact contact a dtb with the binman
4619 # definition in the correct place
4620 syms = elf.GetSymbolFileOffset(infile,
4621 ['dtb_embed_begin', 'dtb_embed_end'])
4622 data = tools.ReadFile(outfile)
4623 dtb_data = data[syms['dtb_embed_begin'].offset:
4624 syms['dtb_embed_end'].offset]
4625
4626 dtb = fdt.Fdt.FromData(dtb_data)
4627 dtb.Scan()
4628 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4629 self.assertEqual({
4630 'image-pos': 0,
4631 'offset': 0,
4632 '_testing:offset': 32,
4633 '_testing:size': 2,
4634 '_testing:image-pos': 32,
4635 'section@0/u-boot:offset': 0,
4636 'section@0/u-boot:size': len(U_BOOT_DATA),
4637 'section@0/u-boot:image-pos': 0,
4638 'section@0:offset': 0,
4639 'section@0:size': 16,
4640 'section@0:image-pos': 0,
4641
4642 'section@1/u-boot:offset': 0,
4643 'section@1/u-boot:size': len(U_BOOT_DATA),
4644 'section@1/u-boot:image-pos': 16,
4645 'section@1:offset': 16,
4646 'section@1:size': 16,
4647 'section@1:image-pos': 16,
4648 'size': 40
4649 }, props)
4650
4651 def testUpdateFdtInElfInvalid(self):
4652 """Test that invalid args are detected with --update-fdt-in-elf"""
4653 with self.assertRaises(ValueError) as e:
4654 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
4655 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
4656 str(e.exception))
4657
4658 def testUpdateFdtInElfNoSyms(self):
4659 """Test that missing symbols are detected with --update-fdt-in-elf"""
4660 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4661 outfile = ''
4662 begin_sym = 'wrong_begin'
4663 end_sym = 'wrong_end'
4664 with self.assertRaises(ValueError) as e:
4665 self._DoTestFile(
4666 '060_fdt_update.dts',
4667 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4668 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
4669 str(e.exception))
4670
4671 def testUpdateFdtInElfTooSmall(self):
4672 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
4673 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
4674 outfile = os.path.join(self._indir, 'u-boot.out')
4675 begin_sym = 'dtb_embed_begin'
4676 end_sym = 'dtb_embed_end'
4677 with self.assertRaises(ValueError) as e:
4678 self._DoTestFile(
4679 '060_fdt_update.dts', update_dtb=True,
4680 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4681 self.assertRegex(
4682 str(e.exception),
4683 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
4684
Simon Glassc475dec2021-11-23 11:03:42 -07004685 def testVersion(self):
4686 """Test we can get the binman version"""
4687 version = '(unreleased)'
4688 self.assertEqual(version, state.GetVersion(self._indir))
4689
4690 with self.assertRaises(SystemExit):
4691 with test_util.capture_sys_output() as (_, stderr):
4692 self._DoBinman('-V')
4693 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
4694
4695 # Try running the tool too, just to be safe
4696 result = self._RunBinman('-V')
4697 self.assertEqual('Binman %s\n' % version, result.stderr)
4698
4699 # Set up a version file to make sure that works
4700 version = 'v2025.01-rc2'
4701 tools.WriteFile(os.path.join(self._indir, 'version'), version,
4702 binary=False)
4703 self.assertEqual(version, state.GetVersion(self._indir))
4704
Simon Glass943bf782021-11-23 21:09:50 -07004705 def testAltFormat(self):
4706 """Test that alternative formats can be used to extract"""
4707 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
4708
4709 try:
4710 tmpdir, updated_fname = self._SetupImageInTmpdir()
4711 with test_util.capture_sys_output() as (stdout, _):
4712 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
4713 self.assertEqual(
4714 '''Flag (-F) Entry type Description
4715fdt fdtmap Extract the devicetree blob from the fdtmap
4716''',
4717 stdout.getvalue())
4718
4719 dtb = os.path.join(tmpdir, 'fdt.dtb')
4720 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
4721 dtb, 'fdtmap')
4722
4723 # Check that we can read it and it can be scanning, meaning it does
4724 # not have a 16-byte fdtmap header
4725 data = tools.ReadFile(dtb)
4726 dtb = fdt.Fdt.FromData(data)
4727 dtb.Scan()
4728
4729 # Now check u-boot which has no alt_format
4730 fname = os.path.join(tmpdir, 'fdt.dtb')
4731 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
4732 '-f', fname, 'u-boot')
4733 data = tools.ReadFile(fname)
4734 self.assertEqual(U_BOOT_DATA, data)
4735
4736 finally:
4737 shutil.rmtree(tmpdir)
4738
Simon Glasscc2c5002021-11-23 21:09:52 -07004739 def testExtblobList(self):
4740 """Test an image with an external blob list"""
4741 data = self._DoReadFile('215_blob_ext_list.dts')
4742 self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
4743
4744 def testExtblobListMissing(self):
4745 """Test an image with a missing external blob"""
4746 with self.assertRaises(ValueError) as e:
4747 self._DoReadFile('216_blob_ext_list_missing.dts')
4748 self.assertIn("Filename 'missing-file' not found in input path",
4749 str(e.exception))
4750
4751 def testExtblobListMissingOk(self):
4752 """Test an image with an missing external blob that is allowed"""
4753 with test_util.capture_sys_output() as (stdout, stderr):
4754 self._DoTestFile('216_blob_ext_list_missing.dts',
4755 allow_missing=True)
4756 err = stderr.getvalue()
4757 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
4758
Simon Glass75989722021-11-23 21:08:59 -07004759 def testFip(self):
4760 """Basic test of generation of an ARM Firmware Image Package (FIP)"""
4761 data = self._DoReadFile('203_fip.dts')
4762 hdr, fents = fip_util.decode_fip(data)
4763 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
4764 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
4765 self.assertEqual(0x123, hdr.flags)
4766
4767 self.assertEqual(2, len(fents))
4768
4769 fent = fents[0]
4770 self.assertEqual(
4771 bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
4772 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
4773 self.assertEqual('soc-fw', fent.fip_type)
4774 self.assertEqual(0x88, fent.offset)
4775 self.assertEqual(len(ATF_BL31_DATA), fent.size)
4776 self.assertEqual(0x123456789abcdef, fent.flags)
4777 self.assertEqual(ATF_BL31_DATA, fent.data)
4778 self.assertEqual(True, fent.valid)
4779
4780 fent = fents[1]
4781 self.assertEqual(
4782 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
4783 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
4784 self.assertEqual('scp-fwu-cfg', fent.fip_type)
4785 self.assertEqual(0x8c, fent.offset)
4786 self.assertEqual(len(ATF_BL31_DATA), fent.size)
4787 self.assertEqual(0, fent.flags)
4788 self.assertEqual(ATF_BL2U_DATA, fent.data)
4789 self.assertEqual(True, fent.valid)
4790
4791 def testFipOther(self):
4792 """Basic FIP with something that isn't a external blob"""
4793 data = self._DoReadFile('204_fip_other.dts')
4794 hdr, fents = fip_util.decode_fip(data)
4795
4796 self.assertEqual(2, len(fents))
4797 fent = fents[1]
4798 self.assertEqual('rot-cert', fent.fip_type)
4799 self.assertEqual(b'aa', fent.data)
4800
4801 def testFipOther(self):
4802 """Basic FIP with something that isn't a external blob"""
4803 data = self._DoReadFile('204_fip_other.dts')
4804 hdr, fents = fip_util.decode_fip(data)
4805
4806 self.assertEqual(2, len(fents))
4807 fent = fents[1]
4808 self.assertEqual('rot-cert', fent.fip_type)
4809 self.assertEqual(b'aa', fent.data)
4810
4811 def testFipNoType(self):
4812 """FIP with an entry of an unknown type"""
4813 with self.assertRaises(ValueError) as e:
4814 self._DoReadFile('205_fip_no_type.dts')
4815 self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
4816 str(e.exception))
4817
4818 def testFipUuid(self):
4819 """Basic FIP with a manual uuid"""
4820 data = self._DoReadFile('206_fip_uuid.dts')
4821 hdr, fents = fip_util.decode_fip(data)
4822
4823 self.assertEqual(2, len(fents))
4824 fent = fents[1]
4825 self.assertEqual(None, fent.fip_type)
4826 self.assertEqual(
4827 bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
4828 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
4829 fent.uuid)
4830 self.assertEqual(U_BOOT_DATA, fent.data)
4831
4832 def testFipLs(self):
4833 """Test listing a FIP"""
4834 data = self._DoReadFileRealDtb('207_fip_ls.dts')
4835 hdr, fents = fip_util.decode_fip(data)
4836
4837 try:
4838 tmpdir, updated_fname = self._SetupImageInTmpdir()
4839 with test_util.capture_sys_output() as (stdout, stderr):
4840 self._DoBinman('ls', '-i', updated_fname)
4841 finally:
4842 shutil.rmtree(tmpdir)
4843 lines = stdout.getvalue().splitlines()
4844 expected = [
4845'Name Image-pos Size Entry-type Offset Uncomp-size',
4846'----------------------------------------------------------------',
4847'main-section 0 2d3 section 0',
4848' atf-fip 0 90 atf-fip 0',
4849' soc-fw 88 4 blob-ext 88',
4850' u-boot 8c 4 u-boot 8c',
4851' fdtmap 90 243 fdtmap 90',
4852]
4853 self.assertEqual(expected, lines)
4854
4855 image = control.images['image']
4856 entries = image.GetEntries()
4857 fdtmap = entries['fdtmap']
4858
4859 fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
4860 magic = fdtmap_data[:8]
4861 self.assertEqual(b'_FDTMAP_', magic)
4862 self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
4863
4864 fdt_data = fdtmap_data[16:]
4865 dtb = fdt.Fdt.FromData(fdt_data)
4866 dtb.Scan()
4867 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
4868 self.assertEqual({
4869 'atf-fip/soc-fw:image-pos': 136,
4870 'atf-fip/soc-fw:offset': 136,
4871 'atf-fip/soc-fw:size': 4,
4872 'atf-fip/u-boot:image-pos': 140,
4873 'atf-fip/u-boot:offset': 140,
4874 'atf-fip/u-boot:size': 4,
4875 'atf-fip:image-pos': 0,
4876 'atf-fip:offset': 0,
4877 'atf-fip:size': 144,
4878 'image-pos': 0,
4879 'offset': 0,
4880 'fdtmap:image-pos': fdtmap.image_pos,
4881 'fdtmap:offset': fdtmap.offset,
4882 'fdtmap:size': len(fdtmap_data),
4883 'size': len(data),
4884 }, props)
4885
4886 def testFipExtractOneEntry(self):
4887 """Test extracting a single entry fron an FIP"""
4888 self._DoReadFileRealDtb('207_fip_ls.dts')
4889 image_fname = tools.GetOutputFilename('image.bin')
4890 fname = os.path.join(self._indir, 'output.extact')
4891 control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
4892 data = tools.ReadFile(fname)
4893 self.assertEqual(U_BOOT_DATA, data)
4894
4895 def testFipReplace(self):
4896 """Test replacing a single file in a FIP"""
4897 expected = U_BOOT_DATA + tools.GetBytes(0x78, 50)
4898 data = self._DoReadFileRealDtb('208_fip_replace.dts')
4899 updated_fname = tools.GetOutputFilename('image-updated.bin')
4900 tools.WriteFile(updated_fname, data)
4901 entry_name = 'atf-fip/u-boot'
4902 control.WriteEntry(updated_fname, entry_name, expected,
4903 allow_resize=True)
4904 actual = control.ReadEntry(updated_fname, entry_name)
4905 self.assertEqual(expected, actual)
4906
4907 new_data = tools.ReadFile(updated_fname)
4908 hdr, fents = fip_util.decode_fip(new_data)
4909
4910 self.assertEqual(2, len(fents))
4911
4912 # Check that the FIP entry is updated
4913 fent = fents[1]
4914 self.assertEqual(0x8c, fent.offset)
4915 self.assertEqual(len(expected), fent.size)
4916 self.assertEqual(0, fent.flags)
4917 self.assertEqual(expected, fent.data)
4918 self.assertEqual(True, fent.valid)
4919
4920 def testFipMissing(self):
4921 with test_util.capture_sys_output() as (stdout, stderr):
4922 self._DoTestFile('209_fip_missing.dts', allow_missing=True)
4923 err = stderr.getvalue()
4924 self.assertRegex(err, "Image 'main-section'.*missing.*: rmm-fw")
4925
4926 def testFipSize(self):
4927 """Test a FIP with a size property"""
4928 data = self._DoReadFile('210_fip_size.dts')
4929 self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
4930 hdr, fents = fip_util.decode_fip(data)
4931 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
4932 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
4933
4934 self.assertEqual(1, len(fents))
4935
4936 fent = fents[0]
4937 self.assertEqual('soc-fw', fent.fip_type)
4938 self.assertEqual(0x60, fent.offset)
4939 self.assertEqual(len(ATF_BL31_DATA), fent.size)
4940 self.assertEqual(ATF_BL31_DATA, fent.data)
4941 self.assertEqual(True, fent.valid)
4942
4943 rest = data[0x60 + len(ATF_BL31_DATA):0x100]
4944 self.assertEqual(tools.GetBytes(0xff, len(rest)), rest)
4945
4946 def testFipBadAlign(self):
4947 """Test that an invalid alignment value in a FIP is detected"""
4948 with self.assertRaises(ValueError) as e:
4949 self._DoTestFile('211_fip_bad_align.dts')
4950 self.assertIn(
4951 "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
4952 str(e.exception))
4953
4954 def testFipCollection(self):
4955 """Test using a FIP in a collection"""
4956 data = self._DoReadFile('212_fip_collection.dts')
4957 entry1 = control.images['image'].GetEntries()['collection']
4958 data1 = data[:entry1.size]
4959 hdr1, fents2 = fip_util.decode_fip(data1)
4960
4961 entry2 = control.images['image'].GetEntries()['atf-fip']
4962 data2 = data[entry2.offset:entry2.offset + entry2.size]
4963 hdr1, fents2 = fip_util.decode_fip(data2)
4964
4965 # The 'collection' entry should have U-Boot included at the end
4966 self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
4967 self.assertEqual(data1, data2 + U_BOOT_DATA)
4968 self.assertEqual(U_BOOT_DATA, data1[-4:])
4969
4970 # There should be a U-Boot after the final FIP
4971 self.assertEqual(U_BOOT_DATA, data[-4:])
Simon Glassc69d19c2021-07-06 10:36:37 -06004972
Simon Glass32d4f102022-01-12 13:10:35 -07004973 def testFakeBlob(self):
4974 """Test handling of faking an external blob"""
4975 with test_util.capture_sys_output() as (stdout, stderr):
4976 self._DoTestFile('217_fake_blob.dts', allow_missing=True,
4977 allow_fake_blobs=True)
4978 err = stderr.getvalue()
4979 self.assertRegex(
4980 err,
4981 "Image '.*' has faked external blobs and is non-functional: .*")
Simon Glass32d4f102022-01-12 13:10:35 -07004982
Simon Glassf4590e02022-01-09 20:13:46 -07004983 def testExtblobListFaked(self):
4984 """Test an extblob with missing external blob that are faked"""
4985 with test_util.capture_sys_output() as (stdout, stderr):
4986 self._DoTestFile('216_blob_ext_list_missing.dts',
4987 allow_fake_blobs=True)
4988 err = stderr.getvalue()
4989 self.assertRegex(err, "Image 'main-section'.*faked.*: blob-ext-list")
4990
Simon Glass56ee85e2022-01-09 20:13:57 -07004991 def testListBintools(self):
4992 args = ['tool', '--list']
4993 with test_util.capture_sys_output() as (stdout, _):
4994 self._DoBinman(*args)
4995 out = stdout.getvalue().splitlines()
4996 self.assertTrue(len(out) >= 2)
4997
4998 def testFetchBintools(self):
4999 def fail_download(url):
5000 """Take the tools.Download() function by raising an exception"""
5001 raise urllib.error.URLError('my error')
5002
5003 args = ['tool']
5004 with self.assertRaises(ValueError) as e:
5005 self._DoBinman(*args)
5006 self.assertIn("Invalid arguments to 'tool' subcommand",
5007 str(e.exception))
5008
5009 args = ['tool', '--fetch']
5010 with self.assertRaises(ValueError) as e:
5011 self._DoBinman(*args)
5012 self.assertIn('Please specify bintools to fetch', str(e.exception))
5013
5014 args = ['tool', '--fetch', '_testing']
5015 with unittest.mock.patch.object(tools, 'Download',
5016 side_effect=fail_download):
5017 with test_util.capture_sys_output() as (stdout, _):
5018 self._DoBinman(*args)
5019 self.assertIn('failed to fetch with all methods', stdout.getvalue())
5020
Simon Glass32d4f102022-01-12 13:10:35 -07005021
Simon Glass9fc60b42017-11-12 21:52:22 -07005022if __name__ == "__main__":
5023 unittest.main()