blob: b1a929242afaae2fdb312da72b22f74ff4093cca [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'
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +030046U_BOOT_SPL_DATA = b'56780123456789abcdefghijklm'
47U_BOOT_TPL_DATA = b'tpl9876543210fedcbazywvuts'
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'
Alper Nebi Yasak21353312022-02-08 01:08:04 +030064U_BOOT_EXP_DATA = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
65U_BOOT_SPL_EXP_DATA = U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA
66U_BOOT_TPL_EXP_DATA = U_BOOT_TPL_NODTB_DATA + U_BOOT_TPL_DTB_DATA
Simon Glassc6c10e72019-05-17 22:00:46 -060067FSP_DATA = b'fsp'
68CMC_DATA = b'cmc'
69VBT_DATA = b'vbt'
70MRC_DATA = b'mrc'
Simon Glassbb748372018-07-17 13:25:33 -060071TEXT_DATA = 'text'
72TEXT_DATA2 = 'text2'
73TEXT_DATA3 = 'text3'
Simon Glassc6c10e72019-05-17 22:00:46 -060074CROS_EC_RW_DATA = b'ecrw'
75GBB_DATA = b'gbbd'
76BMPBLK_DATA = b'bmp'
77VBLOCK_DATA = b'vblk'
78FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
79 b"sorry you're alive\n")
Simon Glassff5c7e32019-07-08 13:18:42 -060080COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
Simon Glass8f5ef892020-10-26 17:40:25 -060081COMPRESS_DATA_BIG = COMPRESS_DATA * 2
Simon Glassc6c10e72019-05-17 22:00:46 -060082REFCODE_DATA = b'refcode'
Simon Glassea0fff92019-08-24 07:23:07 -060083FSP_M_DATA = b'fsp_m'
Simon Glassbc6a88f2019-10-20 21:31:35 -060084FSP_S_DATA = b'fsp_s'
Simon Glass998d1482019-10-20 21:31:36 -060085FSP_T_DATA = b'fsp_t'
Simon Glassdc2f81a2020-09-01 05:13:58 -060086ATF_BL31_DATA = b'bl31'
Roger Quadros47f420a2022-02-19 20:50:04 +020087TEE_OS_DATA = b'this is some tee OS data'
Simon Glass75989722021-11-23 21:08:59 -070088ATF_BL2U_DATA = b'bl2u'
Bin Meng4c4d6072021-05-10 20:23:33 +080089OPENSBI_DATA = b'opensbi'
Samuel Holland18bd4552020-10-21 21:12:15 -050090SCP_DATA = b'scp'
Simon Glass6cf99532020-09-01 05:13:59 -060091TEST_FDT1_DATA = b'fdt1'
92TEST_FDT2_DATA = b'test-fdt2'
Simon Glassfb91d562020-09-06 10:35:33 -060093ENV_DATA = b'var1=1\nvar2="2"'
Philippe Reynesb1c50932022-03-28 22:57:04 +020094PRE_LOAD_MAGIC = b'UBSH'
95PRE_LOAD_VERSION = 0x11223344.to_bytes(4, 'big')
96PRE_LOAD_HDR_SIZE = 0x00001000.to_bytes(4, 'big')
Simon Glass6cf99532020-09-01 05:13:59 -060097
98# Subdirectory of the input dir to use to put test FDTs
99TEST_FDT_SUBDIR = 'fdts'
Simon Glassec127af2018-07-17 13:25:39 -0600100
Simon Glass6ccbfcd2019-07-20 12:23:47 -0600101# The expected size for the device tree in some tests
Simon Glassf667e452019-07-08 14:25:50 -0600102EXTRACT_DTB_SIZE = 0x3c9
103
Simon Glass6ccbfcd2019-07-20 12:23:47 -0600104# Properties expected to be in the device tree when update_dtb is used
105BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
106
Simon Glass12bb1a92019-07-20 12:23:51 -0600107# Extra properties expected to be in the device tree when allow-repack is used
108REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
109
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +0200110# Supported compression bintools
111COMP_BINTOOLS = ['lz4', 'lzma_alone']
Simon Glass4f443042016-11-25 20:15:52 -0700112
113class TestFunctional(unittest.TestCase):
114 """Functional tests for binman
115
116 Most of these use a sample .dts file to build an image and then check
117 that it looks correct. The sample files are in the test/ subdirectory
118 and are numbered.
119
120 For each entry type a very small test file is created using fixed
121 string contents. This makes it easy to test that things look right, and
122 debug problems.
123
124 In some cases a 'real' file must be used - these are also supplied in
125 the test/ diurectory.
126 """
127 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600128 def setUpClass(cls):
Simon Glass4d5994f2017-11-12 21:52:20 -0700129 global entry
Simon Glass16287932020-04-17 18:09:03 -0600130 from binman import entry
Simon Glass4d5994f2017-11-12 21:52:20 -0700131
Simon Glass4f443042016-11-25 20:15:52 -0700132 # Handle the case where argv[0] is 'python'
Simon Glassb986b3b2019-08-24 07:22:43 -0600133 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
134 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
Simon Glass4f443042016-11-25 20:15:52 -0700135
136 # Create a temporary directory for input files
Simon Glassb986b3b2019-08-24 07:22:43 -0600137 cls._indir = tempfile.mkdtemp(prefix='binmant.')
Simon Glass4f443042016-11-25 20:15:52 -0700138
139 # Create some test files
140 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
141 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
142 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glassb8ef5b62018-07-17 13:25:48 -0600143 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700144 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -0700145 TestFunctional._MakeInputFile('me.bin', ME_DATA)
146 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glassb986b3b2019-08-24 07:22:43 -0600147 cls._ResetDtbs()
Simon Glass2250ee62019-08-24 07:22:48 -0600148
Jagdish Gediya9d368f32018-09-03 21:35:08 +0530149 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glass2250ee62019-08-24 07:22:48 -0600150
Simon Glass5e239182019-08-24 07:22:49 -0600151 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
152 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
Simon Glass87722132017-11-12 21:52:26 -0700153 X86_START16_SPL_DATA)
Simon Glass5e239182019-08-24 07:22:49 -0600154 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
Simon Glass35b384c2018-09-14 04:57:10 -0600155 X86_START16_TPL_DATA)
Simon Glass2250ee62019-08-24 07:22:48 -0600156
157 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
158 X86_RESET16_DATA)
159 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
160 X86_RESET16_SPL_DATA)
161 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
162 X86_RESET16_TPL_DATA)
163
Simon Glass4f443042016-11-25 20:15:52 -0700164 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass6b187df2017-11-12 21:52:27 -0700165 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
166 U_BOOT_SPL_NODTB_DATA)
Simon Glassf0253632018-09-14 04:57:32 -0600167 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
168 U_BOOT_TPL_NODTB_DATA)
Simon Glassda229092016-11-25 20:15:56 -0700169 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
170 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Meng59ea8c22017-08-15 22:41:54 -0700171 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassca4f4ff2017-11-12 21:52:28 -0700172 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassec127af2018-07-17 13:25:39 -0600173 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glass0ef87aa2018-07-17 13:25:44 -0600174 TestFunctional._MakeInputDir('devkeys')
175 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass3ae192c2018-10-01 12:22:31 -0600176 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glassea0fff92019-08-24 07:23:07 -0600177 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
Simon Glassbc6a88f2019-10-20 21:31:35 -0600178 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
Simon Glass998d1482019-10-20 21:31:36 -0600179 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700180
Simon Glass53e22bf2019-08-24 07:22:53 -0600181 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
182 elf_test.BuildElfTestFiles(cls._elf_testdir)
183
Simon Glasse0ff8552016-11-25 20:15:53 -0700184 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glassf514d8f2019-08-24 07:22:54 -0600185 TestFunctional._MakeInputFile('u-boot',
Simon Glassc1aa66e2022-01-29 14:14:04 -0700186 tools.read_file(cls.ElfTestFile('u_boot_ucode_ptr')))
Simon Glasse0ff8552016-11-25 20:15:53 -0700187
188 # Intel flash descriptor file
Simon Glass0ba4b3d2020-07-09 18:39:41 -0600189 cls._SetupDescriptor()
Simon Glasse0ff8552016-11-25 20:15:53 -0700190
Simon Glassb986b3b2019-08-24 07:22:43 -0600191 shutil.copytree(cls.TestFile('files'),
192 os.path.join(cls._indir, 'files'))
Simon Glass0a98b282018-09-14 04:57:28 -0600193
Simon Glass83d73c22018-09-14 04:57:26 -0600194 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
Simon Glass8f5ef892020-10-26 17:40:25 -0600195 TestFunctional._MakeInputFile('compress_big', COMPRESS_DATA_BIG)
Simon Glassdc2f81a2020-09-01 05:13:58 -0600196 TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
Roger Quadros47f420a2022-02-19 20:50:04 +0200197 TestFunctional._MakeInputFile('tee-pager.bin', TEE_OS_DATA)
Simon Glass75989722021-11-23 21:08:59 -0700198 TestFunctional._MakeInputFile('bl2u.bin', ATF_BL2U_DATA)
Bin Meng4c4d6072021-05-10 20:23:33 +0800199 TestFunctional._MakeInputFile('fw_dynamic.bin', OPENSBI_DATA)
Samuel Holland18bd4552020-10-21 21:12:15 -0500200 TestFunctional._MakeInputFile('scp.bin', SCP_DATA)
Simon Glass83d73c22018-09-14 04:57:26 -0600201
Simon Glass6cf99532020-09-01 05:13:59 -0600202 # Add a few .dtb files for testing
203 TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR,
204 TEST_FDT1_DATA)
205 TestFunctional._MakeInputFile('%s/test-fdt2.dtb' % TEST_FDT_SUBDIR,
206 TEST_FDT2_DATA)
207
Simon Glassfb91d562020-09-06 10:35:33 -0600208 TestFunctional._MakeInputFile('env.txt', ENV_DATA)
209
Simon Glass40c8bdd2022-03-05 20:19:12 -0700210 # ELF file with two sections in different parts of memory, used for both
211 # ATF and OP_TEE
212 TestFunctional._MakeInputFile('bl31.elf',
213 tools.read_file(cls.ElfTestFile('elf_sections')))
214 TestFunctional._MakeInputFile('tee.elf',
215 tools.read_file(cls.ElfTestFile('elf_sections')))
216
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +0200217 cls.comp_bintools = {}
218 for name in COMP_BINTOOLS:
219 cls.comp_bintools[name] = bintool.Bintool.create(name)
Simon Glassac62fba2019-07-08 13:18:53 -0600220
Simon Glass4f443042016-11-25 20:15:52 -0700221 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600222 def tearDownClass(cls):
Simon Glass4f443042016-11-25 20:15:52 -0700223 """Remove the temporary input directory and its contents"""
Simon Glassb986b3b2019-08-24 07:22:43 -0600224 if cls.preserve_indir:
225 print('Preserving input dir: %s' % cls._indir)
Simon Glassd5164a72019-07-08 13:18:49 -0600226 else:
Simon Glassb986b3b2019-08-24 07:22:43 -0600227 if cls._indir:
228 shutil.rmtree(cls._indir)
229 cls._indir = None
Simon Glass4f443042016-11-25 20:15:52 -0700230
Simon Glassd5164a72019-07-08 13:18:49 -0600231 @classmethod
Simon Glass8acce602019-07-08 13:18:50 -0600232 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
Simon Glass53cd5d92019-07-08 14:25:29 -0600233 toolpath=None, verbosity=None):
Simon Glassd5164a72019-07-08 13:18:49 -0600234 """Accept arguments controlling test execution
235
236 Args:
237 preserve_indir: Preserve the shared input directory used by all
238 tests in this class.
239 preserve_outdir: Preserve the output directories used by tests. Each
240 test has its own, so this is normally only useful when running a
241 single test.
Simon Glass8acce602019-07-08 13:18:50 -0600242 toolpath: ist of paths to use for tools
Simon Glassd5164a72019-07-08 13:18:49 -0600243 """
244 cls.preserve_indir = preserve_indir
245 cls.preserve_outdirs = preserve_outdirs
Simon Glass8acce602019-07-08 13:18:50 -0600246 cls.toolpath = toolpath
Simon Glass53cd5d92019-07-08 14:25:29 -0600247 cls.verbosity = verbosity
Simon Glassd5164a72019-07-08 13:18:49 -0600248
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +0200249 def _CheckBintool(self, bintool):
250 if not bintool.is_present():
251 self.skipTest('%s not available' % bintool.name)
252
Simon Glassac62fba2019-07-08 13:18:53 -0600253 def _CheckLz4(self):
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +0200254 bintool = self.comp_bintools['lz4']
255 self._CheckBintool(bintool)
Simon Glassac62fba2019-07-08 13:18:53 -0600256
Simon Glassbf574f12019-07-20 12:24:09 -0600257 def _CleanupOutputDir(self):
258 """Remove the temporary output directory"""
259 if self.preserve_outdirs:
260 print('Preserving output dir: %s' % tools.outdir)
261 else:
Simon Glassc1aa66e2022-01-29 14:14:04 -0700262 tools._finalise_for_test()
Simon Glassbf574f12019-07-20 12:24:09 -0600263
Simon Glass4f443042016-11-25 20:15:52 -0700264 def setUp(self):
265 # Enable this to turn on debugging output
Simon Glassf3385a52022-01-29 14:14:15 -0700266 # tout.init(tout.DEBUG)
Simon Glass4f443042016-11-25 20:15:52 -0700267 command.test_result = None
268
269 def tearDown(self):
270 """Remove the temporary output directory"""
Simon Glassbf574f12019-07-20 12:24:09 -0600271 self._CleanupOutputDir()
Simon Glass4f443042016-11-25 20:15:52 -0700272
Simon Glassf86a7362019-07-20 12:24:10 -0600273 def _SetupImageInTmpdir(self):
274 """Set up the output image in a new temporary directory
275
276 This is used when an image has been generated in the output directory,
277 but we want to run binman again. This will create a new output
278 directory and fail to delete the original one.
279
280 This creates a new temporary directory, copies the image to it (with a
281 new name) and removes the old output directory.
282
283 Returns:
284 Tuple:
285 Temporary directory to use
286 New image filename
287 """
Simon Glassc1aa66e2022-01-29 14:14:04 -0700288 image_fname = tools.get_output_filename('image.bin')
Simon Glassf86a7362019-07-20 12:24:10 -0600289 tmpdir = tempfile.mkdtemp(prefix='binman.')
290 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
Simon Glassc1aa66e2022-01-29 14:14:04 -0700291 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassf86a7362019-07-20 12:24:10 -0600292 self._CleanupOutputDir()
293 return tmpdir, updated_fname
294
Simon Glassb8ef5b62018-07-17 13:25:48 -0600295 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600296 def _ResetDtbs(cls):
Simon Glassb8ef5b62018-07-17 13:25:48 -0600297 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
298 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
299 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
300
Simon Glass4f443042016-11-25 20:15:52 -0700301 def _RunBinman(self, *args, **kwargs):
302 """Run binman using the command line
303
304 Args:
305 Arguments to pass, as a list of strings
306 kwargs: Arguments to pass to Command.RunPipe()
307 """
Simon Glassd9800692022-01-29 14:14:05 -0700308 result = command.run_pipe([[self._binman_pathname] + list(args)],
Simon Glass4f443042016-11-25 20:15:52 -0700309 capture=True, capture_stderr=True, raise_on_error=False)
310 if result.return_code and kwargs.get('raise_on_error', True):
311 raise Exception("Error running '%s': %s" % (' '.join(args),
312 result.stdout + result.stderr))
313 return result
314
Simon Glass53cd5d92019-07-08 14:25:29 -0600315 def _DoBinman(self, *argv):
Simon Glass4f443042016-11-25 20:15:52 -0700316 """Run binman using directly (in the same process)
317
318 Args:
319 Arguments to pass, as a list of strings
320 Returns:
321 Return value (0 for success)
322 """
Simon Glass53cd5d92019-07-08 14:25:29 -0600323 argv = list(argv)
324 args = cmdline.ParseArgs(argv)
325 args.pager = 'binman-invalid-pager'
326 args.build_dir = self._indir
Simon Glass4f443042016-11-25 20:15:52 -0700327
328 # For testing, you can force an increase in verbosity here
Simon Glass53cd5d92019-07-08 14:25:29 -0600329 # args.verbosity = tout.DEBUG
330 return control.Binman(args)
Simon Glass4f443042016-11-25 20:15:52 -0700331
Simon Glass53af22a2018-07-17 13:25:32 -0600332 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glasseb833d82019-04-25 21:58:34 -0600333 entry_args=None, images=None, use_real_dtb=False,
Simon Glass63aeaeb2021-03-18 20:25:05 +1300334 use_expanded=False, verbosity=None, allow_missing=False,
Heiko Thierya89c8f22022-01-06 11:49:41 +0100335 allow_fake_blobs=False, extra_indirs=None, threads=None,
Simon Glass4f9ee832022-01-09 20:14:09 -0700336 test_section_timeout=False, update_fdt_in_elf=None,
337 force_missing_bintools=''):
Simon Glass4f443042016-11-25 20:15:52 -0700338 """Run binman with a given test file
339
340 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600341 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600342 debug: True to enable debugging output
Simon Glass3b0c3822018-06-01 09:38:20 -0600343 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600344 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600345 tree before packing it into the image
Simon Glass0bfa7b02018-09-14 04:57:12 -0600346 entry_args: Dict of entry args to supply to binman
347 key: arg name
348 value: value of that arg
349 images: List of image names to build
Simon Glasse9d336d2020-09-01 05:13:55 -0600350 use_real_dtb: True to use the test file as the contents of
351 the u-boot-dtb entry. Normally this is not needed and the
352 test contents (the U_BOOT_DTB_DATA string) can be used.
353 But in some test we need the real contents.
Simon Glass63aeaeb2021-03-18 20:25:05 +1300354 use_expanded: True to use expanded entries where available, e.g.
355 'u-boot-expanded' instead of 'u-boot'
Simon Glasse9d336d2020-09-01 05:13:55 -0600356 verbosity: Verbosity level to use (0-3, None=don't set it)
357 allow_missing: Set the '--allow-missing' flag so that missing
358 external binaries just produce a warning instead of an error
Heiko Thierya89c8f22022-01-06 11:49:41 +0100359 allow_fake_blobs: Set the '--fake-ext-blobs' flag
Simon Glass6cf99532020-09-01 05:13:59 -0600360 extra_indirs: Extra input directories to add using -I
Simon Glassc69d19c2021-07-06 10:36:37 -0600361 threads: Number of threads to use (None for default, 0 for
362 single-threaded)
Simon Glass7115f002021-11-03 21:09:17 -0600363 test_section_timeout: True to force the first time to timeout, as
364 used in testThreadTimeout()
Simon Glass0427bed2021-11-03 21:09:18 -0600365 update_fdt_in_elf: Value to pass with --update-fdt-in-elf=xxx
Simon Glass4f9ee832022-01-09 20:14:09 -0700366 force_missing_tools (str): comma-separated list of bintools to
367 regard as missing
Simon Glass7115f002021-11-03 21:09:17 -0600368
369 Returns:
370 int return code, 0 on success
Simon Glass4f443042016-11-25 20:15:52 -0700371 """
Simon Glass53cd5d92019-07-08 14:25:29 -0600372 args = []
Simon Glass7fe91732017-11-13 18:55:00 -0700373 if debug:
374 args.append('-D')
Simon Glass53cd5d92019-07-08 14:25:29 -0600375 if verbosity is not None:
376 args.append('-v%d' % verbosity)
377 elif self.verbosity:
378 args.append('-v%d' % self.verbosity)
379 if self.toolpath:
380 for path in self.toolpath:
381 args += ['--toolpath', path]
Simon Glassc69d19c2021-07-06 10:36:37 -0600382 if threads is not None:
383 args.append('-T%d' % threads)
384 if test_section_timeout:
385 args.append('--test-section-timeout')
Simon Glass53cd5d92019-07-08 14:25:29 -0600386 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass3b0c3822018-06-01 09:38:20 -0600387 if map:
388 args.append('-m')
Simon Glass16b8d6b2018-07-06 10:27:42 -0600389 if update_dtb:
Simon Glass2569e102019-07-08 13:18:47 -0600390 args.append('-u')
Simon Glass93d17412018-09-14 04:57:23 -0600391 if not use_real_dtb:
392 args.append('--fake-dtb')
Simon Glass63aeaeb2021-03-18 20:25:05 +1300393 if not use_expanded:
394 args.append('--no-expanded')
Simon Glass53af22a2018-07-17 13:25:32 -0600395 if entry_args:
Simon Glass50979152019-05-14 15:53:41 -0600396 for arg, value in entry_args.items():
Simon Glass53af22a2018-07-17 13:25:32 -0600397 args.append('-a%s=%s' % (arg, value))
Simon Glass4f9f1052020-07-09 18:39:38 -0600398 if allow_missing:
399 args.append('-M')
Heiko Thierya89c8f22022-01-06 11:49:41 +0100400 if allow_fake_blobs:
401 args.append('--fake-ext-blobs')
Simon Glass4f9ee832022-01-09 20:14:09 -0700402 if force_missing_bintools:
403 args += ['--force-missing-bintools', force_missing_bintools]
Simon Glass0427bed2021-11-03 21:09:18 -0600404 if update_fdt_in_elf:
405 args += ['--update-fdt-in-elf', update_fdt_in_elf]
Simon Glass0bfa7b02018-09-14 04:57:12 -0600406 if images:
407 for image in images:
408 args += ['-i', image]
Simon Glass6cf99532020-09-01 05:13:59 -0600409 if extra_indirs:
410 for indir in extra_indirs:
411 args += ['-I', indir]
Simon Glass7fe91732017-11-13 18:55:00 -0700412 return self._DoBinman(*args)
Simon Glass4f443042016-11-25 20:15:52 -0700413
414 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glasse0ff8552016-11-25 20:15:53 -0700415 """Set up a new test device-tree file
416
417 The given file is compiled and set up as the device tree to be used
418 for ths test.
419
420 Args:
421 fname: Filename of .dts file to read
Simon Glass7ae5f312018-06-01 09:38:19 -0600422 outfile: Output filename for compiled device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700423
424 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600425 Contents of device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700426 """
Simon Glassa004f292019-07-20 12:23:49 -0600427 tmpdir = tempfile.mkdtemp(prefix='binmant.')
428 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
Simon Glass1d0ebf72019-05-14 15:53:42 -0600429 with open(dtb, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700430 data = fd.read()
431 TestFunctional._MakeInputFile(outfile, data)
Simon Glassa004f292019-07-20 12:23:49 -0600432 shutil.rmtree(tmpdir)
Simon Glasse0e62752018-10-01 21:12:41 -0600433 return data
Simon Glass4f443042016-11-25 20:15:52 -0700434
Simon Glass6ed45ba2018-09-14 04:57:24 -0600435 def _GetDtbContentsForSplTpl(self, dtb_data, name):
436 """Create a version of the main DTB for SPL or SPL
437
438 For testing we don't actually have different versions of the DTB. With
439 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
440 we don't normally have any unwanted nodes.
441
442 We still want the DTBs for SPL and TPL to be different though, since
443 otherwise it is confusing to know which one we are looking at. So add
444 an 'spl' or 'tpl' property to the top-level node.
Simon Glasse9d336d2020-09-01 05:13:55 -0600445
446 Args:
447 dtb_data: dtb data to modify (this should be a value devicetree)
448 name: Name of a new property to add
449
450 Returns:
451 New dtb data with the property added
Simon Glass6ed45ba2018-09-14 04:57:24 -0600452 """
453 dtb = fdt.Fdt.FromData(dtb_data)
454 dtb.Scan()
455 dtb.GetNode('/binman').AddZeroProp(name)
456 dtb.Sync(auto_resize=True)
457 dtb.Pack()
458 return dtb.GetContents()
459
Simon Glass63aeaeb2021-03-18 20:25:05 +1300460 def _DoReadFileDtb(self, fname, use_real_dtb=False, use_expanded=False,
461 map=False, update_dtb=False, entry_args=None,
Simon Glassc69d19c2021-07-06 10:36:37 -0600462 reset_dtbs=True, extra_indirs=None, threads=None):
Simon Glass4f443042016-11-25 20:15:52 -0700463 """Run binman and return the resulting image
464
465 This runs binman with a given test file and then reads the resulting
466 output file. It is a shortcut function since most tests need to do
467 these steps.
468
469 Raises an assertion failure if binman returns a non-zero exit code.
470
471 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600472 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass4f443042016-11-25 20:15:52 -0700473 use_real_dtb: True to use the test file as the contents of
474 the u-boot-dtb entry. Normally this is not needed and the
475 test contents (the U_BOOT_DTB_DATA string) can be used.
476 But in some test we need the real contents.
Simon Glass63aeaeb2021-03-18 20:25:05 +1300477 use_expanded: True to use expanded entries where available, e.g.
478 'u-boot-expanded' instead of 'u-boot'
Simon Glass3b0c3822018-06-01 09:38:20 -0600479 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600480 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600481 tree before packing it into the image
Simon Glasse9d336d2020-09-01 05:13:55 -0600482 entry_args: Dict of entry args to supply to binman
483 key: arg name
484 value: value of that arg
485 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
486 function. If reset_dtbs is True, then the original test dtb
487 is written back before this function finishes
Simon Glass6cf99532020-09-01 05:13:59 -0600488 extra_indirs: Extra input directories to add using -I
Simon Glassc69d19c2021-07-06 10:36:37 -0600489 threads: Number of threads to use (None for default, 0 for
490 single-threaded)
Simon Glasse0ff8552016-11-25 20:15:53 -0700491
492 Returns:
493 Tuple:
494 Resulting image contents
495 Device tree contents
Simon Glass3b0c3822018-06-01 09:38:20 -0600496 Map data showing contents of image (or None if none)
Simon Glassea6922e2018-07-17 13:25:27 -0600497 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass4f443042016-11-25 20:15:52 -0700498 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700499 dtb_data = None
Simon Glass4f443042016-11-25 20:15:52 -0700500 # Use the compiled test file as the u-boot-dtb input
501 if use_real_dtb:
Simon Glasse0ff8552016-11-25 20:15:53 -0700502 dtb_data = self._SetupDtb(fname)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600503
504 # For testing purposes, make a copy of the DT for SPL and TPL. Add
505 # a node indicating which it is, so aid verification.
506 for name in ['spl', 'tpl']:
507 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
508 outfile = os.path.join(self._indir, dtb_fname)
509 TestFunctional._MakeInputFile(dtb_fname,
510 self._GetDtbContentsForSplTpl(dtb_data, name))
Simon Glass4f443042016-11-25 20:15:52 -0700511
512 try:
Simon Glass53af22a2018-07-17 13:25:32 -0600513 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glass6cf99532020-09-01 05:13:59 -0600514 entry_args=entry_args, use_real_dtb=use_real_dtb,
Simon Glassc69d19c2021-07-06 10:36:37 -0600515 use_expanded=use_expanded, extra_indirs=extra_indirs,
516 threads=threads)
Simon Glass4f443042016-11-25 20:15:52 -0700517 self.assertEqual(0, retcode)
Simon Glassc1aa66e2022-01-29 14:14:04 -0700518 out_dtb_fname = tools.get_output_filename('u-boot.dtb.out')
Simon Glass4f443042016-11-25 20:15:52 -0700519
520 # Find the (only) image, read it and return its contents
521 image = control.images['image']
Simon Glassc1aa66e2022-01-29 14:14:04 -0700522 image_fname = tools.get_output_filename('image.bin')
Simon Glass16b8d6b2018-07-06 10:27:42 -0600523 self.assertTrue(os.path.exists(image_fname))
Simon Glass3b0c3822018-06-01 09:38:20 -0600524 if map:
Simon Glassc1aa66e2022-01-29 14:14:04 -0700525 map_fname = tools.get_output_filename('image.map')
Simon Glass3b0c3822018-06-01 09:38:20 -0600526 with open(map_fname) as fd:
527 map_data = fd.read()
528 else:
529 map_data = None
Simon Glass1d0ebf72019-05-14 15:53:42 -0600530 with open(image_fname, 'rb') as fd:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600531 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass4f443042016-11-25 20:15:52 -0700532 finally:
533 # Put the test file back
Simon Glass6ed45ba2018-09-14 04:57:24 -0600534 if reset_dtbs and use_real_dtb:
Simon Glassb8ef5b62018-07-17 13:25:48 -0600535 self._ResetDtbs()
Simon Glass4f443042016-11-25 20:15:52 -0700536
Simon Glass3c081312019-07-08 14:25:26 -0600537 def _DoReadFileRealDtb(self, fname):
538 """Run binman with a real .dtb file and return the resulting data
539
540 Args:
541 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
542
543 Returns:
544 Resulting image contents
545 """
546 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
547
Simon Glasse0ff8552016-11-25 20:15:53 -0700548 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass7ae5f312018-06-01 09:38:19 -0600549 """Helper function which discards the device-tree binary
550
551 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600552 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600553 use_real_dtb: True to use the test file as the contents of
554 the u-boot-dtb entry. Normally this is not needed and the
555 test contents (the U_BOOT_DTB_DATA string) can be used.
556 But in some test we need the real contents.
Simon Glassea6922e2018-07-17 13:25:27 -0600557
558 Returns:
559 Resulting image contents
Simon Glass7ae5f312018-06-01 09:38:19 -0600560 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700561 return self._DoReadFileDtb(fname, use_real_dtb)[0]
562
Simon Glass4f443042016-11-25 20:15:52 -0700563 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600564 def _MakeInputFile(cls, fname, contents):
Simon Glass4f443042016-11-25 20:15:52 -0700565 """Create a new test input file, creating directories as needed
566
567 Args:
Simon Glass3ab95982018-08-01 15:22:37 -0600568 fname: Filename to create
Simon Glass4f443042016-11-25 20:15:52 -0700569 contents: File contents to write in to the file
570 Returns:
571 Full pathname of file created
572 """
Simon Glassb986b3b2019-08-24 07:22:43 -0600573 pathname = os.path.join(cls._indir, fname)
Simon Glass4f443042016-11-25 20:15:52 -0700574 dirname = os.path.dirname(pathname)
575 if dirname and not os.path.exists(dirname):
576 os.makedirs(dirname)
577 with open(pathname, 'wb') as fd:
578 fd.write(contents)
579 return pathname
580
581 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600582 def _MakeInputDir(cls, dirname):
Simon Glass0ef87aa2018-07-17 13:25:44 -0600583 """Create a new test input directory, creating directories as needed
584
585 Args:
586 dirname: Directory name to create
587
588 Returns:
589 Full pathname of directory created
590 """
Simon Glassb986b3b2019-08-24 07:22:43 -0600591 pathname = os.path.join(cls._indir, dirname)
Simon Glass0ef87aa2018-07-17 13:25:44 -0600592 if not os.path.exists(pathname):
593 os.makedirs(pathname)
594 return pathname
595
596 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600597 def _SetupSplElf(cls, src_fname='bss_data'):
Simon Glass11ae93e2018-10-01 21:12:47 -0600598 """Set up an ELF file with a '_dt_ucode_base_size' symbol
599
600 Args:
601 Filename of ELF file to use as SPL
602 """
Simon Glassc9a0b272019-08-24 07:22:59 -0600603 TestFunctional._MakeInputFile('spl/u-boot-spl',
Simon Glassc1aa66e2022-01-29 14:14:04 -0700604 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass11ae93e2018-10-01 21:12:47 -0600605
606 @classmethod
Simon Glass2090f1e2019-08-24 07:23:00 -0600607 def _SetupTplElf(cls, src_fname='bss_data'):
608 """Set up an ELF file with a '_dt_ucode_base_size' symbol
609
610 Args:
611 Filename of ELF file to use as TPL
612 """
613 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
Simon Glassc1aa66e2022-01-29 14:14:04 -0700614 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass2090f1e2019-08-24 07:23:00 -0600615
616 @classmethod
Simon Glass0ba4b3d2020-07-09 18:39:41 -0600617 def _SetupDescriptor(cls):
618 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
619 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
620
621 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600622 def TestFile(cls, fname):
623 return os.path.join(cls._binman_dir, 'test', fname)
Simon Glass4f443042016-11-25 20:15:52 -0700624
Simon Glass53e22bf2019-08-24 07:22:53 -0600625 @classmethod
626 def ElfTestFile(cls, fname):
627 return os.path.join(cls._elf_testdir, fname)
628
Simon Glass4f443042016-11-25 20:15:52 -0700629 def AssertInList(self, grep_list, target):
630 """Assert that at least one of a list of things is in a target
631
632 Args:
633 grep_list: List of strings to check
634 target: Target string
635 """
636 for grep in grep_list:
637 if grep in target:
638 return
Simon Glass1fc62de2019-05-17 22:00:50 -0600639 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass4f443042016-11-25 20:15:52 -0700640
641 def CheckNoGaps(self, entries):
642 """Check that all entries fit together without gaps
643
644 Args:
645 entries: List of entries to check
646 """
Simon Glass3ab95982018-08-01 15:22:37 -0600647 offset = 0
Simon Glass4f443042016-11-25 20:15:52 -0700648 for entry in entries.values():
Simon Glass3ab95982018-08-01 15:22:37 -0600649 self.assertEqual(offset, entry.offset)
650 offset += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700651
Simon Glasse0ff8552016-11-25 20:15:53 -0700652 def GetFdtLen(self, dtb):
Simon Glass7ae5f312018-06-01 09:38:19 -0600653 """Get the totalsize field from a device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700654
655 Args:
Simon Glass7ae5f312018-06-01 09:38:19 -0600656 dtb: Device-tree binary contents
Simon Glasse0ff8552016-11-25 20:15:53 -0700657
658 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600659 Total size of device-tree binary, from the header
Simon Glasse0ff8552016-11-25 20:15:53 -0700660 """
661 return struct.unpack('>L', dtb[4:8])[0]
662
Simon Glass086cec92019-07-08 14:25:27 -0600663 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glass16b8d6b2018-07-06 10:27:42 -0600664 def AddNode(node, path):
665 if node.name != '/':
666 path += '/' + node.name
Simon Glass086cec92019-07-08 14:25:27 -0600667 for prop in node.props.values():
668 if prop.name in prop_names:
669 prop_path = path + ':' + prop.name
670 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
671 prop.value)
Simon Glass16b8d6b2018-07-06 10:27:42 -0600672 for subnode in node.subnodes:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600673 AddNode(subnode, path)
674
675 tree = {}
Simon Glass16b8d6b2018-07-06 10:27:42 -0600676 AddNode(dtb.GetRoot(), '')
677 return tree
678
Simon Glass4f443042016-11-25 20:15:52 -0700679 def testRun(self):
680 """Test a basic run with valid args"""
681 result = self._RunBinman('-h')
682
683 def testFullHelp(self):
684 """Test that the full help is displayed with -H"""
685 result = self._RunBinman('-H')
Simon Glass61adb2d2021-03-18 20:25:13 +1300686 help_file = os.path.join(self._binman_dir, 'README.rst')
Tom Rini3759df02018-01-16 15:29:50 -0500687 # Remove possible extraneous strings
688 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
689 gothelp = result.stdout.replace(extra, '')
690 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass4f443042016-11-25 20:15:52 -0700691 self.assertEqual(0, len(result.stderr))
692 self.assertEqual(0, result.return_code)
693
694 def testFullHelpInternal(self):
695 """Test that the full help is displayed with -H"""
696 try:
697 command.test_result = command.CommandResult()
698 result = self._DoBinman('-H')
Simon Glass61adb2d2021-03-18 20:25:13 +1300699 help_file = os.path.join(self._binman_dir, 'README.rst')
Simon Glass4f443042016-11-25 20:15:52 -0700700 finally:
701 command.test_result = None
702
703 def testHelp(self):
704 """Test that the basic help is displayed with -h"""
705 result = self._RunBinman('-h')
706 self.assertTrue(len(result.stdout) > 200)
707 self.assertEqual(0, len(result.stderr))
708 self.assertEqual(0, result.return_code)
709
Simon Glass4f443042016-11-25 20:15:52 -0700710 def testBoard(self):
711 """Test that we can run it with a specific board"""
Simon Glass741f2d62018-10-01 12:22:30 -0600712 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass4f443042016-11-25 20:15:52 -0700713 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glass63aeaeb2021-03-18 20:25:05 +1300714 result = self._DoBinman('build', '-n', '-b', 'sandbox')
Simon Glass4f443042016-11-25 20:15:52 -0700715 self.assertEqual(0, result)
716
717 def testNeedBoard(self):
718 """Test that we get an error when no board ius supplied"""
719 with self.assertRaises(ValueError) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600720 result = self._DoBinman('build')
Simon Glass4f443042016-11-25 20:15:52 -0700721 self.assertIn("Must provide a board to process (use -b <board>)",
722 str(e.exception))
723
724 def testMissingDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600725 """Test that an invalid device-tree file generates an error"""
Simon Glass4f443042016-11-25 20:15:52 -0700726 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600727 self._RunBinman('build', '-d', 'missing_file')
Simon Glass4f443042016-11-25 20:15:52 -0700728 # We get one error from libfdt, and a different one from fdtget.
729 self.AssertInList(["Couldn't open blob from 'missing_file'",
730 'No such file or directory'], str(e.exception))
731
732 def testBrokenDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600733 """Test that an invalid device-tree source file generates an error
Simon Glass4f443042016-11-25 20:15:52 -0700734
735 Since this is a source file it should be compiled and the error
736 will come from the device-tree compiler (dtc).
737 """
738 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600739 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700740 self.assertIn("FATAL ERROR: Unable to parse input tree",
741 str(e.exception))
742
743 def testMissingNode(self):
744 """Test that a device tree without a 'binman' node generates an error"""
745 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600746 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700747 self.assertIn("does not have a 'binman' node", str(e.exception))
748
749 def testEmpty(self):
750 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glass53cd5d92019-07-08 14:25:29 -0600751 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700752 self.assertEqual(0, len(result.stderr))
753 self.assertEqual(0, result.return_code)
754
755 def testInvalidEntry(self):
756 """Test that an invalid entry is flagged"""
757 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600758 result = self._RunBinman('build', '-d',
Simon Glass741f2d62018-10-01 12:22:30 -0600759 self.TestFile('004_invalid_entry.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700760 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
761 "'/binman/not-a-valid-type'", str(e.exception))
762
763 def testSimple(self):
764 """Test a simple binman with a single file"""
Simon Glass741f2d62018-10-01 12:22:30 -0600765 data = self._DoReadFile('005_simple.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700766 self.assertEqual(U_BOOT_DATA, data)
767
Simon Glass7fe91732017-11-13 18:55:00 -0700768 def testSimpleDebug(self):
769 """Test a simple binman run with debugging enabled"""
Simon Glasse2705fa2019-07-08 14:25:53 -0600770 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass7fe91732017-11-13 18:55:00 -0700771
Simon Glass4f443042016-11-25 20:15:52 -0700772 def testDual(self):
773 """Test that we can handle creating two images
774
775 This also tests image padding.
776 """
Simon Glass741f2d62018-10-01 12:22:30 -0600777 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700778 self.assertEqual(0, retcode)
779
780 image = control.images['image1']
Simon Glass8beb11e2019-07-08 14:25:47 -0600781 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glassc1aa66e2022-01-29 14:14:04 -0700782 fname = tools.get_output_filename('image1.bin')
Simon Glass4f443042016-11-25 20:15:52 -0700783 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600784 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700785 data = fd.read()
786 self.assertEqual(U_BOOT_DATA, data)
787
788 image = control.images['image2']
Simon Glass8beb11e2019-07-08 14:25:47 -0600789 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glassc1aa66e2022-01-29 14:14:04 -0700790 fname = tools.get_output_filename('image2.bin')
Simon Glass4f443042016-11-25 20:15:52 -0700791 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600792 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700793 data = fd.read()
794 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glassc1aa66e2022-01-29 14:14:04 -0700795 self.assertEqual(tools.get_bytes(0, 3), data[:3])
796 self.assertEqual(tools.get_bytes(0, 5), data[7:])
Simon Glass4f443042016-11-25 20:15:52 -0700797
798 def testBadAlign(self):
799 """Test that an invalid alignment value is detected"""
800 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600801 self._DoTestFile('007_bad_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700802 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
803 "of two", str(e.exception))
804
805 def testPackSimple(self):
806 """Test that packing works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600807 retcode = self._DoTestFile('008_pack.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700808 self.assertEqual(0, retcode)
809 self.assertIn('image', control.images)
810 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600811 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700812 self.assertEqual(5, len(entries))
813
814 # First u-boot
815 self.assertIn('u-boot', entries)
816 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600817 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700818 self.assertEqual(len(U_BOOT_DATA), entry.size)
819
820 # Second u-boot, aligned to 16-byte boundary
821 self.assertIn('u-boot-align', entries)
822 entry = entries['u-boot-align']
Simon Glass3ab95982018-08-01 15:22:37 -0600823 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700824 self.assertEqual(len(U_BOOT_DATA), entry.size)
825
826 # Third u-boot, size 23 bytes
827 self.assertIn('u-boot-size', entries)
828 entry = entries['u-boot-size']
Simon Glass3ab95982018-08-01 15:22:37 -0600829 self.assertEqual(20, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700830 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
831 self.assertEqual(23, entry.size)
832
833 # Fourth u-boot, placed immediate after the above
834 self.assertIn('u-boot-next', entries)
835 entry = entries['u-boot-next']
Simon Glass3ab95982018-08-01 15:22:37 -0600836 self.assertEqual(43, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700837 self.assertEqual(len(U_BOOT_DATA), entry.size)
838
Simon Glass3ab95982018-08-01 15:22:37 -0600839 # Fifth u-boot, placed at a fixed offset
Simon Glass4f443042016-11-25 20:15:52 -0700840 self.assertIn('u-boot-fixed', entries)
841 entry = entries['u-boot-fixed']
Simon Glass3ab95982018-08-01 15:22:37 -0600842 self.assertEqual(61, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700843 self.assertEqual(len(U_BOOT_DATA), entry.size)
844
Simon Glass8beb11e2019-07-08 14:25:47 -0600845 self.assertEqual(65, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700846
847 def testPackExtra(self):
848 """Test that extra packing feature works as expected"""
Simon Glass4eec34c2020-10-26 17:40:10 -0600849 data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
850 update_dtb=True)
Simon Glass4f443042016-11-25 20:15:52 -0700851
Simon Glass4f443042016-11-25 20:15:52 -0700852 self.assertIn('image', control.images)
853 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600854 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700855 self.assertEqual(5, len(entries))
856
857 # First u-boot with padding before and after
858 self.assertIn('u-boot', entries)
859 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600860 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700861 self.assertEqual(3, entry.pad_before)
862 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600863 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassc1aa66e2022-01-29 14:14:04 -0700864 self.assertEqual(tools.get_bytes(0, 3) + U_BOOT_DATA +
865 tools.get_bytes(0, 5), data[:entry.size])
Simon Glassef439ed2020-10-26 17:40:08 -0600866 pos = entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700867
868 # Second u-boot has an aligned size, but it has no effect
869 self.assertIn('u-boot-align-size-nop', entries)
870 entry = entries['u-boot-align-size-nop']
Simon Glassef439ed2020-10-26 17:40:08 -0600871 self.assertEqual(pos, entry.offset)
872 self.assertEqual(len(U_BOOT_DATA), entry.size)
873 self.assertEqual(U_BOOT_DATA, entry.data)
874 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
875 pos += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700876
877 # Third u-boot has an aligned size too
878 self.assertIn('u-boot-align-size', entries)
879 entry = entries['u-boot-align-size']
Simon Glassef439ed2020-10-26 17:40:08 -0600880 self.assertEqual(pos, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700881 self.assertEqual(32, entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600882 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassc1aa66e2022-01-29 14:14:04 -0700883 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
Simon Glassef439ed2020-10-26 17:40:08 -0600884 data[pos:pos + entry.size])
885 pos += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700886
887 # Fourth u-boot has an aligned end
888 self.assertIn('u-boot-align-end', entries)
889 entry = entries['u-boot-align-end']
Simon Glass3ab95982018-08-01 15:22:37 -0600890 self.assertEqual(48, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700891 self.assertEqual(16, entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600892 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glassc1aa66e2022-01-29 14:14:04 -0700893 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 16 - len(U_BOOT_DATA)),
Simon Glassef439ed2020-10-26 17:40:08 -0600894 data[pos:pos + entry.size])
895 pos += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700896
897 # Fifth u-boot immediately afterwards
898 self.assertIn('u-boot-align-both', entries)
899 entry = entries['u-boot-align-both']
Simon Glass3ab95982018-08-01 15:22:37 -0600900 self.assertEqual(64, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700901 self.assertEqual(64, entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600902 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glassc1aa66e2022-01-29 14:14:04 -0700903 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 64 - len(U_BOOT_DATA)),
Simon Glassef439ed2020-10-26 17:40:08 -0600904 data[pos:pos + entry.size])
Simon Glass4f443042016-11-25 20:15:52 -0700905
906 self.CheckNoGaps(entries)
Simon Glass8beb11e2019-07-08 14:25:47 -0600907 self.assertEqual(128, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700908
Simon Glass4eec34c2020-10-26 17:40:10 -0600909 dtb = fdt.Fdt(out_dtb_fname)
910 dtb.Scan()
911 props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
912 expected = {
913 'image-pos': 0,
914 'offset': 0,
915 'size': 128,
916
917 'u-boot:image-pos': 0,
918 'u-boot:offset': 0,
919 'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
920
921 'u-boot-align-size-nop:image-pos': 12,
922 'u-boot-align-size-nop:offset': 12,
923 'u-boot-align-size-nop:size': 4,
924
925 'u-boot-align-size:image-pos': 16,
926 'u-boot-align-size:offset': 16,
927 'u-boot-align-size:size': 32,
928
929 'u-boot-align-end:image-pos': 48,
930 'u-boot-align-end:offset': 48,
931 'u-boot-align-end:size': 16,
932
933 'u-boot-align-both:image-pos': 64,
934 'u-boot-align-both:offset': 64,
935 'u-boot-align-both:size': 64,
936 }
937 self.assertEqual(expected, props)
938
Simon Glass4f443042016-11-25 20:15:52 -0700939 def testPackAlignPowerOf2(self):
940 """Test that invalid entry alignment is detected"""
941 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600942 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700943 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
944 "of two", str(e.exception))
945
946 def testPackAlignSizePowerOf2(self):
947 """Test that invalid entry size alignment is detected"""
948 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600949 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700950 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
951 "power of two", str(e.exception))
952
953 def testPackInvalidAlign(self):
Simon Glass3ab95982018-08-01 15:22:37 -0600954 """Test detection of an offset that does not match its alignment"""
Simon Glass4f443042016-11-25 20:15:52 -0700955 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600956 self._DoTestFile('012_pack_inv_align.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600957 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700958 "align 0x4 (4)", str(e.exception))
959
960 def testPackInvalidSizeAlign(self):
961 """Test that invalid entry size alignment is detected"""
962 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600963 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700964 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
965 "align-size 0x4 (4)", str(e.exception))
966
967 def testPackOverlap(self):
968 """Test that overlapping regions are detected"""
969 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600970 self._DoTestFile('014_pack_overlap.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600971 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -0700972 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
973 str(e.exception))
974
975 def testPackEntryOverflow(self):
976 """Test that entries that overflow their size are detected"""
977 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600978 self._DoTestFile('015_pack_overflow.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700979 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
980 "but entry size is 0x3 (3)", str(e.exception))
981
982 def testPackImageOverflow(self):
983 """Test that entries which overflow the image size are detected"""
984 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600985 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600986 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass4f443042016-11-25 20:15:52 -0700987 "size 0x3 (3)", str(e.exception))
988
989 def testPackImageSize(self):
990 """Test that the image size can be set"""
Simon Glass741f2d62018-10-01 12:22:30 -0600991 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700992 self.assertEqual(0, retcode)
993 self.assertIn('image', control.images)
994 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -0600995 self.assertEqual(7, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700996
997 def testPackImageSizeAlign(self):
998 """Test that image size alignemnt works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600999 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001000 self.assertEqual(0, retcode)
1001 self.assertIn('image', control.images)
1002 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -06001003 self.assertEqual(16, image.size)
Simon Glass4f443042016-11-25 20:15:52 -07001004
1005 def testPackInvalidImageAlign(self):
1006 """Test that invalid image alignment is detected"""
1007 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001008 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glass8f1da502018-06-01 09:38:12 -06001009 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass4f443042016-11-25 20:15:52 -07001010 "align-size 0x8 (8)", str(e.exception))
1011
Simon Glass8d2ef3e2022-02-11 13:23:21 -07001012 def testPackAlignPowerOf2Inv(self):
Simon Glass4f443042016-11-25 20:15:52 -07001013 """Test that invalid image alignment is detected"""
1014 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001015 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -06001016 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass4f443042016-11-25 20:15:52 -07001017 "two", str(e.exception))
1018
1019 def testImagePadByte(self):
1020 """Test that the image pad byte can be specified"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001021 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001022 data = self._DoReadFile('021_image_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001023 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0xff, 1) +
Simon Glasse6d85ff2019-05-14 15:53:47 -06001024 U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -07001025
1026 def testImageName(self):
1027 """Test that image files can be named"""
Simon Glass741f2d62018-10-01 12:22:30 -06001028 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001029 self.assertEqual(0, retcode)
1030 image = control.images['image1']
Simon Glassc1aa66e2022-01-29 14:14:04 -07001031 fname = tools.get_output_filename('test-name')
Simon Glass4f443042016-11-25 20:15:52 -07001032 self.assertTrue(os.path.exists(fname))
1033
1034 image = control.images['image2']
Simon Glassc1aa66e2022-01-29 14:14:04 -07001035 fname = tools.get_output_filename('test-name.xx')
Simon Glass4f443042016-11-25 20:15:52 -07001036 self.assertTrue(os.path.exists(fname))
1037
1038 def testBlobFilename(self):
1039 """Test that generic blobs can be provided by filename"""
Simon Glass741f2d62018-10-01 12:22:30 -06001040 data = self._DoReadFile('023_blob.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001041 self.assertEqual(BLOB_DATA, data)
1042
1043 def testPackSorted(self):
1044 """Test that entries can be sorted"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001045 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001046 data = self._DoReadFile('024_sorted.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001047 self.assertEqual(tools.get_bytes(0, 1) + U_BOOT_SPL_DATA +
1048 tools.get_bytes(0, 2) + U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -07001049
Simon Glass3ab95982018-08-01 15:22:37 -06001050 def testPackZeroOffset(self):
1051 """Test that an entry at offset 0 is not given a new offset"""
Simon Glass4f443042016-11-25 20:15:52 -07001052 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001053 self._DoTestFile('025_pack_zero_size.dts')
Simon Glass3ab95982018-08-01 15:22:37 -06001054 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -07001055 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1056 str(e.exception))
1057
1058 def testPackUbootDtb(self):
1059 """Test that a device tree can be added to U-Boot"""
Simon Glass741f2d62018-10-01 12:22:30 -06001060 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001061 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glasse0ff8552016-11-25 20:15:53 -07001062
1063 def testPackX86RomNoSize(self):
1064 """Test that the end-at-4gb property requires a size property"""
1065 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001066 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -06001067 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glasse0ff8552016-11-25 20:15:53 -07001068 "using end-at-4gb", str(e.exception))
1069
Jagdish Gediya94b57db2018-09-03 21:35:07 +05301070 def test4gbAndSkipAtStartTogether(self):
1071 """Test that the end-at-4gb and skip-at-size property can't be used
1072 together"""
1073 with self.assertRaises(ValueError) as e:
Simon Glassdfdd2b62019-08-24 07:23:02 -06001074 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -06001075 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya94b57db2018-09-03 21:35:07 +05301076 "'skip-at-start'", str(e.exception))
1077
Simon Glasse0ff8552016-11-25 20:15:53 -07001078 def testPackX86RomOutside(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001079 """Test that the end-at-4gb property checks for offset boundaries"""
Simon Glasse0ff8552016-11-25 20:15:53 -07001080 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001081 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glasse6bed4f2020-10-26 17:40:05 -06001082 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
1083 "is outside the section '/binman' starting at "
1084 '0xffffffe0 (4294967264) of size 0x20 (32)',
Simon Glasse0ff8552016-11-25 20:15:53 -07001085 str(e.exception))
1086
1087 def testPackX86Rom(self):
1088 """Test that a basic x86 ROM can be created"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001089 self._SetupSplElf()
Simon Glass9255f3c2019-08-24 07:23:01 -06001090 data = self._DoReadFile('029_x86_rom.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001091 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 3) + U_BOOT_SPL_DATA +
1092 tools.get_bytes(0, 2), data)
Simon Glasse0ff8552016-11-25 20:15:53 -07001093
1094 def testPackX86RomMeNoDesc(self):
1095 """Test that an invalid Intel descriptor entry is detected"""
Simon Glass0ba4b3d2020-07-09 18:39:41 -06001096 try:
Simon Glass52b10dd2020-07-25 15:11:19 -06001097 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
Simon Glass0ba4b3d2020-07-09 18:39:41 -06001098 with self.assertRaises(ValueError) as e:
Simon Glass52b10dd2020-07-25 15:11:19 -06001099 self._DoTestFile('163_x86_rom_me_empty.dts')
Simon Glass0ba4b3d2020-07-09 18:39:41 -06001100 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1101 str(e.exception))
1102 finally:
1103 self._SetupDescriptor()
Simon Glasse0ff8552016-11-25 20:15:53 -07001104
1105 def testPackX86RomBadDesc(self):
1106 """Test that the Intel requires a descriptor entry"""
1107 with self.assertRaises(ValueError) as e:
Simon Glass9255f3c2019-08-24 07:23:01 -06001108 self._DoTestFile('030_x86_rom_me_no_desc.dts')
Simon Glass3ab95982018-08-01 15:22:37 -06001109 self.assertIn("Node '/binman/intel-me': No offset set with "
1110 "offset-unset: should another entry provide this correct "
1111 "offset?", str(e.exception))
Simon Glasse0ff8552016-11-25 20:15:53 -07001112
1113 def testPackX86RomMe(self):
1114 """Test that an x86 ROM with an ME region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001115 data = self._DoReadFile('031_x86_rom_me.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001116 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glassc5ac1382019-07-08 13:18:54 -06001117 if data[:0x1000] != expected_desc:
1118 self.fail('Expected descriptor binary at start of image')
Simon Glasse0ff8552016-11-25 20:15:53 -07001119 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1120
1121 def testPackVga(self):
1122 """Test that an image with a VGA binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001123 data = self._DoReadFile('032_intel_vga.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -07001124 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1125
1126 def testPackStart16(self):
1127 """Test that an image with an x86 start16 region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001128 data = self._DoReadFile('033_x86_start16.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -07001129 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1130
Jagdish Gediya9d368f32018-09-03 21:35:08 +05301131 def testPackPowerpcMpc85xxBootpgResetvec(self):
1132 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1133 created"""
Simon Glassdfdd2b62019-08-24 07:23:02 -06001134 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
Jagdish Gediya9d368f32018-09-03 21:35:08 +05301135 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1136
Simon Glass736bb0a2018-07-06 10:27:17 -06001137 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glassadc57012018-07-06 10:27:16 -06001138 """Handle running a test for insertion of microcode
1139
1140 Args:
1141 dts_fname: Name of test .dts file
1142 nodtb_data: Data that we expect in the first section
Simon Glass736bb0a2018-07-06 10:27:17 -06001143 ucode_second: True if the microsecond entry is second instead of
1144 third
Simon Glassadc57012018-07-06 10:27:16 -06001145
1146 Returns:
1147 Tuple:
1148 Contents of first region (U-Boot or SPL)
Simon Glass3ab95982018-08-01 15:22:37 -06001149 Offset and size components of microcode pointer, as inserted
Simon Glassadc57012018-07-06 10:27:16 -06001150 in the above (two 4-byte words)
1151 """
Simon Glass6b187df2017-11-12 21:52:27 -07001152 data = self._DoReadFile(dts_fname, True)
Simon Glasse0ff8552016-11-25 20:15:53 -07001153
1154 # Now check the device tree has no microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001155 if ucode_second:
1156 ucode_content = data[len(nodtb_data):]
1157 ucode_pos = len(nodtb_data)
1158 dtb_with_ucode = ucode_content[16:]
1159 fdt_len = self.GetFdtLen(dtb_with_ucode)
1160 else:
1161 dtb_with_ucode = data[len(nodtb_data):]
1162 fdt_len = self.GetFdtLen(dtb_with_ucode)
1163 ucode_content = dtb_with_ucode[fdt_len:]
1164 ucode_pos = len(nodtb_data) + fdt_len
Simon Glassc1aa66e2022-01-29 14:14:04 -07001165 fname = tools.get_output_filename('test.dtb')
Simon Glasse0ff8552016-11-25 20:15:53 -07001166 with open(fname, 'wb') as fd:
Simon Glassadc57012018-07-06 10:27:16 -06001167 fd.write(dtb_with_ucode)
Simon Glassec3f3782017-05-27 07:38:29 -06001168 dtb = fdt.FdtScan(fname)
1169 ucode = dtb.GetNode('/microcode')
Simon Glasse0ff8552016-11-25 20:15:53 -07001170 self.assertTrue(ucode)
1171 for node in ucode.subnodes:
1172 self.assertFalse(node.props.get('data'))
1173
Simon Glasse0ff8552016-11-25 20:15:53 -07001174 # Check that the microcode appears immediately after the Fdt
1175 # This matches the concatenation of the data properties in
Simon Glass87722132017-11-12 21:52:26 -07001176 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glasse0ff8552016-11-25 20:15:53 -07001177 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1178 0x78235609)
Simon Glassadc57012018-07-06 10:27:16 -06001179 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glasse0ff8552016-11-25 20:15:53 -07001180
1181 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -06001182 # expected offset and size
Simon Glasse0ff8552016-11-25 20:15:53 -07001183 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1184 len(ucode_data))
Simon Glass736bb0a2018-07-06 10:27:17 -06001185 u_boot = data[:len(nodtb_data)]
1186 return u_boot, pos_and_size
Simon Glass6b187df2017-11-12 21:52:27 -07001187
1188 def testPackUbootMicrocode(self):
1189 """Test that x86 microcode can be handled correctly
1190
1191 We expect to see the following in the image, in order:
1192 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1193 place
1194 u-boot.dtb with the microcode removed
1195 the microcode
1196 """
Simon Glass741f2d62018-10-01 12:22:30 -06001197 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass6b187df2017-11-12 21:52:27 -07001198 U_BOOT_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001199 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1200 b' somewhere in here', first)
Simon Glasse0ff8552016-11-25 20:15:53 -07001201
Simon Glass160a7662017-05-27 07:38:26 -06001202 def _RunPackUbootSingleMicrocode(self):
Simon Glasse0ff8552016-11-25 20:15:53 -07001203 """Test that x86 microcode can be handled correctly
1204
1205 We expect to see the following in the image, in order:
1206 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1207 place
1208 u-boot.dtb with the microcode
1209 an empty microcode region
1210 """
1211 # We need the libfdt library to run this test since only that allows
1212 # finding the offset of a property. This is required by
1213 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass741f2d62018-10-01 12:22:30 -06001214 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glasse0ff8552016-11-25 20:15:53 -07001215
1216 second = data[len(U_BOOT_NODTB_DATA):]
1217
1218 fdt_len = self.GetFdtLen(second)
1219 third = second[fdt_len:]
1220 second = second[:fdt_len]
1221
Simon Glass160a7662017-05-27 07:38:26 -06001222 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1223 self.assertIn(ucode_data, second)
1224 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -07001225
Simon Glass160a7662017-05-27 07:38:26 -06001226 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -06001227 # expected offset and size
Simon Glass160a7662017-05-27 07:38:26 -06001228 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1229 len(ucode_data))
1230 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glassc6c10e72019-05-17 22:00:46 -06001231 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1232 b' somewhere in here', first)
Simon Glassc49deb82016-11-25 20:15:54 -07001233
Simon Glass75db0862016-11-25 20:15:55 -07001234 def testPackUbootSingleMicrocode(self):
1235 """Test that x86 microcode can be handled correctly with fdt_normal.
1236 """
Simon Glass160a7662017-05-27 07:38:26 -06001237 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001238
Simon Glassc49deb82016-11-25 20:15:54 -07001239 def testUBootImg(self):
1240 """Test that u-boot.img can be put in a file"""
Simon Glass741f2d62018-10-01 12:22:30 -06001241 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glassc49deb82016-11-25 20:15:54 -07001242 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glass75db0862016-11-25 20:15:55 -07001243
1244 def testNoMicrocode(self):
1245 """Test that a missing microcode region is detected"""
1246 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001247 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001248 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1249 "node found in ", str(e.exception))
1250
1251 def testMicrocodeWithoutNode(self):
1252 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1253 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001254 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001255 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1256 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1257
1258 def testMicrocodeWithoutNode2(self):
1259 """Test that a missing u-boot-ucode node is detected"""
1260 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001261 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001262 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1263 "microcode region u-boot-ucode", str(e.exception))
1264
1265 def testMicrocodeWithoutPtrInElf(self):
1266 """Test that a U-Boot binary without the microcode symbol is detected"""
1267 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glass75db0862016-11-25 20:15:55 -07001268 try:
Simon Glassbccd91d2019-08-24 07:22:55 -06001269 TestFunctional._MakeInputFile('u-boot',
Simon Glassc1aa66e2022-01-29 14:14:04 -07001270 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass75db0862016-11-25 20:15:55 -07001271
1272 with self.assertRaises(ValueError) as e:
Simon Glass160a7662017-05-27 07:38:26 -06001273 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001274 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1275 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1276
1277 finally:
1278 # Put the original file back
Simon Glassf514d8f2019-08-24 07:22:54 -06001279 TestFunctional._MakeInputFile('u-boot',
Simon Glassc1aa66e2022-01-29 14:14:04 -07001280 tools.read_file(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glass75db0862016-11-25 20:15:55 -07001281
1282 def testMicrocodeNotInImage(self):
1283 """Test that microcode must be placed within the image"""
1284 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001285 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001286 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1287 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glass25ac0e62018-06-01 09:38:14 -06001288 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glass75db0862016-11-25 20:15:55 -07001289
1290 def testWithoutMicrocode(self):
1291 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glassbccd91d2019-08-24 07:22:55 -06001292 TestFunctional._MakeInputFile('u-boot',
Simon Glassc1aa66e2022-01-29 14:14:04 -07001293 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass741f2d62018-10-01 12:22:30 -06001294 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001295
1296 # Now check the device tree has no microcode
1297 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1298 second = data[len(U_BOOT_NODTB_DATA):]
1299
1300 fdt_len = self.GetFdtLen(second)
1301 self.assertEqual(dtb, second[:fdt_len])
1302
1303 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1304 third = data[used_len:]
Simon Glassc1aa66e2022-01-29 14:14:04 -07001305 self.assertEqual(tools.get_bytes(0, 0x200 - used_len), third)
Simon Glass75db0862016-11-25 20:15:55 -07001306
1307 def testUnknownPosSize(self):
1308 """Test that microcode must be placed within the image"""
1309 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001310 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glass3ab95982018-08-01 15:22:37 -06001311 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glass75db0862016-11-25 20:15:55 -07001312 "entry 'invalid-entry'", str(e.exception))
Simon Glassda229092016-11-25 20:15:56 -07001313
1314 def testPackFsp(self):
1315 """Test that an image with a FSP binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001316 data = self._DoReadFile('042_intel_fsp.dts')
Simon Glassda229092016-11-25 20:15:56 -07001317 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1318
1319 def testPackCmc(self):
Bin Meng59ea8c22017-08-15 22:41:54 -07001320 """Test that an image with a CMC binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001321 data = self._DoReadFile('043_intel_cmc.dts')
Simon Glassda229092016-11-25 20:15:56 -07001322 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Meng59ea8c22017-08-15 22:41:54 -07001323
1324 def testPackVbt(self):
1325 """Test that an image with a VBT binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001326 data = self._DoReadFile('046_intel_vbt.dts')
Bin Meng59ea8c22017-08-15 22:41:54 -07001327 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glass9fc60b42017-11-12 21:52:22 -07001328
Simon Glass56509842017-11-12 21:52:25 -07001329 def testSplBssPad(self):
1330 """Test that we can pad SPL's BSS with zeros"""
Simon Glass6b187df2017-11-12 21:52:27 -07001331 # ELF file with a '__bss_size' symbol
Simon Glass11ae93e2018-10-01 21:12:47 -06001332 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001333 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001334 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glasse6d85ff2019-05-14 15:53:47 -06001335 data)
Simon Glass56509842017-11-12 21:52:25 -07001336
Simon Glass86af5112018-10-01 21:12:42 -06001337 def testSplBssPadMissing(self):
1338 """Test that a missing symbol is detected"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001339 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glassb50e5612017-11-13 18:54:54 -07001340 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001341 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassb50e5612017-11-13 18:54:54 -07001342 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1343 str(e.exception))
1344
Simon Glass87722132017-11-12 21:52:26 -07001345 def testPackStart16Spl(self):
Simon Glass35b384c2018-09-14 04:57:10 -06001346 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001347 data = self._DoReadFile('048_x86_start16_spl.dts')
Simon Glass87722132017-11-12 21:52:26 -07001348 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1349
Simon Glass736bb0a2018-07-06 10:27:17 -06001350 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1351 """Helper function for microcode tests
Simon Glass6b187df2017-11-12 21:52:27 -07001352
1353 We expect to see the following in the image, in order:
1354 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1355 correct place
1356 u-boot.dtb with the microcode removed
1357 the microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001358
1359 Args:
1360 dts: Device tree file to use for test
1361 ucode_second: True if the microsecond entry is second instead of
1362 third
Simon Glass6b187df2017-11-12 21:52:27 -07001363 """
Simon Glass11ae93e2018-10-01 21:12:47 -06001364 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass736bb0a2018-07-06 10:27:17 -06001365 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1366 ucode_second=ucode_second)
Simon Glassc6c10e72019-05-17 22:00:46 -06001367 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1368 b'ter somewhere in here', first)
Simon Glass6b187df2017-11-12 21:52:27 -07001369
Simon Glass736bb0a2018-07-06 10:27:17 -06001370 def testPackUbootSplMicrocode(self):
1371 """Test that x86 microcode can be handled correctly in SPL"""
Simon Glass741f2d62018-10-01 12:22:30 -06001372 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass736bb0a2018-07-06 10:27:17 -06001373
1374 def testPackUbootSplMicrocodeReorder(self):
1375 """Test that order doesn't matter for microcode entries
1376
1377 This is the same as testPackUbootSplMicrocode but when we process the
1378 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1379 entry, so we reply on binman to try later.
1380 """
Simon Glass741f2d62018-10-01 12:22:30 -06001381 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass736bb0a2018-07-06 10:27:17 -06001382 ucode_second=True)
1383
Simon Glassca4f4ff2017-11-12 21:52:28 -07001384 def testPackMrc(self):
1385 """Test that an image with an MRC binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001386 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassca4f4ff2017-11-12 21:52:28 -07001387 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1388
Simon Glass47419ea2017-11-13 18:54:55 -07001389 def testSplDtb(self):
1390 """Test that an image with spl/u-boot-spl.dtb can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001391 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass47419ea2017-11-13 18:54:55 -07001392 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1393
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001394 def testSplNoDtb(self):
1395 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass0fe44dc2021-04-25 08:39:32 +12001396 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001397 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001398 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1399
Simon Glass3d433382021-03-21 18:24:30 +13001400 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
1401 use_expanded=False):
Simon Glassf5898822021-03-18 20:24:56 +13001402 """Check the image contains the expected symbol values
1403
1404 Args:
1405 dts: Device tree file to use for test
1406 base_data: Data before and after 'u-boot' section
1407 u_boot_offset: Offset of 'u-boot' section in image
Simon Glass3d433382021-03-21 18:24:30 +13001408 entry_args: Dict of entry args to supply to binman
1409 key: arg name
1410 value: value of that arg
1411 use_expanded: True to use expanded entries where available, e.g.
1412 'u-boot-expanded' instead of 'u-boot'
Simon Glassf5898822021-03-18 20:24:56 +13001413 """
Simon Glass1542c8b2019-08-24 07:22:56 -06001414 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass19790632017-11-13 18:55:01 -07001415 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1416 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03001417 self.assertEqual(syms['_binman_sym_magic'].address, addr)
Simon Glassf5898822021-03-18 20:24:56 +13001418 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03001419 addr + 4)
Simon Glass19790632017-11-13 18:55:01 -07001420
Simon Glass11ae93e2018-10-01 21:12:47 -06001421 self._SetupSplElf('u_boot_binman_syms')
Simon Glass3d433382021-03-21 18:24:30 +13001422 data = self._DoReadFileDtb(dts, entry_args=entry_args,
1423 use_expanded=use_expanded)[0]
Simon Glassf5898822021-03-18 20:24:56 +13001424 # The image should contain the symbols from u_boot_binman_syms.c
1425 # Note that image_pos is adjusted by the base address of the image,
1426 # which is 0x10 in our test image
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03001427 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE,
1428 0x00, u_boot_offset + len(U_BOOT_DATA),
Simon Glassf5898822021-03-18 20:24:56 +13001429 0x10 + u_boot_offset, 0x04)
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03001430 expected = (sym_values + base_data[24:] +
Simon Glassc1aa66e2022-01-29 14:14:04 -07001431 tools.get_bytes(0xff, 1) + U_BOOT_DATA + sym_values +
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03001432 base_data[24:])
Simon Glass19790632017-11-13 18:55:01 -07001433 self.assertEqual(expected, data)
1434
Simon Glassf5898822021-03-18 20:24:56 +13001435 def testSymbols(self):
1436 """Test binman can assign symbols embedded in U-Boot"""
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03001437 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glassf5898822021-03-18 20:24:56 +13001438
1439 def testSymbolsNoDtb(self):
1440 """Test binman can assign symbols embedded in U-Boot SPL"""
Simon Glasse9e0db82021-03-21 18:24:29 +13001441 self.checkSymbols('196_symbols_nodtb.dts',
Simon Glassf5898822021-03-18 20:24:56 +13001442 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1443 0x38)
1444
Simon Glassdd57c132018-06-01 09:38:11 -06001445 def testPackUnitAddress(self):
1446 """Test that we support multiple binaries with the same name"""
Simon Glass741f2d62018-10-01 12:22:30 -06001447 data = self._DoReadFile('054_unit_address.dts')
Simon Glassdd57c132018-06-01 09:38:11 -06001448 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1449
Simon Glass18546952018-06-01 09:38:16 -06001450 def testSections(self):
1451 """Basic test of sections"""
Simon Glass741f2d62018-10-01 12:22:30 -06001452 data = self._DoReadFile('055_sections.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001453 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1454 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
1455 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glass18546952018-06-01 09:38:16 -06001456 self.assertEqual(expected, data)
Simon Glass9fc60b42017-11-12 21:52:22 -07001457
Simon Glass3b0c3822018-06-01 09:38:20 -06001458 def testMap(self):
1459 """Tests outputting a map of the images"""
Simon Glass741f2d62018-10-01 12:22:30 -06001460 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001461 self.assertEqual('''ImagePos Offset Size Name
146200000000 00000000 00000028 main-section
146300000000 00000000 00000010 section@0
146400000000 00000000 00000004 u-boot
146500000010 00000010 00000010 section@1
146600000010 00000000 00000004 u-boot
146700000020 00000020 00000004 section@2
146800000020 00000000 00000004 u-boot
Simon Glass3b0c3822018-06-01 09:38:20 -06001469''', map_data)
1470
Simon Glassc8d48ef2018-06-01 09:38:21 -06001471 def testNamePrefix(self):
1472 """Tests that name prefixes are used"""
Simon Glass741f2d62018-10-01 12:22:30 -06001473 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001474 self.assertEqual('''ImagePos Offset Size Name
147500000000 00000000 00000028 main-section
147600000000 00000000 00000010 section@0
147700000000 00000000 00000004 ro-u-boot
147800000010 00000010 00000010 section@1
147900000010 00000000 00000004 rw-u-boot
Simon Glassc8d48ef2018-06-01 09:38:21 -06001480''', map_data)
1481
Simon Glass736bb0a2018-07-06 10:27:17 -06001482 def testUnknownContents(self):
1483 """Test that obtaining the contents works as expected"""
1484 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001485 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass8beb11e2019-07-08 14:25:47 -06001486 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glass16287932020-04-17 18:09:03 -06001487 "processing of contents: remaining ["
1488 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass736bb0a2018-07-06 10:27:17 -06001489
Simon Glass5c890232018-07-06 10:27:19 -06001490 def testBadChangeSize(self):
1491 """Test that trying to change the size of an entry fails"""
Simon Glassc52c9e72019-07-08 14:25:37 -06001492 try:
1493 state.SetAllowEntryExpansion(False)
1494 with self.assertRaises(ValueError) as e:
1495 self._DoReadFile('059_change_size.dts', True)
Simon Glass79d3c582019-07-20 12:23:57 -06001496 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glassc52c9e72019-07-08 14:25:37 -06001497 str(e.exception))
1498 finally:
1499 state.SetAllowEntryExpansion(True)
Simon Glass5c890232018-07-06 10:27:19 -06001500
Simon Glass16b8d6b2018-07-06 10:27:42 -06001501 def testUpdateFdt(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001502 """Test that we can update the device tree with offset/size info"""
Simon Glass741f2d62018-10-01 12:22:30 -06001503 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glass16b8d6b2018-07-06 10:27:42 -06001504 update_dtb=True)
Simon Glasscee02e62018-07-17 13:25:52 -06001505 dtb = fdt.Fdt(out_dtb_fname)
1506 dtb.Scan()
Simon Glass12bb1a92019-07-20 12:23:51 -06001507 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001508 self.assertEqual({
Simon Glassdbf6be92018-08-01 15:22:42 -06001509 'image-pos': 0,
Simon Glass8122f392018-07-17 13:25:28 -06001510 'offset': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001511 '_testing:offset': 32,
Simon Glass79d3c582019-07-20 12:23:57 -06001512 '_testing:size': 2,
Simon Glassdbf6be92018-08-01 15:22:42 -06001513 '_testing:image-pos': 32,
Simon Glass3ab95982018-08-01 15:22:37 -06001514 'section@0/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001515 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001516 'section@0/u-boot:image-pos': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001517 'section@0:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001518 'section@0:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001519 'section@0:image-pos': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001520
Simon Glass3ab95982018-08-01 15:22:37 -06001521 'section@1/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001522 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001523 'section@1/u-boot:image-pos': 16,
Simon Glass3ab95982018-08-01 15:22:37 -06001524 'section@1:offset': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001525 'section@1:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001526 'section@1:image-pos': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001527 'size': 40
1528 }, props)
1529
1530 def testUpdateFdtBad(self):
1531 """Test that we detect when ProcessFdt never completes"""
1532 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001533 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001534 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glass16287932020-04-17 18:09:03 -06001535 '[<binman.etype._testing.Entry__testing',
1536 str(e.exception))
Simon Glass5c890232018-07-06 10:27:19 -06001537
Simon Glass53af22a2018-07-17 13:25:32 -06001538 def testEntryArgs(self):
1539 """Test passing arguments to entries from the command line"""
1540 entry_args = {
1541 'test-str-arg': 'test1',
1542 'test-int-arg': '456',
1543 }
Simon Glass741f2d62018-10-01 12:22:30 -06001544 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001545 self.assertIn('image', control.images)
1546 entry = control.images['image'].GetEntries()['_testing']
1547 self.assertEqual('test0', entry.test_str_fdt)
1548 self.assertEqual('test1', entry.test_str_arg)
1549 self.assertEqual(123, entry.test_int_fdt)
1550 self.assertEqual(456, entry.test_int_arg)
1551
1552 def testEntryArgsMissing(self):
1553 """Test missing arguments and properties"""
1554 entry_args = {
1555 'test-int-arg': '456',
1556 }
Simon Glass741f2d62018-10-01 12:22:30 -06001557 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001558 entry = control.images['image'].GetEntries()['_testing']
1559 self.assertEqual('test0', entry.test_str_fdt)
1560 self.assertEqual(None, entry.test_str_arg)
1561 self.assertEqual(None, entry.test_int_fdt)
1562 self.assertEqual(456, entry.test_int_arg)
1563
1564 def testEntryArgsRequired(self):
1565 """Test missing arguments and properties"""
1566 entry_args = {
1567 'test-int-arg': '456',
1568 }
1569 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001570 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass3decfa32020-09-01 05:13:54 -06001571 self.assertIn("Node '/binman/_testing': "
1572 'Missing required properties/entry args: test-str-arg, '
1573 'test-int-fdt, test-int-arg',
Simon Glass53af22a2018-07-17 13:25:32 -06001574 str(e.exception))
1575
1576 def testEntryArgsInvalidFormat(self):
1577 """Test that an invalid entry-argument format is detected"""
Simon Glass53cd5d92019-07-08 14:25:29 -06001578 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1579 '-ano-value']
Simon Glass53af22a2018-07-17 13:25:32 -06001580 with self.assertRaises(ValueError) as e:
1581 self._DoBinman(*args)
1582 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1583
1584 def testEntryArgsInvalidInteger(self):
1585 """Test that an invalid entry-argument integer is detected"""
1586 entry_args = {
1587 'test-int-arg': 'abc',
1588 }
1589 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001590 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001591 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1592 "'test-int-arg' (value 'abc') to integer",
1593 str(e.exception))
1594
1595 def testEntryArgsInvalidDatatype(self):
1596 """Test that an invalid entry-argument datatype is detected
1597
1598 This test could be written in entry_test.py except that it needs
1599 access to control.entry_args, which seems more than that module should
1600 be able to see.
1601 """
1602 entry_args = {
1603 'test-bad-datatype-arg': '12',
1604 }
1605 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001606 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass53af22a2018-07-17 13:25:32 -06001607 entry_args=entry_args)
1608 self.assertIn('GetArg() internal error: Unknown data type ',
1609 str(e.exception))
1610
Simon Glassbb748372018-07-17 13:25:33 -06001611 def testText(self):
1612 """Test for a text entry type"""
1613 entry_args = {
1614 'test-id': TEXT_DATA,
1615 'test-id2': TEXT_DATA2,
1616 'test-id3': TEXT_DATA3,
1617 }
Simon Glass741f2d62018-10-01 12:22:30 -06001618 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glassbb748372018-07-17 13:25:33 -06001619 entry_args=entry_args)
Simon Glassc1aa66e2022-01-29 14:14:04 -07001620 expected = (tools.to_bytes(TEXT_DATA) +
1621 tools.get_bytes(0, 8 - len(TEXT_DATA)) +
1622 tools.to_bytes(TEXT_DATA2) + tools.to_bytes(TEXT_DATA3) +
Simon Glassaa88b502019-07-08 13:18:40 -06001623 b'some text' + b'more text')
Simon Glassbb748372018-07-17 13:25:33 -06001624 self.assertEqual(expected, data)
1625
Simon Glassfd8d1f72018-07-17 13:25:36 -06001626 def testEntryDocs(self):
1627 """Test for creation of entry documentation"""
1628 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass87d43322020-08-05 13:27:46 -06001629 control.WriteEntryDocs(control.GetEntryModules())
Simon Glassfd8d1f72018-07-17 13:25:36 -06001630 self.assertTrue(len(stdout.getvalue()) > 0)
1631
1632 def testEntryDocsMissing(self):
1633 """Test handling of missing entry documentation"""
1634 with self.assertRaises(ValueError) as e:
1635 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass87d43322020-08-05 13:27:46 -06001636 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glassfd8d1f72018-07-17 13:25:36 -06001637 self.assertIn('Documentation is missing for modules: u_boot',
1638 str(e.exception))
1639
Simon Glass11e36cc2018-07-17 13:25:38 -06001640 def testFmap(self):
1641 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001642 data = self._DoReadFile('067_fmap.dts')
Simon Glass11e36cc2018-07-17 13:25:38 -06001643 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc1aa66e2022-01-29 14:14:04 -07001644 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1645 U_BOOT_DATA + tools.get_bytes(ord('a'), 12))
Simon Glass11e36cc2018-07-17 13:25:38 -06001646 self.assertEqual(expected, data[:32])
Simon Glassc6c10e72019-05-17 22:00:46 -06001647 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass11e36cc2018-07-17 13:25:38 -06001648 self.assertEqual(1, fhdr.ver_major)
1649 self.assertEqual(0, fhdr.ver_minor)
1650 self.assertEqual(0, fhdr.base)
Simon Glass17365752021-04-03 11:05:10 +13001651 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 5
Simon Glassc7722e82021-04-03 11:05:09 +13001652 self.assertEqual(16 + 16 + expect_size, fhdr.image_size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001653 self.assertEqual(b'FMAP', fhdr.name)
Simon Glass17365752021-04-03 11:05:10 +13001654 self.assertEqual(5, fhdr.nareas)
Simon Glassc7722e82021-04-03 11:05:09 +13001655 fiter = iter(fentries)
Simon Glass11e36cc2018-07-17 13:25:38 -06001656
Simon Glassc7722e82021-04-03 11:05:09 +13001657 fentry = next(fiter)
Simon Glass17365752021-04-03 11:05:10 +13001658 self.assertEqual(b'SECTION0', fentry.name)
1659 self.assertEqual(0, fentry.offset)
1660 self.assertEqual(16, fentry.size)
1661 self.assertEqual(0, fentry.flags)
1662
1663 fentry = next(fiter)
Simon Glassc7722e82021-04-03 11:05:09 +13001664 self.assertEqual(b'RO_U_BOOT', fentry.name)
1665 self.assertEqual(0, fentry.offset)
1666 self.assertEqual(4, fentry.size)
1667 self.assertEqual(0, fentry.flags)
Simon Glass11e36cc2018-07-17 13:25:38 -06001668
Simon Glassc7722e82021-04-03 11:05:09 +13001669 fentry = next(fiter)
Simon Glass17365752021-04-03 11:05:10 +13001670 self.assertEqual(b'SECTION1', fentry.name)
1671 self.assertEqual(16, fentry.offset)
1672 self.assertEqual(16, fentry.size)
1673 self.assertEqual(0, fentry.flags)
1674
1675 fentry = next(fiter)
Simon Glassc7722e82021-04-03 11:05:09 +13001676 self.assertEqual(b'RW_U_BOOT', fentry.name)
1677 self.assertEqual(16, fentry.offset)
1678 self.assertEqual(4, fentry.size)
1679 self.assertEqual(0, fentry.flags)
Simon Glass11e36cc2018-07-17 13:25:38 -06001680
Simon Glassc7722e82021-04-03 11:05:09 +13001681 fentry = next(fiter)
1682 self.assertEqual(b'FMAP', fentry.name)
1683 self.assertEqual(32, fentry.offset)
1684 self.assertEqual(expect_size, fentry.size)
1685 self.assertEqual(0, fentry.flags)
Simon Glass11e36cc2018-07-17 13:25:38 -06001686
Simon Glassec127af2018-07-17 13:25:39 -06001687 def testBlobNamedByArg(self):
1688 """Test we can add a blob with the filename coming from an entry arg"""
1689 entry_args = {
1690 'cros-ec-rw-path': 'ecrw.bin',
1691 }
Simon Glass3decfa32020-09-01 05:13:54 -06001692 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassec127af2018-07-17 13:25:39 -06001693
Simon Glass3af8e492018-07-17 13:25:40 -06001694 def testFill(self):
1695 """Test for an fill entry type"""
Simon Glass741f2d62018-10-01 12:22:30 -06001696 data = self._DoReadFile('069_fill.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001697 expected = tools.get_bytes(0xff, 8) + tools.get_bytes(0, 8)
Simon Glass3af8e492018-07-17 13:25:40 -06001698 self.assertEqual(expected, data)
1699
1700 def testFillNoSize(self):
1701 """Test for an fill entry type with no size"""
1702 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001703 self._DoReadFile('070_fill_no_size.dts')
Simon Glasscdadada2022-08-13 11:40:44 -06001704 self.assertIn("'fill' entry is missing properties: size",
Simon Glass3af8e492018-07-17 13:25:40 -06001705 str(e.exception))
1706
Simon Glass0ef87aa2018-07-17 13:25:44 -06001707 def _HandleGbbCommand(self, pipe_list):
1708 """Fake calls to the futility utility"""
1709 if pipe_list[0][0] == 'futility':
1710 fname = pipe_list[0][-1]
1711 # Append our GBB data to the file, which will happen every time the
1712 # futility command is called.
Simon Glass1d0ebf72019-05-14 15:53:42 -06001713 with open(fname, 'ab') as fd:
Simon Glass0ef87aa2018-07-17 13:25:44 -06001714 fd.write(GBB_DATA)
1715 return command.CommandResult()
1716
1717 def testGbb(self):
1718 """Test for the Chromium OS Google Binary Block"""
1719 command.test_result = self._HandleGbbCommand
1720 entry_args = {
1721 'keydir': 'devkeys',
1722 'bmpblk': 'bmpblk.bin',
1723 }
Simon Glass741f2d62018-10-01 12:22:30 -06001724 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glass0ef87aa2018-07-17 13:25:44 -06001725
1726 # Since futility
Simon Glassc1aa66e2022-01-29 14:14:04 -07001727 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
1728 tools.get_bytes(0, 0x2180 - 16))
Simon Glass0ef87aa2018-07-17 13:25:44 -06001729 self.assertEqual(expected, data)
1730
1731 def testGbbTooSmall(self):
1732 """Test for the Chromium OS Google Binary Block being large enough"""
1733 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001734 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001735 self.assertIn("Node '/binman/gbb': GBB is too small",
1736 str(e.exception))
1737
1738 def testGbbNoSize(self):
1739 """Test for the Chromium OS Google Binary Block having a size"""
1740 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001741 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001742 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1743 str(e.exception))
1744
Simon Glass4f9ee832022-01-09 20:14:09 -07001745 def testGbbMissing(self):
1746 """Test that binman still produces an image if futility is missing"""
1747 entry_args = {
1748 'keydir': 'devkeys',
1749 }
1750 with test_util.capture_sys_output() as (_, stderr):
1751 self._DoTestFile('071_gbb.dts', force_missing_bintools='futility',
1752 entry_args=entry_args)
1753 err = stderr.getvalue()
1754 self.assertRegex(err,
1755 "Image 'main-section'.*missing bintools.*: futility")
1756
Simon Glass24d0d3c2018-07-17 13:25:47 -06001757 def _HandleVblockCommand(self, pipe_list):
Simon Glass5af9ebc2021-01-06 21:35:17 -07001758 """Fake calls to the futility utility
1759
1760 The expected pipe is:
1761
1762 [('futility', 'vbutil_firmware', '--vblock',
1763 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1764 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1765 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1766 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1767
1768 This writes to the output file (here, 'vblock.vblock'). If
1769 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1770 of the input data (here, 'input.vblock').
1771 """
Simon Glass24d0d3c2018-07-17 13:25:47 -06001772 if pipe_list[0][0] == 'futility':
1773 fname = pipe_list[0][3]
Simon Glassa326b492018-09-14 04:57:11 -06001774 with open(fname, 'wb') as fd:
Simon Glass5af9ebc2021-01-06 21:35:17 -07001775 if self._hash_data:
1776 infile = pipe_list[0][11]
1777 m = hashlib.sha256()
Simon Glassc1aa66e2022-01-29 14:14:04 -07001778 data = tools.read_file(infile)
Simon Glass5af9ebc2021-01-06 21:35:17 -07001779 m.update(data)
1780 fd.write(m.digest())
1781 else:
1782 fd.write(VBLOCK_DATA)
1783
Simon Glass24d0d3c2018-07-17 13:25:47 -06001784 return command.CommandResult()
1785
1786 def testVblock(self):
1787 """Test for the Chromium OS Verified Boot Block"""
Simon Glass5af9ebc2021-01-06 21:35:17 -07001788 self._hash_data = False
Simon Glass24d0d3c2018-07-17 13:25:47 -06001789 command.test_result = self._HandleVblockCommand
1790 entry_args = {
1791 'keydir': 'devkeys',
1792 }
Simon Glass741f2d62018-10-01 12:22:30 -06001793 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass24d0d3c2018-07-17 13:25:47 -06001794 entry_args=entry_args)
1795 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1796 self.assertEqual(expected, data)
1797
1798 def testVblockNoContent(self):
1799 """Test we detect a vblock which has no content to sign"""
1800 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001801 self._DoReadFile('075_vblock_no_content.dts')
Simon Glass189f2912021-03-21 18:24:31 +13001802 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
Simon Glass24d0d3c2018-07-17 13:25:47 -06001803 'property', str(e.exception))
1804
1805 def testVblockBadPhandle(self):
1806 """Test that we detect a vblock with an invalid phandle in contents"""
1807 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001808 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001809 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1810 '1000', str(e.exception))
1811
1812 def testVblockBadEntry(self):
1813 """Test that we detect an entry that points to a non-entry"""
1814 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001815 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001816 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1817 "'other'", str(e.exception))
1818
Simon Glass5af9ebc2021-01-06 21:35:17 -07001819 def testVblockContent(self):
1820 """Test that the vblock signs the right data"""
1821 self._hash_data = True
1822 command.test_result = self._HandleVblockCommand
1823 entry_args = {
1824 'keydir': 'devkeys',
1825 }
1826 data = self._DoReadFileDtb(
1827 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1828 entry_args=entry_args)[0]
1829 hashlen = 32 # SHA256 hash is 32 bytes
1830 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1831 hashval = data[-hashlen:]
1832 dtb = data[len(U_BOOT_DATA):-hashlen]
1833
1834 expected_data = U_BOOT_DATA + dtb
1835
1836 # The hashval should be a hash of the dtb
1837 m = hashlib.sha256()
1838 m.update(expected_data)
1839 expected_hashval = m.digest()
1840 self.assertEqual(expected_hashval, hashval)
1841
Simon Glass4f9ee832022-01-09 20:14:09 -07001842 def testVblockMissing(self):
1843 """Test that binman still produces an image if futility is missing"""
1844 entry_args = {
1845 'keydir': 'devkeys',
1846 }
1847 with test_util.capture_sys_output() as (_, stderr):
1848 self._DoTestFile('074_vblock.dts',
1849 force_missing_bintools='futility',
1850 entry_args=entry_args)
1851 err = stderr.getvalue()
1852 self.assertRegex(err,
1853 "Image 'main-section'.*missing bintools.*: futility")
1854
Simon Glassb8ef5b62018-07-17 13:25:48 -06001855 def testTpl(self):
Simon Glass2090f1e2019-08-24 07:23:00 -06001856 """Test that an image with TPL and its device tree can be created"""
Simon Glassb8ef5b62018-07-17 13:25:48 -06001857 # ELF file with a '__bss_size' symbol
Simon Glass2090f1e2019-08-24 07:23:00 -06001858 self._SetupTplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001859 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glassb8ef5b62018-07-17 13:25:48 -06001860 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1861
Simon Glass15a587c2018-07-17 13:25:51 -06001862 def testUsesPos(self):
1863 """Test that the 'pos' property cannot be used anymore"""
1864 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001865 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass15a587c2018-07-17 13:25:51 -06001866 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1867 "'pos'", str(e.exception))
1868
Simon Glassd178eab2018-09-14 04:57:08 -06001869 def testFillZero(self):
1870 """Test for an fill entry type with a size of 0"""
Simon Glass741f2d62018-10-01 12:22:30 -06001871 data = self._DoReadFile('080_fill_empty.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001872 self.assertEqual(tools.get_bytes(0, 16), data)
Simon Glassd178eab2018-09-14 04:57:08 -06001873
Simon Glass0b489362018-09-14 04:57:09 -06001874 def testTextMissing(self):
1875 """Test for a text entry type where there is no text"""
1876 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001877 self._DoReadFileDtb('066_text.dts',)
Simon Glass0b489362018-09-14 04:57:09 -06001878 self.assertIn("Node '/binman/text': No value provided for text label "
1879 "'test-id'", str(e.exception))
1880
Simon Glass35b384c2018-09-14 04:57:10 -06001881 def testPackStart16Tpl(self):
1882 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001883 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glass35b384c2018-09-14 04:57:10 -06001884 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1885
Simon Glass0bfa7b02018-09-14 04:57:12 -06001886 def testSelectImage(self):
1887 """Test that we can select which images to build"""
Simon Glasseb833d82019-04-25 21:58:34 -06001888 expected = 'Skipping images: image1'
Simon Glass0bfa7b02018-09-14 04:57:12 -06001889
Simon Glasseb833d82019-04-25 21:58:34 -06001890 # We should only get the expected message in verbose mode
Simon Glassee0c9a72019-07-08 13:18:48 -06001891 for verbosity in (0, 2):
Simon Glasseb833d82019-04-25 21:58:34 -06001892 with test_util.capture_sys_output() as (stdout, stderr):
1893 retcode = self._DoTestFile('006_dual_image.dts',
1894 verbosity=verbosity,
1895 images=['image2'])
1896 self.assertEqual(0, retcode)
1897 if verbosity:
1898 self.assertIn(expected, stdout.getvalue())
1899 else:
1900 self.assertNotIn(expected, stdout.getvalue())
1901
Simon Glassc1aa66e2022-01-29 14:14:04 -07001902 self.assertFalse(os.path.exists(tools.get_output_filename('image1.bin')))
1903 self.assertTrue(os.path.exists(tools.get_output_filename('image2.bin')))
Simon Glassf86a7362019-07-20 12:24:10 -06001904 self._CleanupOutputDir()
Simon Glass0bfa7b02018-09-14 04:57:12 -06001905
Simon Glass6ed45ba2018-09-14 04:57:24 -06001906 def testUpdateFdtAll(self):
1907 """Test that all device trees are updated with offset/size info"""
Simon Glass3c081312019-07-08 14:25:26 -06001908 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glass6ed45ba2018-09-14 04:57:24 -06001909
1910 base_expected = {
1911 'section:image-pos': 0,
1912 'u-boot-tpl-dtb:size': 513,
1913 'u-boot-spl-dtb:size': 513,
1914 'u-boot-spl-dtb:offset': 493,
1915 'image-pos': 0,
1916 'section/u-boot-dtb:image-pos': 0,
1917 'u-boot-spl-dtb:image-pos': 493,
1918 'section/u-boot-dtb:size': 493,
1919 'u-boot-tpl-dtb:image-pos': 1006,
1920 'section/u-boot-dtb:offset': 0,
1921 'section:size': 493,
1922 'offset': 0,
1923 'section:offset': 0,
1924 'u-boot-tpl-dtb:offset': 1006,
1925 'size': 1519
1926 }
1927
1928 # We expect three device-tree files in the output, one after the other.
1929 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1930 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1931 # main U-Boot tree. All three should have the same postions and offset.
1932 start = 0
1933 for item in ['', 'spl', 'tpl']:
1934 dtb = fdt.Fdt.FromData(data[start:])
1935 dtb.Scan()
Simon Glass12bb1a92019-07-20 12:23:51 -06001936 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
1937 ['spl', 'tpl'])
Simon Glass6ed45ba2018-09-14 04:57:24 -06001938 expected = dict(base_expected)
1939 if item:
1940 expected[item] = 0
1941 self.assertEqual(expected, props)
1942 start += dtb._fdt_obj.totalsize()
1943
1944 def testUpdateFdtOutput(self):
1945 """Test that output DTB files are updated"""
1946 try:
Simon Glass741f2d62018-10-01 12:22:30 -06001947 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glass6ed45ba2018-09-14 04:57:24 -06001948 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1949
1950 # Unfortunately, compiling a source file always results in a file
1951 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass741f2d62018-10-01 12:22:30 -06001952 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glass6ed45ba2018-09-14 04:57:24 -06001953 # binman as a file called u-boot.dtb. To fix this, copy the file
1954 # over to the expected place.
Simon Glass6ed45ba2018-09-14 04:57:24 -06001955 start = 0
1956 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1957 'tpl/u-boot-tpl.dtb.out']:
1958 dtb = fdt.Fdt.FromData(data[start:])
1959 size = dtb._fdt_obj.totalsize()
Simon Glassc1aa66e2022-01-29 14:14:04 -07001960 pathname = tools.get_output_filename(os.path.split(fname)[1])
1961 outdata = tools.read_file(pathname)
Simon Glass6ed45ba2018-09-14 04:57:24 -06001962 name = os.path.split(fname)[0]
1963
1964 if name:
1965 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1966 else:
1967 orig_indata = dtb_data
1968 self.assertNotEqual(outdata, orig_indata,
1969 "Expected output file '%s' be updated" % pathname)
1970 self.assertEqual(outdata, data[start:start + size],
1971 "Expected output file '%s' to match output image" %
1972 pathname)
1973 start += size
1974 finally:
1975 self._ResetDtbs()
1976
Simon Glass83d73c22018-09-14 04:57:26 -06001977 def _decompress(self, data):
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +02001978 bintool = self.comp_bintools['lz4']
1979 return bintool.decompress(data)
Simon Glass83d73c22018-09-14 04:57:26 -06001980
1981 def testCompress(self):
1982 """Test compression of blobs"""
Simon Glassac62fba2019-07-08 13:18:53 -06001983 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06001984 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass83d73c22018-09-14 04:57:26 -06001985 use_real_dtb=True, update_dtb=True)
1986 dtb = fdt.Fdt(out_dtb_fname)
1987 dtb.Scan()
1988 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1989 orig = self._decompress(data)
1990 self.assertEquals(COMPRESS_DATA, orig)
Simon Glass97c3e9a2020-10-26 17:40:15 -06001991
1992 # Do a sanity check on various fields
1993 image = control.images['image']
1994 entries = image.GetEntries()
1995 self.assertEqual(1, len(entries))
1996
1997 entry = entries['blob']
1998 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
1999 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
2000 orig = self._decompress(entry.data)
2001 self.assertEqual(orig, entry.uncomp_data)
2002
Simon Glass63e7ba62020-10-26 17:40:16 -06002003 self.assertEqual(image.data, entry.data)
2004
Simon Glass83d73c22018-09-14 04:57:26 -06002005 expected = {
2006 'blob:uncomp-size': len(COMPRESS_DATA),
2007 'blob:size': len(data),
2008 'size': len(data),
2009 }
2010 self.assertEqual(expected, props)
2011
Simon Glass0a98b282018-09-14 04:57:28 -06002012 def testFiles(self):
2013 """Test bringing in multiple files"""
Simon Glass741f2d62018-10-01 12:22:30 -06002014 data = self._DoReadFile('084_files.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06002015 self.assertEqual(FILES_DATA, data)
2016
2017 def testFilesCompress(self):
2018 """Test bringing in multiple files and compressing them"""
Simon Glassac62fba2019-07-08 13:18:53 -06002019 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06002020 data = self._DoReadFile('085_files_compress.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06002021
2022 image = control.images['image']
2023 entries = image.GetEntries()
2024 files = entries['files']
Simon Glass8beb11e2019-07-08 14:25:47 -06002025 entries = files._entries
Simon Glass0a98b282018-09-14 04:57:28 -06002026
Simon Glassc6c10e72019-05-17 22:00:46 -06002027 orig = b''
Simon Glass0a98b282018-09-14 04:57:28 -06002028 for i in range(1, 3):
2029 key = '%d.dat' % i
2030 start = entries[key].image_pos
2031 len = entries[key].size
2032 chunk = data[start:start + len]
2033 orig += self._decompress(chunk)
2034
2035 self.assertEqual(FILES_DATA, orig)
2036
2037 def testFilesMissing(self):
2038 """Test missing files"""
2039 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002040 data = self._DoReadFile('086_files_none.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06002041 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
2042 'no files', str(e.exception))
2043
2044 def testFilesNoPattern(self):
2045 """Test missing files"""
2046 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002047 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06002048 self.assertIn("Node '/binman/files': Missing 'pattern' property",
2049 str(e.exception))
2050
Simon Glass80a66ae2022-03-05 20:18:59 -07002051 def testExtendSize(self):
2052 """Test an extending entry"""
2053 data, _, map_data, _ = self._DoReadFileDtb('088_extend_size.dts',
Simon Glassba64a0b2018-09-14 04:57:29 -06002054 map=True)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002055 expect = (tools.get_bytes(ord('a'), 8) + U_BOOT_DATA +
2056 MRC_DATA + tools.get_bytes(ord('b'), 1) + U_BOOT_DATA +
2057 tools.get_bytes(ord('c'), 8) + U_BOOT_DATA +
2058 tools.get_bytes(ord('d'), 8))
Simon Glassba64a0b2018-09-14 04:57:29 -06002059 self.assertEqual(expect, data)
2060 self.assertEqual('''ImagePos Offset Size Name
206100000000 00000000 00000028 main-section
206200000000 00000000 00000008 fill
206300000008 00000008 00000004 u-boot
20640000000c 0000000c 00000004 section
20650000000c 00000000 00000003 intel-mrc
206600000010 00000010 00000004 u-boot2
206700000014 00000014 0000000c section2
206800000014 00000000 00000008 fill
20690000001c 00000008 00000004 u-boot
207000000020 00000020 00000008 fill2
2071''', map_data)
2072
Simon Glass80a66ae2022-03-05 20:18:59 -07002073 def testExtendSizeBad(self):
2074 """Test an extending entry which fails to provide contents"""
Simon Glass163ed6c2018-09-14 04:57:36 -06002075 with test_util.capture_sys_output() as (stdout, stderr):
2076 with self.assertRaises(ValueError) as e:
Simon Glass80a66ae2022-03-05 20:18:59 -07002077 self._DoReadFileDtb('089_extend_size_bad.dts', map=True)
Simon Glassba64a0b2018-09-14 04:57:29 -06002078 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
2079 'expanding entry', str(e.exception))
2080
Simon Glasse0e5df92018-09-14 04:57:31 -06002081 def testHash(self):
2082 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06002083 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06002084 use_real_dtb=True, update_dtb=True)
2085 dtb = fdt.Fdt(out_dtb_fname)
2086 dtb.Scan()
2087 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
2088 m = hashlib.sha256()
2089 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06002090 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06002091
2092 def testHashNoAlgo(self):
2093 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002094 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06002095 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2096 'hash node', str(e.exception))
2097
2098 def testHashBadAlgo(self):
2099 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002100 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glass8db1f992022-02-08 10:59:44 -07002101 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm 'invalid'",
Simon Glasse0e5df92018-09-14 04:57:31 -06002102 str(e.exception))
2103
2104 def testHashSection(self):
2105 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06002106 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06002107 use_real_dtb=True, update_dtb=True)
2108 dtb = fdt.Fdt(out_dtb_fname)
2109 dtb.Scan()
2110 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2111 m = hashlib.sha256()
2112 m.update(U_BOOT_DATA)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002113 m.update(tools.get_bytes(ord('a'), 16))
Simon Glassc6c10e72019-05-17 22:00:46 -06002114 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06002115
Simon Glassf0253632018-09-14 04:57:32 -06002116 def testPackUBootTplMicrocode(self):
2117 """Test that x86 microcode can be handled correctly in TPL
2118
2119 We expect to see the following in the image, in order:
2120 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2121 place
2122 u-boot-tpl.dtb with the microcode removed
2123 the microcode
2124 """
Simon Glass2090f1e2019-08-24 07:23:00 -06002125 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass741f2d62018-10-01 12:22:30 -06002126 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glassf0253632018-09-14 04:57:32 -06002127 U_BOOT_TPL_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06002128 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2129 b'ter somewhere in here', first)
Simon Glassf0253632018-09-14 04:57:32 -06002130
Simon Glassf8f8df62018-09-14 04:57:34 -06002131 def testFmapX86(self):
2132 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06002133 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassf8f8df62018-09-14 04:57:34 -06002134 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc1aa66e2022-01-29 14:14:04 -07002135 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('a'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06002136 self.assertEqual(expected, data[:32])
2137 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2138
2139 self.assertEqual(0x100, fhdr.image_size)
2140
2141 self.assertEqual(0, fentries[0].offset)
2142 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06002143 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06002144
2145 self.assertEqual(4, fentries[1].offset)
2146 self.assertEqual(3, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06002147 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06002148
2149 self.assertEqual(32, fentries[2].offset)
2150 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2151 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06002152 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06002153
2154 def testFmapX86Section(self):
2155 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06002156 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002157 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('b'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06002158 self.assertEqual(expected, data[:32])
2159 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2160
Simon Glass17365752021-04-03 11:05:10 +13002161 self.assertEqual(0x180, fhdr.image_size)
2162 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
Simon Glassc7722e82021-04-03 11:05:09 +13002163 fiter = iter(fentries)
Simon Glassf8f8df62018-09-14 04:57:34 -06002164
Simon Glassc7722e82021-04-03 11:05:09 +13002165 fentry = next(fiter)
2166 self.assertEqual(b'U_BOOT', fentry.name)
2167 self.assertEqual(0, fentry.offset)
2168 self.assertEqual(4, fentry.size)
Simon Glassf8f8df62018-09-14 04:57:34 -06002169
Simon Glassc7722e82021-04-03 11:05:09 +13002170 fentry = next(fiter)
Simon Glass17365752021-04-03 11:05:10 +13002171 self.assertEqual(b'SECTION', fentry.name)
2172 self.assertEqual(4, fentry.offset)
2173 self.assertEqual(0x20 + expect_size, fentry.size)
2174
2175 fentry = next(fiter)
Simon Glassc7722e82021-04-03 11:05:09 +13002176 self.assertEqual(b'INTEL_MRC', fentry.name)
2177 self.assertEqual(4, fentry.offset)
2178 self.assertEqual(3, fentry.size)
Simon Glassf8f8df62018-09-14 04:57:34 -06002179
Simon Glassc7722e82021-04-03 11:05:09 +13002180 fentry = next(fiter)
2181 self.assertEqual(b'FMAP', fentry.name)
2182 self.assertEqual(36, fentry.offset)
2183 self.assertEqual(expect_size, fentry.size)
Simon Glassf8f8df62018-09-14 04:57:34 -06002184
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002185 def testElf(self):
2186 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06002187 self._SetupSplElf()
Simon Glass2090f1e2019-08-24 07:23:00 -06002188 self._SetupTplElf()
Simon Glass53e22bf2019-08-24 07:22:53 -06002189 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002190 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06002191 data = self._DoReadFile('096_elf.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002192
Simon Glass093d1682019-07-08 13:18:25 -06002193 def testElfStrip(self):
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002194 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06002195 self._SetupSplElf()
Simon Glass53e22bf2019-08-24 07:22:53 -06002196 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002197 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06002198 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002199
Simon Glass163ed6c2018-09-14 04:57:36 -06002200 def testPackOverlapMap(self):
2201 """Test that overlapping regions are detected"""
2202 with test_util.capture_sys_output() as (stdout, stderr):
2203 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002204 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002205 map_fname = tools.get_output_filename('image.map')
Simon Glass163ed6c2018-09-14 04:57:36 -06002206 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2207 stdout.getvalue())
2208
2209 # We should not get an inmage, but there should be a map file
Simon Glassc1aa66e2022-01-29 14:14:04 -07002210 self.assertFalse(os.path.exists(tools.get_output_filename('image.bin')))
Simon Glass163ed6c2018-09-14 04:57:36 -06002211 self.assertTrue(os.path.exists(map_fname))
Simon Glassc1aa66e2022-01-29 14:14:04 -07002212 map_data = tools.read_file(map_fname, binary=False)
Simon Glass163ed6c2018-09-14 04:57:36 -06002213 self.assertEqual('''ImagePos Offset Size Name
Simon Glass0ff83da2020-10-26 17:40:24 -06002214<none> 00000000 00000008 main-section
Simon Glass163ed6c2018-09-14 04:57:36 -06002215<none> 00000000 00000004 u-boot
2216<none> 00000003 00000004 u-boot-align
2217''', map_data)
2218
Simon Glass093d1682019-07-08 13:18:25 -06002219 def testPackRefCode(self):
Simon Glass3ae192c2018-10-01 12:22:31 -06002220 """Test that an image with an Intel Reference code binary works"""
2221 data = self._DoReadFile('100_intel_refcode.dts')
2222 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2223
Simon Glass9481c802019-04-25 21:58:39 -06002224 def testSectionOffset(self):
2225 """Tests use of a section with an offset"""
2226 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2227 map=True)
2228 self.assertEqual('''ImagePos Offset Size Name
222900000000 00000000 00000038 main-section
223000000004 00000004 00000010 section@0
223100000004 00000000 00000004 u-boot
223200000018 00000018 00000010 section@1
223300000018 00000000 00000004 u-boot
22340000002c 0000002c 00000004 section@2
22350000002c 00000000 00000004 u-boot
2236''', map_data)
2237 self.assertEqual(data,
Simon Glassc1aa66e2022-01-29 14:14:04 -07002238 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2239 tools.get_bytes(0x21, 12) +
2240 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2241 tools.get_bytes(0x61, 12) +
2242 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2243 tools.get_bytes(0x26, 8))
Simon Glass9481c802019-04-25 21:58:39 -06002244
Simon Glassac62fba2019-07-08 13:18:53 -06002245 def testCbfsRaw(self):
2246 """Test base handling of a Coreboot Filesystem (CBFS)
2247
2248 The exact contents of the CBFS is verified by similar tests in
2249 cbfs_util_test.py. The tests here merely check that the files added to
2250 the CBFS can be found in the final image.
2251 """
2252 data = self._DoReadFile('102_cbfs_raw.dts')
2253 size = 0xb0
2254
2255 cbfs = cbfs_util.CbfsReader(data)
2256 self.assertEqual(size, cbfs.rom_size)
2257
2258 self.assertIn('u-boot-dtb', cbfs.files)
2259 cfile = cbfs.files['u-boot-dtb']
2260 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2261
2262 def testCbfsArch(self):
2263 """Test on non-x86 architecture"""
2264 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2265 size = 0x100
2266
2267 cbfs = cbfs_util.CbfsReader(data)
2268 self.assertEqual(size, cbfs.rom_size)
2269
2270 self.assertIn('u-boot-dtb', cbfs.files)
2271 cfile = cbfs.files['u-boot-dtb']
2272 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2273
2274 def testCbfsStage(self):
2275 """Tests handling of a Coreboot Filesystem (CBFS)"""
2276 if not elf.ELF_TOOLS:
2277 self.skipTest('Python elftools not available')
2278 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2279 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2280 size = 0xb0
2281
2282 data = self._DoReadFile('104_cbfs_stage.dts')
2283 cbfs = cbfs_util.CbfsReader(data)
2284 self.assertEqual(size, cbfs.rom_size)
2285
2286 self.assertIn('u-boot', cbfs.files)
2287 cfile = cbfs.files['u-boot']
2288 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2289
2290 def testCbfsRawCompress(self):
2291 """Test handling of compressing raw files"""
2292 self._CheckLz4()
2293 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2294 size = 0x140
2295
2296 cbfs = cbfs_util.CbfsReader(data)
2297 self.assertIn('u-boot', cbfs.files)
2298 cfile = cbfs.files['u-boot']
2299 self.assertEqual(COMPRESS_DATA, cfile.data)
2300
2301 def testCbfsBadArch(self):
2302 """Test handling of a bad architecture"""
2303 with self.assertRaises(ValueError) as e:
2304 self._DoReadFile('106_cbfs_bad_arch.dts')
2305 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2306
2307 def testCbfsNoSize(self):
2308 """Test handling of a missing size property"""
2309 with self.assertRaises(ValueError) as e:
2310 self._DoReadFile('107_cbfs_no_size.dts')
2311 self.assertIn('entry must have a size property', str(e.exception))
2312
Simon Glasse2f04742021-11-23 11:03:54 -07002313 def testCbfsNoContents(self):
Simon Glassac62fba2019-07-08 13:18:53 -06002314 """Test handling of a CBFS entry which does not provide contentsy"""
2315 with self.assertRaises(ValueError) as e:
2316 self._DoReadFile('108_cbfs_no_contents.dts')
2317 self.assertIn('Could not complete processing of contents',
2318 str(e.exception))
2319
2320 def testCbfsBadCompress(self):
2321 """Test handling of a bad architecture"""
2322 with self.assertRaises(ValueError) as e:
2323 self._DoReadFile('109_cbfs_bad_compress.dts')
2324 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2325 str(e.exception))
2326
2327 def testCbfsNamedEntries(self):
2328 """Test handling of named entries"""
2329 data = self._DoReadFile('110_cbfs_name.dts')
2330
2331 cbfs = cbfs_util.CbfsReader(data)
2332 self.assertIn('FRED', cbfs.files)
2333 cfile1 = cbfs.files['FRED']
2334 self.assertEqual(U_BOOT_DATA, cfile1.data)
2335
2336 self.assertIn('hello', cbfs.files)
2337 cfile2 = cbfs.files['hello']
2338 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2339
Simon Glassc5ac1382019-07-08 13:18:54 -06002340 def _SetupIfwi(self, fname):
2341 """Set up to run an IFWI test
2342
2343 Args:
2344 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2345 """
2346 self._SetupSplElf()
Simon Glass2090f1e2019-08-24 07:23:00 -06002347 self._SetupTplElf()
Simon Glassc5ac1382019-07-08 13:18:54 -06002348
2349 # Intel Integrated Firmware Image (IFWI) file
2350 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2351 data = fd.read()
2352 TestFunctional._MakeInputFile(fname,data)
2353
2354 def _CheckIfwi(self, data):
2355 """Check that an image with an IFWI contains the correct output
2356
2357 Args:
2358 data: Conents of output file
2359 """
Simon Glassc1aa66e2022-01-29 14:14:04 -07002360 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glassc5ac1382019-07-08 13:18:54 -06002361 if data[:0x1000] != expected_desc:
2362 self.fail('Expected descriptor binary at start of image')
2363
2364 # We expect to find the TPL wil in subpart IBBP entry IBBL
Simon Glassc1aa66e2022-01-29 14:14:04 -07002365 image_fname = tools.get_output_filename('image.bin')
2366 tpl_fname = tools.get_output_filename('tpl.out')
Simon Glass532ae702022-01-09 20:14:01 -07002367 ifwitool = bintool.Bintool.create('ifwitool')
2368 ifwitool.extract(image_fname, 'IBBP', 'IBBL', tpl_fname)
Simon Glassc5ac1382019-07-08 13:18:54 -06002369
Simon Glassc1aa66e2022-01-29 14:14:04 -07002370 tpl_data = tools.read_file(tpl_fname)
Simon Glasse95be632019-08-24 07:22:51 -06002371 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glassc5ac1382019-07-08 13:18:54 -06002372
2373 def testPackX86RomIfwi(self):
2374 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2375 self._SetupIfwi('fitimage.bin')
Simon Glass9255f3c2019-08-24 07:23:01 -06002376 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002377 self._CheckIfwi(data)
2378
2379 def testPackX86RomIfwiNoDesc(self):
2380 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2381 self._SetupIfwi('ifwi.bin')
Simon Glass9255f3c2019-08-24 07:23:01 -06002382 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002383 self._CheckIfwi(data)
2384
2385 def testPackX86RomIfwiNoData(self):
2386 """Test that an x86 ROM with IFWI handles missing data"""
2387 self._SetupIfwi('ifwi.bin')
2388 with self.assertRaises(ValueError) as e:
Simon Glass9255f3c2019-08-24 07:23:01 -06002389 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002390 self.assertIn('Could not complete processing of contents',
2391 str(e.exception))
Simon Glass53af22a2018-07-17 13:25:32 -06002392
Simon Glass4f9ee832022-01-09 20:14:09 -07002393 def testIfwiMissing(self):
2394 """Test that binman still produces an image if ifwitool is missing"""
2395 self._SetupIfwi('fitimage.bin')
2396 with test_util.capture_sys_output() as (_, stderr):
2397 self._DoTestFile('111_x86_rom_ifwi.dts',
2398 force_missing_bintools='ifwitool')
2399 err = stderr.getvalue()
2400 self.assertRegex(err,
2401 "Image 'main-section'.*missing bintools.*: ifwitool")
2402
Simon Glasse073d4e2019-07-08 13:18:56 -06002403 def testCbfsOffset(self):
2404 """Test a CBFS with files at particular offsets
2405
2406 Like all CFBS tests, this is just checking the logic that calls
2407 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2408 """
2409 data = self._DoReadFile('114_cbfs_offset.dts')
2410 size = 0x200
2411
2412 cbfs = cbfs_util.CbfsReader(data)
2413 self.assertEqual(size, cbfs.rom_size)
2414
2415 self.assertIn('u-boot', cbfs.files)
2416 cfile = cbfs.files['u-boot']
2417 self.assertEqual(U_BOOT_DATA, cfile.data)
2418 self.assertEqual(0x40, cfile.cbfs_offset)
2419
2420 self.assertIn('u-boot-dtb', cbfs.files)
2421 cfile2 = cbfs.files['u-boot-dtb']
2422 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2423 self.assertEqual(0x140, cfile2.cbfs_offset)
2424
Simon Glass086cec92019-07-08 14:25:27 -06002425 def testFdtmap(self):
2426 """Test an FDT map can be inserted in the image"""
2427 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2428 fdtmap_data = data[len(U_BOOT_DATA):]
2429 magic = fdtmap_data[:8]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002430 self.assertEqual(b'_FDTMAP_', magic)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002431 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass086cec92019-07-08 14:25:27 -06002432
2433 fdt_data = fdtmap_data[16:]
2434 dtb = fdt.Fdt.FromData(fdt_data)
2435 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002436 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass086cec92019-07-08 14:25:27 -06002437 self.assertEqual({
2438 'image-pos': 0,
2439 'offset': 0,
2440 'u-boot:offset': 0,
2441 'u-boot:size': len(U_BOOT_DATA),
2442 'u-boot:image-pos': 0,
2443 'fdtmap:image-pos': 4,
2444 'fdtmap:offset': 4,
2445 'fdtmap:size': len(fdtmap_data),
2446 'size': len(data),
2447 }, props)
2448
2449 def testFdtmapNoMatch(self):
2450 """Check handling of an FDT map when the section cannot be found"""
2451 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2452
2453 # Mangle the section name, which should cause a mismatch between the
2454 # correct FDT path and the one expected by the section
2455 image = control.images['image']
Simon Glasscf228942019-07-08 14:25:28 -06002456 image._node.path += '-suffix'
Simon Glass086cec92019-07-08 14:25:27 -06002457 entries = image.GetEntries()
2458 fdtmap = entries['fdtmap']
2459 with self.assertRaises(ValueError) as e:
2460 fdtmap._GetFdtmap()
2461 self.assertIn("Cannot locate node for path '/binman-suffix'",
2462 str(e.exception))
2463
Simon Glasscf228942019-07-08 14:25:28 -06002464 def testFdtmapHeader(self):
2465 """Test an FDT map and image header can be inserted in the image"""
2466 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2467 fdtmap_pos = len(U_BOOT_DATA)
2468 fdtmap_data = data[fdtmap_pos:]
2469 fdt_data = fdtmap_data[16:]
2470 dtb = fdt.Fdt.FromData(fdt_data)
2471 fdt_size = dtb.GetFdtObj().totalsize()
2472 hdr_data = data[-8:]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002473 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002474 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2475 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2476
2477 def testFdtmapHeaderStart(self):
2478 """Test an image header can be inserted at the image start"""
2479 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2480 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2481 hdr_data = data[:8]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002482 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002483 offset = struct.unpack('<I', hdr_data[4:])[0]
2484 self.assertEqual(fdtmap_pos, offset)
2485
2486 def testFdtmapHeaderPos(self):
2487 """Test an image header can be inserted at a chosen position"""
2488 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2489 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2490 hdr_data = data[0x80:0x88]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002491 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002492 offset = struct.unpack('<I', hdr_data[4:])[0]
2493 self.assertEqual(fdtmap_pos, offset)
2494
2495 def testHeaderMissingFdtmap(self):
2496 """Test an image header requires an fdtmap"""
2497 with self.assertRaises(ValueError) as e:
2498 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2499 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2500 str(e.exception))
2501
2502 def testHeaderNoLocation(self):
2503 """Test an image header with a no specified location is detected"""
2504 with self.assertRaises(ValueError) as e:
2505 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2506 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2507 str(e.exception))
2508
Simon Glassc52c9e72019-07-08 14:25:37 -06002509 def testEntryExpand(self):
Simon Glass80a66ae2022-03-05 20:18:59 -07002510 """Test extending an entry after it is packed"""
2511 data = self._DoReadFile('121_entry_extend.dts')
Simon Glass79d3c582019-07-20 12:23:57 -06002512 self.assertEqual(b'aaa', data[:3])
2513 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2514 self.assertEqual(b'aaa', data[-3:])
Simon Glassc52c9e72019-07-08 14:25:37 -06002515
Simon Glass80a66ae2022-03-05 20:18:59 -07002516 def testEntryExtendBad(self):
2517 """Test extending an entry after it is packed, twice"""
Simon Glassc52c9e72019-07-08 14:25:37 -06002518 with self.assertRaises(ValueError) as e:
Simon Glass80a66ae2022-03-05 20:18:59 -07002519 self._DoReadFile('122_entry_extend_twice.dts')
Simon Glass61ec04f2019-07-20 12:23:58 -06002520 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glassc52c9e72019-07-08 14:25:37 -06002521 str(e.exception))
2522
Simon Glass80a66ae2022-03-05 20:18:59 -07002523 def testEntryExtendSection(self):
2524 """Test extending an entry within a section after it is packed"""
2525 data = self._DoReadFile('123_entry_extend_section.dts')
Simon Glass79d3c582019-07-20 12:23:57 -06002526 self.assertEqual(b'aaa', data[:3])
2527 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2528 self.assertEqual(b'aaa', data[-3:])
Simon Glassc52c9e72019-07-08 14:25:37 -06002529
Simon Glass6c223fd2019-07-08 14:25:38 -06002530 def testCompressDtb(self):
2531 """Test that compress of device-tree files is supported"""
2532 self._CheckLz4()
2533 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2534 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2535 comp_data = data[len(U_BOOT_DATA):]
2536 orig = self._decompress(comp_data)
2537 dtb = fdt.Fdt.FromData(orig)
2538 dtb.Scan()
2539 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2540 expected = {
2541 'u-boot:size': len(U_BOOT_DATA),
2542 'u-boot-dtb:uncomp-size': len(orig),
2543 'u-boot-dtb:size': len(comp_data),
2544 'size': len(data),
2545 }
2546 self.assertEqual(expected, props)
2547
Simon Glass69f7cb32019-07-08 14:25:41 -06002548 def testCbfsUpdateFdt(self):
2549 """Test that we can update the device tree with CBFS offset/size info"""
2550 self._CheckLz4()
2551 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2552 update_dtb=True)
2553 dtb = fdt.Fdt(out_dtb_fname)
2554 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002555 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass69f7cb32019-07-08 14:25:41 -06002556 del props['cbfs/u-boot:size']
2557 self.assertEqual({
2558 'offset': 0,
2559 'size': len(data),
2560 'image-pos': 0,
2561 'cbfs:offset': 0,
2562 'cbfs:size': len(data),
2563 'cbfs:image-pos': 0,
2564 'cbfs/u-boot:offset': 0x38,
2565 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2566 'cbfs/u-boot:image-pos': 0x38,
2567 'cbfs/u-boot-dtb:offset': 0xb8,
2568 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2569 'cbfs/u-boot-dtb:image-pos': 0xb8,
2570 }, props)
2571
Simon Glass8a1ad062019-07-08 14:25:42 -06002572 def testCbfsBadType(self):
2573 """Test an image header with a no specified location is detected"""
2574 with self.assertRaises(ValueError) as e:
2575 self._DoReadFile('126_cbfs_bad_type.dts')
2576 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2577
Simon Glass41b8ba02019-07-08 14:25:43 -06002578 def testList(self):
2579 """Test listing the files in an image"""
2580 self._CheckLz4()
2581 data = self._DoReadFile('127_list.dts')
2582 image = control.images['image']
2583 entries = image.BuildEntryList()
2584 self.assertEqual(7, len(entries))
2585
2586 ent = entries[0]
2587 self.assertEqual(0, ent.indent)
2588 self.assertEqual('main-section', ent.name)
2589 self.assertEqual('section', ent.etype)
2590 self.assertEqual(len(data), ent.size)
2591 self.assertEqual(0, ent.image_pos)
2592 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002593 self.assertEqual(0, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002594
2595 ent = entries[1]
2596 self.assertEqual(1, ent.indent)
2597 self.assertEqual('u-boot', ent.name)
2598 self.assertEqual('u-boot', ent.etype)
2599 self.assertEqual(len(U_BOOT_DATA), ent.size)
2600 self.assertEqual(0, ent.image_pos)
2601 self.assertEqual(None, ent.uncomp_size)
2602 self.assertEqual(0, ent.offset)
2603
2604 ent = entries[2]
2605 self.assertEqual(1, ent.indent)
2606 self.assertEqual('section', ent.name)
2607 self.assertEqual('section', ent.etype)
2608 section_size = ent.size
2609 self.assertEqual(0x100, ent.image_pos)
2610 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002611 self.assertEqual(0x100, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002612
2613 ent = entries[3]
2614 self.assertEqual(2, ent.indent)
2615 self.assertEqual('cbfs', ent.name)
2616 self.assertEqual('cbfs', ent.etype)
2617 self.assertEqual(0x400, ent.size)
2618 self.assertEqual(0x100, ent.image_pos)
2619 self.assertEqual(None, ent.uncomp_size)
2620 self.assertEqual(0, ent.offset)
2621
2622 ent = entries[4]
2623 self.assertEqual(3, ent.indent)
2624 self.assertEqual('u-boot', ent.name)
2625 self.assertEqual('u-boot', ent.etype)
2626 self.assertEqual(len(U_BOOT_DATA), ent.size)
2627 self.assertEqual(0x138, ent.image_pos)
2628 self.assertEqual(None, ent.uncomp_size)
2629 self.assertEqual(0x38, ent.offset)
2630
2631 ent = entries[5]
2632 self.assertEqual(3, ent.indent)
2633 self.assertEqual('u-boot-dtb', ent.name)
2634 self.assertEqual('text', ent.etype)
2635 self.assertGreater(len(COMPRESS_DATA), ent.size)
2636 self.assertEqual(0x178, ent.image_pos)
2637 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2638 self.assertEqual(0x78, ent.offset)
2639
2640 ent = entries[6]
2641 self.assertEqual(2, ent.indent)
2642 self.assertEqual('u-boot-dtb', ent.name)
2643 self.assertEqual('u-boot-dtb', ent.etype)
2644 self.assertEqual(0x500, ent.image_pos)
2645 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2646 dtb_size = ent.size
2647 # Compressing this data expands it since headers are added
2648 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2649 self.assertEqual(0x400, ent.offset)
2650
2651 self.assertEqual(len(data), 0x100 + section_size)
2652 self.assertEqual(section_size, 0x400 + dtb_size)
2653
Simon Glasse1925fa2019-07-08 14:25:44 -06002654 def testFindFdtmap(self):
2655 """Test locating an FDT map in an image"""
2656 self._CheckLz4()
2657 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2658 image = control.images['image']
2659 entries = image.GetEntries()
2660 entry = entries['fdtmap']
2661 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2662
2663 def testFindFdtmapMissing(self):
2664 """Test failing to locate an FDP map"""
2665 data = self._DoReadFile('005_simple.dts')
2666 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2667
Simon Glass2d260032019-07-08 14:25:45 -06002668 def testFindImageHeader(self):
2669 """Test locating a image header"""
2670 self._CheckLz4()
Simon Glassffded752019-07-08 14:25:46 -06002671 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002672 image = control.images['image']
2673 entries = image.GetEntries()
2674 entry = entries['fdtmap']
2675 # The header should point to the FDT map
2676 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2677
2678 def testFindImageHeaderStart(self):
2679 """Test locating a image header located at the start of an image"""
Simon Glassffded752019-07-08 14:25:46 -06002680 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002681 image = control.images['image']
2682 entries = image.GetEntries()
2683 entry = entries['fdtmap']
2684 # The header should point to the FDT map
2685 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2686
2687 def testFindImageHeaderMissing(self):
2688 """Test failing to locate an image header"""
2689 data = self._DoReadFile('005_simple.dts')
2690 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2691
Simon Glassffded752019-07-08 14:25:46 -06002692 def testReadImage(self):
2693 """Test reading an image and accessing its FDT map"""
2694 self._CheckLz4()
2695 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002696 image_fname = tools.get_output_filename('image.bin')
Simon Glassffded752019-07-08 14:25:46 -06002697 orig_image = control.images['image']
2698 image = Image.FromFile(image_fname)
2699 self.assertEqual(orig_image.GetEntries().keys(),
2700 image.GetEntries().keys())
2701
2702 orig_entry = orig_image.GetEntries()['fdtmap']
2703 entry = image.GetEntries()['fdtmap']
2704 self.assertEquals(orig_entry.offset, entry.offset)
2705 self.assertEquals(orig_entry.size, entry.size)
2706 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2707
2708 def testReadImageNoHeader(self):
2709 """Test accessing an image's FDT map without an image header"""
2710 self._CheckLz4()
2711 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002712 image_fname = tools.get_output_filename('image.bin')
Simon Glassffded752019-07-08 14:25:46 -06002713 image = Image.FromFile(image_fname)
2714 self.assertTrue(isinstance(image, Image))
Simon Glass10f9d002019-07-20 12:23:50 -06002715 self.assertEqual('image', image.image_name[-5:])
Simon Glassffded752019-07-08 14:25:46 -06002716
2717 def testReadImageFail(self):
2718 """Test failing to read an image image's FDT map"""
2719 self._DoReadFile('005_simple.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002720 image_fname = tools.get_output_filename('image.bin')
Simon Glassffded752019-07-08 14:25:46 -06002721 with self.assertRaises(ValueError) as e:
2722 image = Image.FromFile(image_fname)
2723 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glasse073d4e2019-07-08 13:18:56 -06002724
Simon Glass61f564d2019-07-08 14:25:48 -06002725 def testListCmd(self):
2726 """Test listing the files in an image using an Fdtmap"""
2727 self._CheckLz4()
2728 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2729
2730 # lz4 compression size differs depending on the version
2731 image = control.images['image']
2732 entries = image.GetEntries()
2733 section_size = entries['section'].size
2734 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2735 fdtmap_offset = entries['fdtmap'].offset
2736
Simon Glassf86a7362019-07-20 12:24:10 -06002737 try:
2738 tmpdir, updated_fname = self._SetupImageInTmpdir()
2739 with test_util.capture_sys_output() as (stdout, stderr):
2740 self._DoBinman('ls', '-i', updated_fname)
2741 finally:
2742 shutil.rmtree(tmpdir)
Simon Glass61f564d2019-07-08 14:25:48 -06002743 lines = stdout.getvalue().splitlines()
2744 expected = [
2745'Name Image-pos Size Entry-type Offset Uncomp-size',
2746'----------------------------------------------------------------------',
2747'main-section 0 c00 section 0',
2748' u-boot 0 4 u-boot 0',
2749' section 100 %x section 100' % section_size,
2750' cbfs 100 400 cbfs 0',
2751' u-boot 138 4 u-boot 38',
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002752' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glass61f564d2019-07-08 14:25:48 -06002753' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002754' fdtmap %x 3bd fdtmap %x' %
Simon Glass61f564d2019-07-08 14:25:48 -06002755 (fdtmap_offset, fdtmap_offset),
2756' image-header bf8 8 image-header bf8',
2757 ]
2758 self.assertEqual(expected, lines)
2759
2760 def testListCmdFail(self):
2761 """Test failing to list an image"""
2762 self._DoReadFile('005_simple.dts')
Simon Glassf86a7362019-07-20 12:24:10 -06002763 try:
2764 tmpdir, updated_fname = self._SetupImageInTmpdir()
2765 with self.assertRaises(ValueError) as e:
2766 self._DoBinman('ls', '-i', updated_fname)
2767 finally:
2768 shutil.rmtree(tmpdir)
Simon Glass61f564d2019-07-08 14:25:48 -06002769 self.assertIn("Cannot find FDT map in image", str(e.exception))
2770
2771 def _RunListCmd(self, paths, expected):
2772 """List out entries and check the result
2773
2774 Args:
2775 paths: List of paths to pass to the list command
2776 expected: Expected list of filenames to be returned, in order
2777 """
2778 self._CheckLz4()
2779 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002780 image_fname = tools.get_output_filename('image.bin')
Simon Glass61f564d2019-07-08 14:25:48 -06002781 image = Image.FromFile(image_fname)
2782 lines = image.GetListEntries(paths)[1]
2783 files = [line[0].strip() for line in lines[1:]]
2784 self.assertEqual(expected, files)
2785
2786 def testListCmdSection(self):
2787 """Test listing the files in a section"""
2788 self._RunListCmd(['section'],
2789 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2790
2791 def testListCmdFile(self):
2792 """Test listing a particular file"""
2793 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2794
2795 def testListCmdWildcard(self):
2796 """Test listing a wildcarded file"""
2797 self._RunListCmd(['*boot*'],
2798 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2799
2800 def testListCmdWildcardMulti(self):
2801 """Test listing a wildcarded file"""
2802 self._RunListCmd(['*cb*', '*head*'],
2803 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2804
2805 def testListCmdEmpty(self):
2806 """Test listing a wildcarded file"""
2807 self._RunListCmd(['nothing'], [])
2808
2809 def testListCmdPath(self):
2810 """Test listing the files in a sub-entry of a section"""
2811 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2812
Simon Glassf667e452019-07-08 14:25:50 -06002813 def _RunExtractCmd(self, entry_name, decomp=True):
2814 """Extract an entry from an image
2815
2816 Args:
2817 entry_name: Entry name to extract
2818 decomp: True to decompress the data if compressed, False to leave
2819 it in its raw uncompressed format
2820
2821 Returns:
2822 data from entry
2823 """
2824 self._CheckLz4()
2825 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002826 image_fname = tools.get_output_filename('image.bin')
Simon Glassf667e452019-07-08 14:25:50 -06002827 return control.ReadEntry(image_fname, entry_name, decomp)
2828
2829 def testExtractSimple(self):
2830 """Test extracting a single file"""
2831 data = self._RunExtractCmd('u-boot')
2832 self.assertEqual(U_BOOT_DATA, data)
2833
Simon Glass71ce0ba2019-07-08 14:25:52 -06002834 def testExtractSection(self):
2835 """Test extracting the files in a section"""
2836 data = self._RunExtractCmd('section')
2837 cbfs_data = data[:0x400]
2838 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002839 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass71ce0ba2019-07-08 14:25:52 -06002840 dtb_data = data[0x400:]
2841 dtb = self._decompress(dtb_data)
2842 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2843
2844 def testExtractCompressed(self):
2845 """Test extracting compressed data"""
2846 data = self._RunExtractCmd('section/u-boot-dtb')
2847 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2848
2849 def testExtractRaw(self):
2850 """Test extracting compressed data without decompressing it"""
2851 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2852 dtb = self._decompress(data)
2853 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2854
2855 def testExtractCbfs(self):
2856 """Test extracting CBFS data"""
2857 data = self._RunExtractCmd('section/cbfs/u-boot')
2858 self.assertEqual(U_BOOT_DATA, data)
2859
2860 def testExtractCbfsCompressed(self):
2861 """Test extracting CBFS compressed data"""
2862 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2863 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2864
2865 def testExtractCbfsRaw(self):
2866 """Test extracting CBFS compressed data without decompressing it"""
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +02002867 bintool = self.comp_bintools['lzma_alone']
2868 self._CheckBintool(bintool)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002869 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +02002870 dtb = bintool.decompress(data)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002871 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2872
Simon Glassf667e452019-07-08 14:25:50 -06002873 def testExtractBadEntry(self):
2874 """Test extracting a bad section path"""
2875 with self.assertRaises(ValueError) as e:
2876 self._RunExtractCmd('section/does-not-exist')
2877 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2878 str(e.exception))
2879
2880 def testExtractMissingFile(self):
2881 """Test extracting file that does not exist"""
2882 with self.assertRaises(IOError) as e:
2883 control.ReadEntry('missing-file', 'name')
2884
2885 def testExtractBadFile(self):
2886 """Test extracting an invalid file"""
2887 fname = os.path.join(self._indir, 'badfile')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002888 tools.write_file(fname, b'')
Simon Glassf667e452019-07-08 14:25:50 -06002889 with self.assertRaises(ValueError) as e:
2890 control.ReadEntry(fname, 'name')
2891
Simon Glass71ce0ba2019-07-08 14:25:52 -06002892 def testExtractCmd(self):
2893 """Test extracting a file fron an image on the command line"""
2894 self._CheckLz4()
2895 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass71ce0ba2019-07-08 14:25:52 -06002896 fname = os.path.join(self._indir, 'output.extact')
Simon Glassf86a7362019-07-20 12:24:10 -06002897 try:
2898 tmpdir, updated_fname = self._SetupImageInTmpdir()
2899 with test_util.capture_sys_output() as (stdout, stderr):
2900 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2901 '-f', fname)
2902 finally:
2903 shutil.rmtree(tmpdir)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002904 data = tools.read_file(fname)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002905 self.assertEqual(U_BOOT_DATA, data)
2906
2907 def testExtractOneEntry(self):
2908 """Test extracting a single entry fron an image """
2909 self._CheckLz4()
2910 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002911 image_fname = tools.get_output_filename('image.bin')
Simon Glass71ce0ba2019-07-08 14:25:52 -06002912 fname = os.path.join(self._indir, 'output.extact')
2913 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
Simon Glassc1aa66e2022-01-29 14:14:04 -07002914 data = tools.read_file(fname)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002915 self.assertEqual(U_BOOT_DATA, data)
2916
2917 def _CheckExtractOutput(self, decomp):
2918 """Helper to test file output with and without decompression
2919
2920 Args:
2921 decomp: True to decompress entry data, False to output it raw
2922 """
2923 def _CheckPresent(entry_path, expect_data, expect_size=None):
2924 """Check and remove expected file
2925
2926 This checks the data/size of a file and removes the file both from
2927 the outfiles set and from the output directory. Once all files are
2928 processed, both the set and directory should be empty.
2929
2930 Args:
2931 entry_path: Entry path
2932 expect_data: Data to expect in file, or None to skip check
2933 expect_size: Size of data to expect in file, or None to skip
2934 """
2935 path = os.path.join(outdir, entry_path)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002936 data = tools.read_file(path)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002937 os.remove(path)
2938 if expect_data:
2939 self.assertEqual(expect_data, data)
2940 elif expect_size:
2941 self.assertEqual(expect_size, len(data))
2942 outfiles.remove(path)
2943
2944 def _CheckDirPresent(name):
2945 """Remove expected directory
2946
2947 This gives an error if the directory does not exist as expected
2948
2949 Args:
2950 name: Name of directory to remove
2951 """
2952 path = os.path.join(outdir, name)
2953 os.rmdir(path)
2954
2955 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002956 image_fname = tools.get_output_filename('image.bin')
Simon Glass71ce0ba2019-07-08 14:25:52 -06002957 outdir = os.path.join(self._indir, 'extract')
2958 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2959
2960 # Create a set of all file that were output (should be 9)
2961 outfiles = set()
2962 for root, dirs, files in os.walk(outdir):
2963 outfiles |= set([os.path.join(root, fname) for fname in files])
2964 self.assertEqual(9, len(outfiles))
2965 self.assertEqual(9, len(einfos))
2966
2967 image = control.images['image']
2968 entries = image.GetEntries()
2969
2970 # Check the 9 files in various ways
2971 section = entries['section']
2972 section_entries = section.GetEntries()
2973 cbfs_entries = section_entries['cbfs'].GetEntries()
2974 _CheckPresent('u-boot', U_BOOT_DATA)
2975 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
2976 dtb_len = EXTRACT_DTB_SIZE
2977 if not decomp:
2978 dtb_len = cbfs_entries['u-boot-dtb'].size
2979 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
2980 if not decomp:
2981 dtb_len = section_entries['u-boot-dtb'].size
2982 _CheckPresent('section/u-boot-dtb', None, dtb_len)
2983
2984 fdtmap = entries['fdtmap']
2985 _CheckPresent('fdtmap', fdtmap.data)
2986 hdr = entries['image-header']
2987 _CheckPresent('image-header', hdr.data)
2988
2989 _CheckPresent('section/root', section.data)
2990 cbfs = section_entries['cbfs']
2991 _CheckPresent('section/cbfs/root', cbfs.data)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002992 data = tools.read_file(image_fname)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002993 _CheckPresent('root', data)
2994
2995 # There should be no files left. Remove all the directories to check.
2996 # If there are any files/dirs remaining, one of these checks will fail.
2997 self.assertEqual(0, len(outfiles))
2998 _CheckDirPresent('section/cbfs')
2999 _CheckDirPresent('section')
3000 _CheckDirPresent('')
3001 self.assertFalse(os.path.exists(outdir))
3002
3003 def testExtractAllEntries(self):
3004 """Test extracting all entries"""
3005 self._CheckLz4()
3006 self._CheckExtractOutput(decomp=True)
3007
3008 def testExtractAllEntriesRaw(self):
3009 """Test extracting all entries without decompressing them"""
3010 self._CheckLz4()
3011 self._CheckExtractOutput(decomp=False)
3012
3013 def testExtractSelectedEntries(self):
3014 """Test extracting some entries"""
3015 self._CheckLz4()
3016 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003017 image_fname = tools.get_output_filename('image.bin')
Simon Glass71ce0ba2019-07-08 14:25:52 -06003018 outdir = os.path.join(self._indir, 'extract')
3019 einfos = control.ExtractEntries(image_fname, None, outdir,
3020 ['*cb*', '*head*'])
3021
3022 # File output is tested by testExtractAllEntries(), so just check that
3023 # the expected entries are selected
3024 names = [einfo.name for einfo in einfos]
3025 self.assertEqual(names,
3026 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
3027
3028 def testExtractNoEntryPaths(self):
3029 """Test extracting some entries"""
3030 self._CheckLz4()
3031 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003032 image_fname = tools.get_output_filename('image.bin')
Simon Glass71ce0ba2019-07-08 14:25:52 -06003033 with self.assertRaises(ValueError) as e:
3034 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassbb5edc12019-07-20 12:24:14 -06003035 self.assertIn('Must specify an entry path to write with -f',
Simon Glass71ce0ba2019-07-08 14:25:52 -06003036 str(e.exception))
3037
3038 def testExtractTooManyEntryPaths(self):
3039 """Test extracting some entries"""
3040 self._CheckLz4()
3041 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003042 image_fname = tools.get_output_filename('image.bin')
Simon Glass71ce0ba2019-07-08 14:25:52 -06003043 with self.assertRaises(ValueError) as e:
3044 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassbb5edc12019-07-20 12:24:14 -06003045 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass71ce0ba2019-07-08 14:25:52 -06003046 str(e.exception))
3047
Simon Glasse2705fa2019-07-08 14:25:53 -06003048 def testPackAlignSection(self):
3049 """Test that sections can have alignment"""
3050 self._DoReadFile('131_pack_align_section.dts')
3051
3052 self.assertIn('image', control.images)
3053 image = control.images['image']
3054 entries = image.GetEntries()
3055 self.assertEqual(3, len(entries))
3056
3057 # First u-boot
3058 self.assertIn('u-boot', entries)
3059 entry = entries['u-boot']
3060 self.assertEqual(0, entry.offset)
3061 self.assertEqual(0, entry.image_pos)
3062 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3063 self.assertEqual(len(U_BOOT_DATA), entry.size)
3064
3065 # Section0
3066 self.assertIn('section0', entries)
3067 section0 = entries['section0']
3068 self.assertEqual(0x10, section0.offset)
3069 self.assertEqual(0x10, section0.image_pos)
3070 self.assertEqual(len(U_BOOT_DATA), section0.size)
3071
3072 # Second u-boot
3073 section_entries = section0.GetEntries()
3074 self.assertIn('u-boot', section_entries)
3075 entry = section_entries['u-boot']
3076 self.assertEqual(0, entry.offset)
3077 self.assertEqual(0x10, entry.image_pos)
3078 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3079 self.assertEqual(len(U_BOOT_DATA), entry.size)
3080
3081 # Section1
3082 self.assertIn('section1', entries)
3083 section1 = entries['section1']
3084 self.assertEqual(0x14, section1.offset)
3085 self.assertEqual(0x14, section1.image_pos)
3086 self.assertEqual(0x20, section1.size)
3087
3088 # Second u-boot
3089 section_entries = section1.GetEntries()
3090 self.assertIn('u-boot', section_entries)
3091 entry = section_entries['u-boot']
3092 self.assertEqual(0, entry.offset)
3093 self.assertEqual(0x14, entry.image_pos)
3094 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3095 self.assertEqual(len(U_BOOT_DATA), entry.size)
3096
3097 # Section2
3098 self.assertIn('section2', section_entries)
3099 section2 = section_entries['section2']
3100 self.assertEqual(0x4, section2.offset)
3101 self.assertEqual(0x18, section2.image_pos)
3102 self.assertEqual(4, section2.size)
3103
3104 # Third u-boot
3105 section_entries = section2.GetEntries()
3106 self.assertIn('u-boot', section_entries)
3107 entry = section_entries['u-boot']
3108 self.assertEqual(0, entry.offset)
3109 self.assertEqual(0x18, entry.image_pos)
3110 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3111 self.assertEqual(len(U_BOOT_DATA), entry.size)
3112
Simon Glass51014aa2019-07-20 12:23:56 -06003113 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3114 dts='132_replace.dts'):
Simon Glass10f9d002019-07-20 12:23:50 -06003115 """Replace an entry in an image
3116
3117 This writes the entry data to update it, then opens the updated file and
3118 returns the value that it now finds there.
3119
3120 Args:
3121 entry_name: Entry name to replace
3122 data: Data to replace it with
3123 decomp: True to compress the data if needed, False if data is
3124 already compressed so should be used as is
Simon Glass51014aa2019-07-20 12:23:56 -06003125 allow_resize: True to allow entries to change size, False to raise
3126 an exception
Simon Glass10f9d002019-07-20 12:23:50 -06003127
3128 Returns:
3129 Tuple:
3130 data from entry
3131 data from fdtmap (excluding header)
Simon Glass51014aa2019-07-20 12:23:56 -06003132 Image object that was modified
Simon Glass10f9d002019-07-20 12:23:50 -06003133 """
Simon Glass51014aa2019-07-20 12:23:56 -06003134 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass10f9d002019-07-20 12:23:50 -06003135 update_dtb=True)[1]
3136
3137 self.assertIn('image', control.images)
3138 image = control.images['image']
3139 entries = image.GetEntries()
3140 orig_dtb_data = entries['u-boot-dtb'].data
3141 orig_fdtmap_data = entries['fdtmap'].data
3142
Simon Glassc1aa66e2022-01-29 14:14:04 -07003143 image_fname = tools.get_output_filename('image.bin')
3144 updated_fname = tools.get_output_filename('image-updated.bin')
3145 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glass51014aa2019-07-20 12:23:56 -06003146 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3147 allow_resize)
Simon Glass10f9d002019-07-20 12:23:50 -06003148 data = control.ReadEntry(updated_fname, entry_name, decomp)
3149
Simon Glass51014aa2019-07-20 12:23:56 -06003150 # The DT data should not change unless resized:
3151 if not allow_resize:
3152 new_dtb_data = entries['u-boot-dtb'].data
3153 self.assertEqual(new_dtb_data, orig_dtb_data)
3154 new_fdtmap_data = entries['fdtmap'].data
3155 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass10f9d002019-07-20 12:23:50 -06003156
Simon Glass51014aa2019-07-20 12:23:56 -06003157 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass10f9d002019-07-20 12:23:50 -06003158
3159 def testReplaceSimple(self):
3160 """Test replacing a single file"""
3161 expected = b'x' * len(U_BOOT_DATA)
Simon Glass51014aa2019-07-20 12:23:56 -06003162 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3163 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06003164 self.assertEqual(expected, data)
3165
3166 # Test that the state looks right. There should be an FDT for the fdtmap
3167 # that we jsut read back in, and it should match what we find in the
3168 # 'control' tables. Checking for an FDT that does not exist should
3169 # return None.
3170 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glass51014aa2019-07-20 12:23:56 -06003171 self.assertIsNotNone(path)
Simon Glass10f9d002019-07-20 12:23:50 -06003172 self.assertEqual(expected_fdtmap, fdtmap)
3173
3174 dtb = state.GetFdtForEtype('fdtmap')
3175 self.assertEqual(dtb.GetContents(), fdtmap)
3176
3177 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3178 self.assertIsNone(missing_path)
3179 self.assertIsNone(missing_fdtmap)
3180
3181 missing_dtb = state.GetFdtForEtype('missing')
3182 self.assertIsNone(missing_dtb)
3183
3184 self.assertEqual('/binman', state.fdt_path_prefix)
3185
3186 def testReplaceResizeFail(self):
3187 """Test replacing a file by something larger"""
3188 expected = U_BOOT_DATA + b'x'
3189 with self.assertRaises(ValueError) as e:
Simon Glass51014aa2019-07-20 12:23:56 -06003190 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3191 dts='139_replace_repack.dts')
Simon Glass10f9d002019-07-20 12:23:50 -06003192 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3193 str(e.exception))
3194
3195 def testReplaceMulti(self):
3196 """Test replacing entry data where multiple images are generated"""
3197 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3198 update_dtb=True)[0]
3199 expected = b'x' * len(U_BOOT_DATA)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003200 updated_fname = tools.get_output_filename('image-updated.bin')
3201 tools.write_file(updated_fname, data)
Simon Glass10f9d002019-07-20 12:23:50 -06003202 entry_name = 'u-boot'
Simon Glass51014aa2019-07-20 12:23:56 -06003203 control.WriteEntry(updated_fname, entry_name, expected,
3204 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06003205 data = control.ReadEntry(updated_fname, entry_name)
3206 self.assertEqual(expected, data)
3207
3208 # Check the state looks right.
3209 self.assertEqual('/binman/image', state.fdt_path_prefix)
3210
3211 # Now check we can write the first image
Simon Glassc1aa66e2022-01-29 14:14:04 -07003212 image_fname = tools.get_output_filename('first-image.bin')
3213 updated_fname = tools.get_output_filename('first-updated.bin')
3214 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glass10f9d002019-07-20 12:23:50 -06003215 entry_name = 'u-boot'
Simon Glass51014aa2019-07-20 12:23:56 -06003216 control.WriteEntry(updated_fname, entry_name, expected,
3217 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06003218 data = control.ReadEntry(updated_fname, entry_name)
3219 self.assertEqual(expected, data)
3220
3221 # Check the state looks right.
3222 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass8beb11e2019-07-08 14:25:47 -06003223
Simon Glass12bb1a92019-07-20 12:23:51 -06003224 def testUpdateFdtAllRepack(self):
3225 """Test that all device trees are updated with offset/size info"""
3226 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3227 SECTION_SIZE = 0x300
3228 DTB_SIZE = 602
3229 FDTMAP_SIZE = 608
3230 base_expected = {
3231 'offset': 0,
3232 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3233 'image-pos': 0,
3234 'section:offset': 0,
3235 'section:size': SECTION_SIZE,
3236 'section:image-pos': 0,
3237 'section/u-boot-dtb:offset': 4,
3238 'section/u-boot-dtb:size': 636,
3239 'section/u-boot-dtb:image-pos': 4,
3240 'u-boot-spl-dtb:offset': SECTION_SIZE,
3241 'u-boot-spl-dtb:size': DTB_SIZE,
3242 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3243 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3244 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3245 'u-boot-tpl-dtb:size': DTB_SIZE,
3246 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3247 'fdtmap:size': FDTMAP_SIZE,
3248 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3249 }
3250 main_expected = {
3251 'section:orig-size': SECTION_SIZE,
3252 'section/u-boot-dtb:orig-offset': 4,
3253 }
3254
3255 # We expect three device-tree files in the output, with the first one
3256 # within a fixed-size section.
3257 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3258 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3259 # main U-Boot tree. All three should have the same positions and offset
3260 # except that the main tree should include the main_expected properties
3261 start = 4
3262 for item in ['', 'spl', 'tpl', None]:
3263 if item is None:
3264 start += 16 # Move past fdtmap header
3265 dtb = fdt.Fdt.FromData(data[start:])
3266 dtb.Scan()
3267 props = self._GetPropTree(dtb,
3268 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3269 prefix='/' if item is None else '/binman/')
3270 expected = dict(base_expected)
3271 if item:
3272 expected[item] = 0
3273 else:
3274 # Main DTB and fdtdec should include the 'orig-' properties
3275 expected.update(main_expected)
3276 # Helpful for debugging:
3277 #for prop in sorted(props):
3278 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3279 self.assertEqual(expected, props)
3280 if item == '':
3281 start = SECTION_SIZE
3282 else:
3283 start += dtb._fdt_obj.totalsize()
3284
Simon Glasseba1f0c2019-07-20 12:23:55 -06003285 def testFdtmapHeaderMiddle(self):
3286 """Test an FDT map in the middle of an image when it should be at end"""
3287 with self.assertRaises(ValueError) as e:
3288 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3289 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3290 str(e.exception))
3291
3292 def testFdtmapHeaderStartBad(self):
3293 """Test an FDT map in middle of an image when it should be at start"""
3294 with self.assertRaises(ValueError) as e:
3295 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3296 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3297 str(e.exception))
3298
3299 def testFdtmapHeaderEndBad(self):
3300 """Test an FDT map at the start of an image when it should be at end"""
3301 with self.assertRaises(ValueError) as e:
3302 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3303 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3304 str(e.exception))
3305
3306 def testFdtmapHeaderNoSize(self):
3307 """Test an image header at the end of an image with undefined size"""
3308 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3309
Simon Glass51014aa2019-07-20 12:23:56 -06003310 def testReplaceResize(self):
3311 """Test replacing a single file in an entry with a larger file"""
3312 expected = U_BOOT_DATA + b'x'
3313 data, _, image = self._RunReplaceCmd('u-boot', expected,
3314 dts='139_replace_repack.dts')
3315 self.assertEqual(expected, data)
3316
3317 entries = image.GetEntries()
3318 dtb_data = entries['u-boot-dtb'].data
3319 dtb = fdt.Fdt.FromData(dtb_data)
3320 dtb.Scan()
3321
3322 # The u-boot section should now be larger in the dtb
3323 node = dtb.GetNode('/binman/u-boot')
3324 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3325
3326 # Same for the fdtmap
3327 fdata = entries['fdtmap'].data
3328 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3329 fdtb.Scan()
3330 fnode = fdtb.GetNode('/u-boot')
3331 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3332
3333 def testReplaceResizeNoRepack(self):
3334 """Test replacing an entry with a larger file when not allowed"""
3335 expected = U_BOOT_DATA + b'x'
3336 with self.assertRaises(ValueError) as e:
3337 self._RunReplaceCmd('u-boot', expected)
3338 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3339 str(e.exception))
3340
Simon Glass61ec04f2019-07-20 12:23:58 -06003341 def testEntryShrink(self):
3342 """Test contracting an entry after it is packed"""
3343 try:
3344 state.SetAllowEntryContraction(True)
3345 data = self._DoReadFileDtb('140_entry_shrink.dts',
3346 update_dtb=True)[0]
3347 finally:
3348 state.SetAllowEntryContraction(False)
3349 self.assertEqual(b'a', data[:1])
3350 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3351 self.assertEqual(b'a', data[-1:])
3352
3353 def testEntryShrinkFail(self):
3354 """Test not being allowed to contract an entry after it is packed"""
3355 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3356
3357 # In this case there is a spare byte at the end of the data. The size of
3358 # the contents is only 1 byte but we still have the size before it
3359 # shrunk.
3360 self.assertEqual(b'a\0', data[:2])
3361 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3362 self.assertEqual(b'a\0', data[-2:])
3363
Simon Glass27145fd2019-07-20 12:24:01 -06003364 def testDescriptorOffset(self):
3365 """Test that the Intel descriptor is always placed at at the start"""
3366 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3367 image = control.images['image']
3368 entries = image.GetEntries()
3369 desc = entries['intel-descriptor']
3370 self.assertEqual(0xff800000, desc.offset);
3371 self.assertEqual(0xff800000, desc.image_pos);
3372
Simon Glasseb0f4a42019-07-20 12:24:06 -06003373 def testReplaceCbfs(self):
3374 """Test replacing a single file in CBFS without changing the size"""
3375 self._CheckLz4()
3376 expected = b'x' * len(U_BOOT_DATA)
3377 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003378 updated_fname = tools.get_output_filename('image-updated.bin')
3379 tools.write_file(updated_fname, data)
Simon Glasseb0f4a42019-07-20 12:24:06 -06003380 entry_name = 'section/cbfs/u-boot'
3381 control.WriteEntry(updated_fname, entry_name, expected,
3382 allow_resize=True)
3383 data = control.ReadEntry(updated_fname, entry_name)
3384 self.assertEqual(expected, data)
3385
3386 def testReplaceResizeCbfs(self):
3387 """Test replacing a single file in CBFS with one of a different size"""
3388 self._CheckLz4()
3389 expected = U_BOOT_DATA + b'x'
3390 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003391 updated_fname = tools.get_output_filename('image-updated.bin')
3392 tools.write_file(updated_fname, data)
Simon Glasseb0f4a42019-07-20 12:24:06 -06003393 entry_name = 'section/cbfs/u-boot'
3394 control.WriteEntry(updated_fname, entry_name, expected,
3395 allow_resize=True)
3396 data = control.ReadEntry(updated_fname, entry_name)
3397 self.assertEqual(expected, data)
3398
Simon Glassa6cb9952019-07-20 12:24:15 -06003399 def _SetupForReplace(self):
3400 """Set up some files to use to replace entries
3401
3402 This generates an image, copies it to a new file, extracts all the files
3403 in it and updates some of them
3404
3405 Returns:
3406 List
3407 Image filename
3408 Output directory
3409 Expected values for updated entries, each a string
3410 """
3411 data = self._DoReadFileRealDtb('143_replace_all.dts')
3412
Simon Glassc1aa66e2022-01-29 14:14:04 -07003413 updated_fname = tools.get_output_filename('image-updated.bin')
3414 tools.write_file(updated_fname, data)
Simon Glassa6cb9952019-07-20 12:24:15 -06003415
3416 outdir = os.path.join(self._indir, 'extract')
3417 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3418
3419 expected1 = b'x' + U_BOOT_DATA + b'y'
3420 u_boot_fname1 = os.path.join(outdir, 'u-boot')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003421 tools.write_file(u_boot_fname1, expected1)
Simon Glassa6cb9952019-07-20 12:24:15 -06003422
3423 expected2 = b'a' + U_BOOT_DATA + b'b'
3424 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003425 tools.write_file(u_boot_fname2, expected2)
Simon Glassa6cb9952019-07-20 12:24:15 -06003426
3427 expected_text = b'not the same text'
3428 text_fname = os.path.join(outdir, 'text')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003429 tools.write_file(text_fname, expected_text)
Simon Glassa6cb9952019-07-20 12:24:15 -06003430
3431 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3432 dtb = fdt.FdtScan(dtb_fname)
3433 node = dtb.GetNode('/binman/text')
3434 node.AddString('my-property', 'the value')
3435 dtb.Sync(auto_resize=True)
3436 dtb.Flush()
3437
3438 return updated_fname, outdir, expected1, expected2, expected_text
3439
3440 def _CheckReplaceMultiple(self, entry_paths):
3441 """Handle replacing the contents of multiple entries
3442
3443 Args:
3444 entry_paths: List of entry paths to replace
3445
3446 Returns:
3447 List
3448 Dict of entries in the image:
3449 key: Entry name
3450 Value: Entry object
3451 Expected values for updated entries, each a string
3452 """
3453 updated_fname, outdir, expected1, expected2, expected_text = (
3454 self._SetupForReplace())
3455 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3456
3457 image = Image.FromFile(updated_fname)
3458 image.LoadData()
3459 return image.GetEntries(), expected1, expected2, expected_text
3460
3461 def testReplaceAll(self):
3462 """Test replacing the contents of all entries"""
3463 entries, expected1, expected2, expected_text = (
3464 self._CheckReplaceMultiple([]))
3465 data = entries['u-boot'].data
3466 self.assertEqual(expected1, data)
3467
3468 data = entries['u-boot2'].data
3469 self.assertEqual(expected2, data)
3470
3471 data = entries['text'].data
3472 self.assertEqual(expected_text, data)
3473
3474 # Check that the device tree is updated
3475 data = entries['u-boot-dtb'].data
3476 dtb = fdt.Fdt.FromData(data)
3477 dtb.Scan()
3478 node = dtb.GetNode('/binman/text')
3479 self.assertEqual('the value', node.props['my-property'].value)
3480
3481 def testReplaceSome(self):
3482 """Test replacing the contents of a few entries"""
3483 entries, expected1, expected2, expected_text = (
3484 self._CheckReplaceMultiple(['u-boot2', 'text']))
3485
3486 # This one should not change
3487 data = entries['u-boot'].data
3488 self.assertEqual(U_BOOT_DATA, data)
3489
3490 data = entries['u-boot2'].data
3491 self.assertEqual(expected2, data)
3492
3493 data = entries['text'].data
3494 self.assertEqual(expected_text, data)
3495
3496 def testReplaceCmd(self):
3497 """Test replacing a file fron an image on the command line"""
3498 self._DoReadFileRealDtb('143_replace_all.dts')
3499
3500 try:
3501 tmpdir, updated_fname = self._SetupImageInTmpdir()
3502
3503 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3504 expected = b'x' * len(U_BOOT_DATA)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003505 tools.write_file(fname, expected)
Simon Glassa6cb9952019-07-20 12:24:15 -06003506
3507 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003508 data = tools.read_file(updated_fname)
Simon Glassa6cb9952019-07-20 12:24:15 -06003509 self.assertEqual(expected, data[:len(expected)])
3510 map_fname = os.path.join(tmpdir, 'image-updated.map')
3511 self.assertFalse(os.path.exists(map_fname))
3512 finally:
3513 shutil.rmtree(tmpdir)
3514
3515 def testReplaceCmdSome(self):
3516 """Test replacing some files fron an image on the command line"""
3517 updated_fname, outdir, expected1, expected2, expected_text = (
3518 self._SetupForReplace())
3519
3520 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3521 'u-boot2', 'text')
3522
Simon Glassc1aa66e2022-01-29 14:14:04 -07003523 tools.prepare_output_dir(None)
Simon Glassa6cb9952019-07-20 12:24:15 -06003524 image = Image.FromFile(updated_fname)
3525 image.LoadData()
3526 entries = image.GetEntries()
3527
3528 # This one should not change
3529 data = entries['u-boot'].data
3530 self.assertEqual(U_BOOT_DATA, data)
3531
3532 data = entries['u-boot2'].data
3533 self.assertEqual(expected2, data)
3534
3535 data = entries['text'].data
3536 self.assertEqual(expected_text, data)
3537
3538 def testReplaceMissing(self):
3539 """Test replacing entries where the file is missing"""
3540 updated_fname, outdir, expected1, expected2, expected_text = (
3541 self._SetupForReplace())
3542
3543 # Remove one of the files, to generate a warning
3544 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3545 os.remove(u_boot_fname1)
3546
3547 with test_util.capture_sys_output() as (stdout, stderr):
3548 control.ReplaceEntries(updated_fname, None, outdir, [])
3549 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass38fdb4c2020-07-09 18:39:39 -06003550 stderr.getvalue())
Simon Glassa6cb9952019-07-20 12:24:15 -06003551
3552 def testReplaceCmdMap(self):
3553 """Test replacing a file fron an image on the command line"""
3554 self._DoReadFileRealDtb('143_replace_all.dts')
3555
3556 try:
3557 tmpdir, updated_fname = self._SetupImageInTmpdir()
3558
3559 fname = os.path.join(self._indir, 'update-u-boot.bin')
3560 expected = b'x' * len(U_BOOT_DATA)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003561 tools.write_file(fname, expected)
Simon Glassa6cb9952019-07-20 12:24:15 -06003562
3563 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3564 '-f', fname, '-m')
3565 map_fname = os.path.join(tmpdir, 'image-updated.map')
3566 self.assertTrue(os.path.exists(map_fname))
3567 finally:
3568 shutil.rmtree(tmpdir)
3569
3570 def testReplaceNoEntryPaths(self):
3571 """Test replacing an entry without an entry path"""
3572 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003573 image_fname = tools.get_output_filename('image.bin')
Simon Glassa6cb9952019-07-20 12:24:15 -06003574 with self.assertRaises(ValueError) as e:
3575 control.ReplaceEntries(image_fname, 'fname', None, [])
3576 self.assertIn('Must specify an entry path to read with -f',
3577 str(e.exception))
3578
3579 def testReplaceTooManyEntryPaths(self):
3580 """Test extracting some entries"""
3581 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003582 image_fname = tools.get_output_filename('image.bin')
Simon Glassa6cb9952019-07-20 12:24:15 -06003583 with self.assertRaises(ValueError) as e:
3584 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3585 self.assertIn('Must specify exactly one entry path to write with -f',
3586 str(e.exception))
3587
Simon Glass2250ee62019-08-24 07:22:48 -06003588 def testPackReset16(self):
3589 """Test that an image with an x86 reset16 region can be created"""
3590 data = self._DoReadFile('144_x86_reset16.dts')
3591 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3592
3593 def testPackReset16Spl(self):
3594 """Test that an image with an x86 reset16-spl region can be created"""
3595 data = self._DoReadFile('145_x86_reset16_spl.dts')
3596 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3597
3598 def testPackReset16Tpl(self):
3599 """Test that an image with an x86 reset16-tpl region can be created"""
3600 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3601 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3602
Simon Glass5af12072019-08-24 07:22:50 -06003603 def testPackIntelFit(self):
3604 """Test that an image with an Intel FIT and pointer can be created"""
3605 data = self._DoReadFile('147_intel_fit.dts')
3606 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3607 fit = data[16:32];
3608 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3609 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3610
3611 image = control.images['image']
3612 entries = image.GetEntries()
3613 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3614 self.assertEqual(expected_ptr, ptr)
3615
3616 def testPackIntelFitMissing(self):
3617 """Test detection of a FIT pointer with not FIT region"""
3618 with self.assertRaises(ValueError) as e:
3619 self._DoReadFile('148_intel_fit_missing.dts')
3620 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3621 str(e.exception))
3622
Simon Glass7c150132019-11-06 17:22:44 -07003623 def _CheckSymbolsTplSection(self, dts, expected_vals):
3624 data = self._DoReadFile(dts)
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003625 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE, *expected_vals)
Simon Glass2090f1e2019-08-24 07:23:00 -06003626 upto1 = 4 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003627 expected1 = tools.get_bytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass2090f1e2019-08-24 07:23:00 -06003628 self.assertEqual(expected1, data[:upto1])
3629
3630 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003631 expected2 = tools.get_bytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass2090f1e2019-08-24 07:23:00 -06003632 self.assertEqual(expected2, data[upto1:upto2])
3633
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003634 upto3 = 0x3c + len(U_BOOT_DATA)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003635 expected3 = tools.get_bytes(0xff, 1) + U_BOOT_DATA
Simon Glass2090f1e2019-08-24 07:23:00 -06003636 self.assertEqual(expected3, data[upto2:upto3])
3637
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003638 expected4 = sym_values + U_BOOT_TPL_DATA[24:]
Simon Glass7c150132019-11-06 17:22:44 -07003639 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3640
3641 def testSymbolsTplSection(self):
3642 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3643 self._SetupSplElf('u_boot_binman_syms')
3644 self._SetupTplElf('u_boot_binman_syms')
3645 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003646 [0x04, 0x20, 0x10 + 0x3c, 0x04])
Simon Glass7c150132019-11-06 17:22:44 -07003647
3648 def testSymbolsTplSectionX86(self):
3649 """Test binman can assign symbols in a section with end-at-4gb"""
3650 self._SetupSplElf('u_boot_binman_syms_x86')
3651 self._SetupTplElf('u_boot_binman_syms_x86')
3652 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003653 [0xffffff04, 0xffffff20, 0xffffff3c,
Simon Glass7c150132019-11-06 17:22:44 -07003654 0x04])
Simon Glass2090f1e2019-08-24 07:23:00 -06003655
Simon Glassbf4d0e22019-08-24 07:23:03 -06003656 def testPackX86RomIfwiSectiom(self):
3657 """Test that a section can be placed in an IFWI region"""
3658 self._SetupIfwi('fitimage.bin')
3659 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3660 self._CheckIfwi(data)
3661
Simon Glassea0fff92019-08-24 07:23:07 -06003662 def testPackFspM(self):
3663 """Test that an image with a FSP memory-init binary can be created"""
3664 data = self._DoReadFile('152_intel_fsp_m.dts')
3665 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3666
Simon Glassbc6a88f2019-10-20 21:31:35 -06003667 def testPackFspS(self):
3668 """Test that an image with a FSP silicon-init binary can be created"""
3669 data = self._DoReadFile('153_intel_fsp_s.dts')
3670 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassea0fff92019-08-24 07:23:07 -06003671
Simon Glass998d1482019-10-20 21:31:36 -06003672 def testPackFspT(self):
3673 """Test that an image with a FSP temp-ram-init binary can be created"""
3674 data = self._DoReadFile('154_intel_fsp_t.dts')
3675 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3676
Simon Glass0dc706f2020-07-09 18:39:31 -06003677 def testMkimage(self):
3678 """Test using mkimage to build an image"""
3679 data = self._DoReadFile('156_mkimage.dts')
3680
3681 # Just check that the data appears in the file somewhere
3682 self.assertIn(U_BOOT_SPL_DATA, data)
3683
Simon Glass4f9ee832022-01-09 20:14:09 -07003684 def testMkimageMissing(self):
3685 """Test that binman still produces an image if mkimage is missing"""
3686 with test_util.capture_sys_output() as (_, stderr):
3687 self._DoTestFile('156_mkimage.dts',
3688 force_missing_bintools='mkimage')
3689 err = stderr.getvalue()
3690 self.assertRegex(err,
3691 "Image 'main-section'.*missing bintools.*: mkimage")
3692
Simon Glassce867ad2020-07-09 18:39:36 -06003693 def testExtblob(self):
3694 """Test an image with an external blob"""
3695 data = self._DoReadFile('157_blob_ext.dts')
3696 self.assertEqual(REFCODE_DATA, data)
3697
3698 def testExtblobMissing(self):
3699 """Test an image with a missing external blob"""
3700 with self.assertRaises(ValueError) as e:
3701 self._DoReadFile('158_blob_ext_missing.dts')
3702 self.assertIn("Filename 'missing-file' not found in input path",
3703 str(e.exception))
3704
Simon Glass4f9f1052020-07-09 18:39:38 -06003705 def testExtblobMissingOk(self):
3706 """Test an image with an missing external blob that is allowed"""
Simon Glassb1cca952020-07-09 18:39:40 -06003707 with test_util.capture_sys_output() as (stdout, stderr):
3708 self._DoTestFile('158_blob_ext_missing.dts', allow_missing=True)
3709 err = stderr.getvalue()
3710 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
3711
3712 def testExtblobMissingOkSect(self):
3713 """Test an image with an missing external blob that is allowed"""
3714 with test_util.capture_sys_output() as (stdout, stderr):
3715 self._DoTestFile('159_blob_ext_missing_sect.dts',
3716 allow_missing=True)
3717 err = stderr.getvalue()
3718 self.assertRegex(err, "Image 'main-section'.*missing.*: "
3719 "blob-ext blob-ext2")
Simon Glass4f9f1052020-07-09 18:39:38 -06003720
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003721 def testPackX86RomMeMissingDesc(self):
3722 """Test that an missing Intel descriptor entry is allowed"""
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003723 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass52b10dd2020-07-25 15:11:19 -06003724 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003725 err = stderr.getvalue()
3726 self.assertRegex(err,
3727 "Image 'main-section'.*missing.*: intel-descriptor")
3728
3729 def testPackX86RomMissingIfwi(self):
3730 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3731 self._SetupIfwi('fitimage.bin')
3732 pathname = os.path.join(self._indir, 'fitimage.bin')
3733 os.remove(pathname)
3734 with test_util.capture_sys_output() as (stdout, stderr):
3735 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3736 err = stderr.getvalue()
3737 self.assertRegex(err, "Image 'main-section'.*missing.*: intel-ifwi")
3738
Simon Glass8d2ef3e2022-02-11 13:23:21 -07003739 def testPackOverlapZero(self):
Simon Glassb3295fd2020-07-09 18:39:42 -06003740 """Test that zero-size overlapping regions are ignored"""
3741 self._DoTestFile('160_pack_overlap_zero.dts')
3742
Alper Nebi Yasak21353312022-02-08 01:08:04 +03003743 def _CheckSimpleFitData(self, fit_data, kernel_data, fdt1_data):
Simon Glassfdc34362020-07-09 18:39:45 -06003744 # The data should be inside the FIT
3745 dtb = fdt.Fdt.FromData(fit_data)
3746 dtb.Scan()
3747 fnode = dtb.GetNode('/images/kernel')
3748 self.assertIn('data', fnode.props)
3749
3750 fname = os.path.join(self._indir, 'fit_data.fit')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003751 tools.write_file(fname, fit_data)
3752 out = tools.run('dumpimage', '-l', fname)
Simon Glassfdc34362020-07-09 18:39:45 -06003753
3754 # Check a few features to make sure the plumbing works. We don't need
3755 # to test the operation of mkimage or dumpimage here. First convert the
3756 # output into a dict where the keys are the fields printed by dumpimage
3757 # and the values are a list of values for each field
3758 lines = out.splitlines()
3759
3760 # Converts "Compression: gzip compressed" into two groups:
3761 # 'Compression' and 'gzip compressed'
3762 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3763 vals = collections.defaultdict(list)
3764 for line in lines:
3765 mat = re_line.match(line)
3766 vals[mat.group(1)].append(mat.group(2))
3767
3768 self.assertEquals('FIT description: test-desc', lines[0])
3769 self.assertIn('Created:', lines[1])
3770 self.assertIn('Image 0 (kernel)', vals)
3771 self.assertIn('Hash value', vals)
3772 data_sizes = vals.get('Data Size')
3773 self.assertIsNotNone(data_sizes)
3774 self.assertEqual(2, len(data_sizes))
3775 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
Alper Nebi Yasak21353312022-02-08 01:08:04 +03003776 self.assertEqual(len(kernel_data), int(data_sizes[0].split()[0]))
3777 self.assertEqual(len(fdt1_data), int(data_sizes[1].split()[0]))
3778
Alper Nebi Yasake7368782022-03-27 18:31:47 +03003779 # Check if entry listing correctly omits /images/
3780 image = control.images['image']
3781 fit_entry = image.GetEntries()['fit']
3782 subentries = list(fit_entry.GetEntries().keys())
3783 expected = ['kernel', 'fdt-1']
3784 self.assertEqual(expected, subentries)
3785
Alper Nebi Yasak21353312022-02-08 01:08:04 +03003786 def testSimpleFit(self):
3787 """Test an image with a FIT inside"""
3788 data = self._DoReadFile('161_fit.dts')
3789 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3790 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3791 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3792
3793 self._CheckSimpleFitData(fit_data, U_BOOT_DATA, U_BOOT_SPL_DTB_DATA)
3794
3795 def testSimpleFitExpandsSubentries(self):
3796 """Test that FIT images expand their subentries"""
3797 data = self._DoReadFileDtb('161_fit.dts', use_expanded=True)[0]
3798 self.assertEqual(U_BOOT_EXP_DATA, data[:len(U_BOOT_EXP_DATA)])
3799 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3800 fit_data = data[len(U_BOOT_EXP_DATA):-len(U_BOOT_NODTB_DATA)]
3801
3802 self._CheckSimpleFitData(fit_data, U_BOOT_EXP_DATA, U_BOOT_SPL_DTB_DATA)
Simon Glassfdc34362020-07-09 18:39:45 -06003803
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003804 def testSimpleFitImagePos(self):
3805 """Test that we have correct image-pos for FIT subentries"""
3806 data, _, _, out_dtb_fname = self._DoReadFileDtb('161_fit.dts',
3807 update_dtb=True)
3808 dtb = fdt.Fdt(out_dtb_fname)
3809 dtb.Scan()
3810 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3811
Simon Glass38397d02022-03-05 20:19:01 -07003812 self.maxDiff = None
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003813 self.assertEqual({
3814 'image-pos': 0,
3815 'offset': 0,
3816 'size': 1890,
3817
3818 'u-boot:image-pos': 0,
3819 'u-boot:offset': 0,
3820 'u-boot:size': 4,
3821
3822 'fit:image-pos': 4,
3823 'fit:offset': 4,
3824 'fit:size': 1840,
3825
Simon Glass38397d02022-03-05 20:19:01 -07003826 'fit/images/kernel:image-pos': 304,
3827 'fit/images/kernel:offset': 300,
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003828 'fit/images/kernel:size': 4,
3829
Simon Glass38397d02022-03-05 20:19:01 -07003830 'fit/images/kernel/u-boot:image-pos': 304,
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003831 'fit/images/kernel/u-boot:offset': 0,
3832 'fit/images/kernel/u-boot:size': 4,
3833
Simon Glass38397d02022-03-05 20:19:01 -07003834 'fit/images/fdt-1:image-pos': 552,
3835 'fit/images/fdt-1:offset': 548,
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003836 'fit/images/fdt-1:size': 6,
3837
Simon Glass38397d02022-03-05 20:19:01 -07003838 'fit/images/fdt-1/u-boot-spl-dtb:image-pos': 552,
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003839 'fit/images/fdt-1/u-boot-spl-dtb:offset': 0,
3840 'fit/images/fdt-1/u-boot-spl-dtb:size': 6,
3841
3842 'u-boot-nodtb:image-pos': 1844,
3843 'u-boot-nodtb:offset': 1844,
3844 'u-boot-nodtb:size': 46,
3845 }, props)
3846
3847 # Actually check the data is where we think it is
3848 for node, expected in [
3849 ("u-boot", U_BOOT_DATA),
3850 ("fit/images/kernel", U_BOOT_DATA),
3851 ("fit/images/kernel/u-boot", U_BOOT_DATA),
3852 ("fit/images/fdt-1", U_BOOT_SPL_DTB_DATA),
3853 ("fit/images/fdt-1/u-boot-spl-dtb", U_BOOT_SPL_DTB_DATA),
3854 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
3855 ]:
3856 image_pos = props[f"{node}:image-pos"]
3857 size = props[f"{node}:size"]
3858 self.assertEqual(len(expected), size)
3859 self.assertEqual(expected, data[image_pos:image_pos+size])
3860
Simon Glassfdc34362020-07-09 18:39:45 -06003861 def testFitExternal(self):
Simon Glasse9d336d2020-09-01 05:13:55 -06003862 """Test an image with an FIT with external images"""
Simon Glassfdc34362020-07-09 18:39:45 -06003863 data = self._DoReadFile('162_fit_external.dts')
3864 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3865
Simon Glass8bc78b72022-01-09 20:13:39 -07003866 # Size of the external-data region as set up by mkimage
3867 external_data_size = len(U_BOOT_DATA) + 2
3868 expected_size = (len(U_BOOT_DATA) + 0x400 +
Simon Glassc1aa66e2022-01-29 14:14:04 -07003869 tools.align(external_data_size, 4) +
Simon Glass8bc78b72022-01-09 20:13:39 -07003870 len(U_BOOT_NODTB_DATA))
3871
Simon Glassfdc34362020-07-09 18:39:45 -06003872 # The data should be outside the FIT
3873 dtb = fdt.Fdt.FromData(fit_data)
3874 dtb.Scan()
3875 fnode = dtb.GetNode('/images/kernel')
3876 self.assertNotIn('data', fnode.props)
Simon Glass8bc78b72022-01-09 20:13:39 -07003877 self.assertEqual(len(U_BOOT_DATA),
3878 fdt_util.fdt32_to_cpu(fnode.props['data-size'].value))
3879 fit_pos = 0x400;
3880 self.assertEqual(
3881 fit_pos,
3882 fdt_util.fdt32_to_cpu(fnode.props['data-position'].value))
3883
3884 self.assertEquals(expected_size, len(data))
3885 actual_pos = len(U_BOOT_DATA) + fit_pos
3886 self.assertEqual(U_BOOT_DATA + b'aa',
3887 data[actual_pos:actual_pos + external_data_size])
Simon Glass12bb1a92019-07-20 12:23:51 -06003888
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003889 def testFitExternalImagePos(self):
3890 """Test that we have correct image-pos for external FIT subentries"""
3891 data, _, _, out_dtb_fname = self._DoReadFileDtb('162_fit_external.dts',
3892 update_dtb=True)
3893 dtb = fdt.Fdt(out_dtb_fname)
3894 dtb.Scan()
3895 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3896
3897 self.assertEqual({
3898 'image-pos': 0,
3899 'offset': 0,
3900 'size': 1082,
3901
3902 'u-boot:image-pos': 0,
3903 'u-boot:offset': 0,
3904 'u-boot:size': 4,
3905
3906 'fit:size': 1032,
3907 'fit:offset': 4,
3908 'fit:image-pos': 4,
3909
3910 'fit/images/kernel:size': 4,
3911 'fit/images/kernel:offset': 1024,
3912 'fit/images/kernel:image-pos': 1028,
3913
3914 'fit/images/kernel/u-boot:size': 4,
3915 'fit/images/kernel/u-boot:offset': 0,
3916 'fit/images/kernel/u-boot:image-pos': 1028,
3917
3918 'fit/images/fdt-1:size': 2,
3919 'fit/images/fdt-1:offset': 1028,
3920 'fit/images/fdt-1:image-pos': 1032,
3921
3922 'fit/images/fdt-1/_testing:size': 2,
3923 'fit/images/fdt-1/_testing:offset': 0,
3924 'fit/images/fdt-1/_testing:image-pos': 1032,
3925
3926 'u-boot-nodtb:image-pos': 1036,
3927 'u-boot-nodtb:offset': 1036,
3928 'u-boot-nodtb:size': 46,
3929 }, props)
3930
3931 # Actually check the data is where we think it is
3932 for node, expected in [
3933 ("u-boot", U_BOOT_DATA),
3934 ("fit/images/kernel", U_BOOT_DATA),
3935 ("fit/images/kernel/u-boot", U_BOOT_DATA),
3936 ("fit/images/fdt-1", b'aa'),
3937 ("fit/images/fdt-1/_testing", b'aa'),
3938 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
3939 ]:
3940 image_pos = props[f"{node}:image-pos"]
3941 size = props[f"{node}:size"]
3942 self.assertEqual(len(expected), size)
3943 self.assertEqual(expected, data[image_pos:image_pos+size])
3944
Simon Glass4f9ee832022-01-09 20:14:09 -07003945 def testFitMissing(self):
3946 """Test that binman still produces a FIT image if mkimage is missing"""
3947 with test_util.capture_sys_output() as (_, stderr):
3948 self._DoTestFile('162_fit_external.dts',
3949 force_missing_bintools='mkimage')
3950 err = stderr.getvalue()
3951 self.assertRegex(err,
3952 "Image 'main-section'.*missing bintools.*: mkimage")
3953
Alper Nebi Yasak8001d0b2020-08-31 12:58:18 +03003954 def testSectionIgnoreHashSignature(self):
3955 """Test that sections ignore hash, signature nodes for its data"""
3956 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
3957 expected = (U_BOOT_DATA + U_BOOT_DATA)
3958 self.assertEqual(expected, data)
3959
Alper Nebi Yasak3fdeb142020-08-31 12:58:19 +03003960 def testPadInSections(self):
3961 """Test pad-before, pad-after for entries in sections"""
Simon Glassf90d9062020-10-26 17:40:09 -06003962 data, _, _, out_dtb_fname = self._DoReadFileDtb(
3963 '166_pad_in_sections.dts', update_dtb=True)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003964 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
3965 U_BOOT_DATA + tools.get_bytes(ord('!'), 6) +
Alper Nebi Yasak3fdeb142020-08-31 12:58:19 +03003966 U_BOOT_DATA)
3967 self.assertEqual(expected, data)
3968
Simon Glassf90d9062020-10-26 17:40:09 -06003969 dtb = fdt.Fdt(out_dtb_fname)
3970 dtb.Scan()
3971 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
3972 expected = {
3973 'image-pos': 0,
3974 'offset': 0,
3975 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
3976
3977 'section:image-pos': 0,
3978 'section:offset': 0,
3979 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
3980
3981 'section/before:image-pos': 0,
3982 'section/before:offset': 0,
3983 'section/before:size': len(U_BOOT_DATA),
3984
3985 'section/u-boot:image-pos': 4,
3986 'section/u-boot:offset': 4,
3987 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
3988
3989 'section/after:image-pos': 26,
3990 'section/after:offset': 26,
3991 'section/after:size': len(U_BOOT_DATA),
3992 }
3993 self.assertEqual(expected, props)
3994
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03003995 def testFitImageSubentryAlignment(self):
3996 """Test relative alignability of FIT image subentries"""
Alper Nebi Yasakf3078d42022-02-08 01:08:07 +03003997 self._SetupSplElf()
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03003998 entry_args = {
3999 'test-id': TEXT_DATA,
4000 }
4001 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
4002 entry_args=entry_args)
4003 dtb = fdt.Fdt.FromData(data)
4004 dtb.Scan()
4005
4006 node = dtb.GetNode('/images/kernel')
4007 data = dtb.GetProps(node)["data"].bytes
4008 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
Simon Glassc1aa66e2022-01-29 14:14:04 -07004009 expected = (tools.get_bytes(0, 0x20) + U_BOOT_SPL_DATA +
4010 tools.get_bytes(0, align_pad) + U_BOOT_DATA)
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03004011 self.assertEqual(expected, data)
4012
4013 node = dtb.GetNode('/images/fdt-1')
4014 data = dtb.GetProps(node)["data"].bytes
Simon Glassc1aa66e2022-01-29 14:14:04 -07004015 expected = (U_BOOT_SPL_DTB_DATA + tools.get_bytes(0, 20) +
4016 tools.to_bytes(TEXT_DATA) + tools.get_bytes(0, 30) +
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03004017 U_BOOT_DTB_DATA)
4018 self.assertEqual(expected, data)
4019
4020 def testFitExtblobMissingOk(self):
4021 """Test a FIT with a missing external blob that is allowed"""
4022 with test_util.capture_sys_output() as (stdout, stderr):
4023 self._DoTestFile('168_fit_missing_blob.dts',
4024 allow_missing=True)
4025 err = stderr.getvalue()
Simon Glassb2381432020-09-06 10:39:09 -06004026 self.assertRegex(err, "Image 'main-section'.*missing.*: atf-bl31")
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03004027
Simon Glass3decfa32020-09-01 05:13:54 -06004028 def testBlobNamedByArgMissing(self):
4029 """Test handling of a missing entry arg"""
4030 with self.assertRaises(ValueError) as e:
4031 self._DoReadFile('068_blob_named_by_arg.dts')
4032 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
4033 str(e.exception))
4034
Simon Glassdc2f81a2020-09-01 05:13:58 -06004035 def testPackBl31(self):
4036 """Test that an image with an ATF BL31 binary can be created"""
4037 data = self._DoReadFile('169_atf_bl31.dts')
4038 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
4039
Samuel Holland18bd4552020-10-21 21:12:15 -05004040 def testPackScp(self):
4041 """Test that an image with an SCP binary can be created"""
4042 data = self._DoReadFile('172_scp.dts')
4043 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
4044
Simon Glass6cf99532020-09-01 05:13:59 -06004045 def testFitFdt(self):
4046 """Test an image with an FIT with multiple FDT images"""
4047 def _CheckFdt(seq, expected_data):
4048 """Check the FDT nodes
4049
4050 Args:
4051 seq: Sequence number to check (0 or 1)
4052 expected_data: Expected contents of 'data' property
4053 """
4054 name = 'fdt-%d' % seq
4055 fnode = dtb.GetNode('/images/%s' % name)
4056 self.assertIsNotNone(fnode)
4057 self.assertEqual({'description','type', 'compression', 'data'},
4058 set(fnode.props.keys()))
4059 self.assertEqual(expected_data, fnode.props['data'].bytes)
4060 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
4061 fnode.props['description'].value)
Jan Kiszkab2106612022-02-28 17:06:20 +01004062 self.assertEqual(fnode.subnodes[0].name, 'hash')
Simon Glass6cf99532020-09-01 05:13:59 -06004063
4064 def _CheckConfig(seq, expected_data):
4065 """Check the configuration nodes
4066
4067 Args:
4068 seq: Sequence number to check (0 or 1)
4069 expected_data: Expected contents of 'data' property
4070 """
4071 cnode = dtb.GetNode('/configurations')
4072 self.assertIn('default', cnode.props)
Simon Glassc0f1ebe2020-09-06 10:39:08 -06004073 self.assertEqual('config-2', cnode.props['default'].value)
Simon Glass6cf99532020-09-01 05:13:59 -06004074
4075 name = 'config-%d' % seq
4076 fnode = dtb.GetNode('/configurations/%s' % name)
4077 self.assertIsNotNone(fnode)
4078 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
4079 set(fnode.props.keys()))
4080 self.assertEqual('conf-test-fdt%d.dtb' % seq,
4081 fnode.props['description'].value)
4082 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
4083
4084 entry_args = {
4085 'of-list': 'test-fdt1 test-fdt2',
Simon Glassc0f1ebe2020-09-06 10:39:08 -06004086 'default-dt': 'test-fdt2',
Simon Glass6cf99532020-09-01 05:13:59 -06004087 }
4088 data = self._DoReadFileDtb(
Bin Mengaa75ce92021-05-10 20:23:32 +08004089 '170_fit_fdt.dts',
Simon Glass6cf99532020-09-01 05:13:59 -06004090 entry_args=entry_args,
4091 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4092 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4093 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4094
4095 dtb = fdt.Fdt.FromData(fit_data)
4096 dtb.Scan()
4097 fnode = dtb.GetNode('/images/kernel')
4098 self.assertIn('data', fnode.props)
4099
4100 # Check all the properties in fdt-1 and fdt-2
4101 _CheckFdt(1, TEST_FDT1_DATA)
4102 _CheckFdt(2, TEST_FDT2_DATA)
4103
4104 # Check configurations
4105 _CheckConfig(1, TEST_FDT1_DATA)
4106 _CheckConfig(2, TEST_FDT2_DATA)
4107
4108 def testFitFdtMissingList(self):
4109 """Test handling of a missing 'of-list' entry arg"""
4110 with self.assertRaises(ValueError) as e:
Bin Mengaa75ce92021-05-10 20:23:32 +08004111 self._DoReadFile('170_fit_fdt.dts')
Simon Glass6cf99532020-09-01 05:13:59 -06004112 self.assertIn("Generator node requires 'of-list' entry argument",
4113 str(e.exception))
4114
4115 def testFitFdtEmptyList(self):
4116 """Test handling of an empty 'of-list' entry arg"""
4117 entry_args = {
4118 'of-list': '',
4119 }
4120 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
4121
4122 def testFitFdtMissingProp(self):
4123 """Test handling of a missing 'fit,fdt-list' property"""
4124 with self.assertRaises(ValueError) as e:
4125 self._DoReadFile('171_fit_fdt_missing_prop.dts')
4126 self.assertIn("Generator node requires 'fit,fdt-list' property",
4127 str(e.exception))
Simon Glassdc2f81a2020-09-01 05:13:58 -06004128
Simon Glassc0f1ebe2020-09-06 10:39:08 -06004129 def testFitFdtMissing(self):
4130 """Test handling of a missing 'default-dt' entry arg"""
4131 entry_args = {
4132 'of-list': 'test-fdt1 test-fdt2',
4133 }
4134 with self.assertRaises(ValueError) as e:
4135 self._DoReadFileDtb(
Bin Mengaa75ce92021-05-10 20:23:32 +08004136 '170_fit_fdt.dts',
Simon Glassc0f1ebe2020-09-06 10:39:08 -06004137 entry_args=entry_args,
4138 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4139 self.assertIn("Generated 'default' node requires default-dt entry argument",
4140 str(e.exception))
4141
4142 def testFitFdtNotInList(self):
4143 """Test handling of a default-dt that is not in the of-list"""
4144 entry_args = {
4145 'of-list': 'test-fdt1 test-fdt2',
4146 'default-dt': 'test-fdt3',
4147 }
4148 with self.assertRaises(ValueError) as e:
4149 self._DoReadFileDtb(
Bin Mengaa75ce92021-05-10 20:23:32 +08004150 '170_fit_fdt.dts',
Simon Glassc0f1ebe2020-09-06 10:39:08 -06004151 entry_args=entry_args,
4152 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4153 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
4154 str(e.exception))
4155
Simon Glassb2381432020-09-06 10:39:09 -06004156 def testFitExtblobMissingHelp(self):
4157 """Test display of help messages when an external blob is missing"""
4158 control.missing_blob_help = control._ReadMissingBlobHelp()
4159 control.missing_blob_help['wibble'] = 'Wibble test'
4160 control.missing_blob_help['another'] = 'Another test'
4161 with test_util.capture_sys_output() as (stdout, stderr):
4162 self._DoTestFile('168_fit_missing_blob.dts',
4163 allow_missing=True)
4164 err = stderr.getvalue()
4165
4166 # We can get the tag from the name, the type or the missing-msg
4167 # property. Check all three.
4168 self.assertIn('You may need to build ARM Trusted', err)
4169 self.assertIn('Wibble test', err)
4170 self.assertIn('Another test', err)
4171
Simon Glass204aa782020-09-06 10:35:32 -06004172 def testMissingBlob(self):
4173 """Test handling of a blob containing a missing file"""
4174 with self.assertRaises(ValueError) as e:
4175 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
4176 self.assertIn("Filename 'missing' not found in input path",
4177 str(e.exception))
4178
Simon Glassfb91d562020-09-06 10:35:33 -06004179 def testEnvironment(self):
4180 """Test adding a U-Boot environment"""
4181 data = self._DoReadFile('174_env.dts')
4182 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
4183 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4184 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4185 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
4186 env)
4187
4188 def testEnvironmentNoSize(self):
4189 """Test that a missing 'size' property is detected"""
4190 with self.assertRaises(ValueError) as e:
Simon Glassa4dfe3e2020-10-26 17:40:00 -06004191 self._DoTestFile('175_env_no_size.dts')
Simon Glassfb91d562020-09-06 10:35:33 -06004192 self.assertIn("'u-boot-env' entry must have a size property",
4193 str(e.exception))
4194
4195 def testEnvironmentTooSmall(self):
4196 """Test handling of an environment that does not fit"""
4197 with self.assertRaises(ValueError) as e:
Simon Glassa4dfe3e2020-10-26 17:40:00 -06004198 self._DoTestFile('176_env_too_small.dts')
Simon Glassfb91d562020-09-06 10:35:33 -06004199
4200 # checksum, start byte, environment with \0 terminator, final \0
4201 need = 4 + 1 + len(ENV_DATA) + 1 + 1
4202 short = need - 0x8
4203 self.assertIn("too small to hold data (need %#x more bytes)" % short,
4204 str(e.exception))
4205
Simon Glassf2c0dd82020-10-26 17:40:01 -06004206 def testSkipAtStart(self):
4207 """Test handling of skip-at-start section"""
4208 data = self._DoReadFile('177_skip_at_start.dts')
4209 self.assertEqual(U_BOOT_DATA, data)
4210
4211 image = control.images['image']
4212 entries = image.GetEntries()
4213 section = entries['section']
4214 self.assertEqual(0, section.offset)
4215 self.assertEqual(len(U_BOOT_DATA), section.size)
4216 self.assertEqual(U_BOOT_DATA, section.GetData())
4217
4218 entry = section.GetEntries()['u-boot']
4219 self.assertEqual(16, entry.offset)
4220 self.assertEqual(len(U_BOOT_DATA), entry.size)
4221 self.assertEqual(U_BOOT_DATA, entry.data)
4222
4223 def testSkipAtStartPad(self):
4224 """Test handling of skip-at-start section with padded entry"""
4225 data = self._DoReadFile('178_skip_at_start_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004226 before = tools.get_bytes(0, 8)
4227 after = tools.get_bytes(0, 4)
Simon Glassf2c0dd82020-10-26 17:40:01 -06004228 all = before + U_BOOT_DATA + after
4229 self.assertEqual(all, data)
4230
4231 image = control.images['image']
4232 entries = image.GetEntries()
4233 section = entries['section']
4234 self.assertEqual(0, section.offset)
4235 self.assertEqual(len(all), section.size)
4236 self.assertEqual(all, section.GetData())
4237
4238 entry = section.GetEntries()['u-boot']
4239 self.assertEqual(16, entry.offset)
4240 self.assertEqual(len(all), entry.size)
4241 self.assertEqual(U_BOOT_DATA, entry.data)
4242
4243 def testSkipAtStartSectionPad(self):
4244 """Test handling of skip-at-start section with padding"""
4245 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004246 before = tools.get_bytes(0, 8)
4247 after = tools.get_bytes(0, 4)
Simon Glassf2c0dd82020-10-26 17:40:01 -06004248 all = before + U_BOOT_DATA + after
Simon Glassd1d3ad72020-10-26 17:40:13 -06004249 self.assertEqual(all, data)
Simon Glassf2c0dd82020-10-26 17:40:01 -06004250
4251 image = control.images['image']
4252 entries = image.GetEntries()
4253 section = entries['section']
4254 self.assertEqual(0, section.offset)
4255 self.assertEqual(len(all), section.size)
Simon Glass63e7ba62020-10-26 17:40:16 -06004256 self.assertEqual(U_BOOT_DATA, section.data)
Simon Glassd1d3ad72020-10-26 17:40:13 -06004257 self.assertEqual(all, section.GetPaddedData())
Simon Glassf2c0dd82020-10-26 17:40:01 -06004258
4259 entry = section.GetEntries()['u-boot']
4260 self.assertEqual(16, entry.offset)
4261 self.assertEqual(len(U_BOOT_DATA), entry.size)
4262 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassfb91d562020-09-06 10:35:33 -06004263
Simon Glass7d398bb2020-10-26 17:40:14 -06004264 def testSectionPad(self):
4265 """Testing padding with sections"""
4266 data = self._DoReadFile('180_section_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004267 expected = (tools.get_bytes(ord('&'), 3) +
4268 tools.get_bytes(ord('!'), 5) +
Simon Glass7d398bb2020-10-26 17:40:14 -06004269 U_BOOT_DATA +
Simon Glassc1aa66e2022-01-29 14:14:04 -07004270 tools.get_bytes(ord('!'), 1) +
4271 tools.get_bytes(ord('&'), 2))
Simon Glass7d398bb2020-10-26 17:40:14 -06004272 self.assertEqual(expected, data)
4273
4274 def testSectionAlign(self):
4275 """Testing alignment with sections"""
4276 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4277 expected = (b'\0' + # fill section
Simon Glassc1aa66e2022-01-29 14:14:04 -07004278 tools.get_bytes(ord('&'), 1) + # padding to section align
Simon Glass7d398bb2020-10-26 17:40:14 -06004279 b'\0' + # fill section
Simon Glassc1aa66e2022-01-29 14:14:04 -07004280 tools.get_bytes(ord('!'), 3) + # padding to u-boot align
Simon Glass7d398bb2020-10-26 17:40:14 -06004281 U_BOOT_DATA +
Simon Glassc1aa66e2022-01-29 14:14:04 -07004282 tools.get_bytes(ord('!'), 4) + # padding to u-boot size
4283 tools.get_bytes(ord('!'), 4)) # padding to section size
Simon Glass7d398bb2020-10-26 17:40:14 -06004284 self.assertEqual(expected, data)
4285
Simon Glass8f5ef892020-10-26 17:40:25 -06004286 def testCompressImage(self):
4287 """Test compression of the entire image"""
4288 self._CheckLz4()
4289 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4290 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4291 dtb = fdt.Fdt(out_dtb_fname)
4292 dtb.Scan()
4293 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4294 'uncomp-size'])
4295 orig = self._decompress(data)
4296 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4297
4298 # Do a sanity check on various fields
4299 image = control.images['image']
4300 entries = image.GetEntries()
4301 self.assertEqual(2, len(entries))
4302
4303 entry = entries['blob']
4304 self.assertEqual(COMPRESS_DATA, entry.data)
4305 self.assertEqual(len(COMPRESS_DATA), entry.size)
4306
4307 entry = entries['u-boot']
4308 self.assertEqual(U_BOOT_DATA, entry.data)
4309 self.assertEqual(len(U_BOOT_DATA), entry.size)
4310
4311 self.assertEqual(len(data), image.size)
4312 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4313 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4314 orig = self._decompress(image.data)
4315 self.assertEqual(orig, image.uncomp_data)
4316
4317 expected = {
4318 'blob:offset': 0,
4319 'blob:size': len(COMPRESS_DATA),
4320 'u-boot:offset': len(COMPRESS_DATA),
4321 'u-boot:size': len(U_BOOT_DATA),
4322 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4323 'offset': 0,
4324 'image-pos': 0,
4325 'size': len(data),
4326 }
4327 self.assertEqual(expected, props)
4328
4329 def testCompressImageLess(self):
4330 """Test compression where compression reduces the image size"""
4331 self._CheckLz4()
4332 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4333 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4334 dtb = fdt.Fdt(out_dtb_fname)
4335 dtb.Scan()
4336 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4337 'uncomp-size'])
4338 orig = self._decompress(data)
4339
4340 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
4341
4342 # Do a sanity check on various fields
4343 image = control.images['image']
4344 entries = image.GetEntries()
4345 self.assertEqual(2, len(entries))
4346
4347 entry = entries['blob']
4348 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4349 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4350
4351 entry = entries['u-boot']
4352 self.assertEqual(U_BOOT_DATA, entry.data)
4353 self.assertEqual(len(U_BOOT_DATA), entry.size)
4354
4355 self.assertEqual(len(data), image.size)
4356 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4357 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4358 image.uncomp_size)
4359 orig = self._decompress(image.data)
4360 self.assertEqual(orig, image.uncomp_data)
4361
4362 expected = {
4363 'blob:offset': 0,
4364 'blob:size': len(COMPRESS_DATA_BIG),
4365 'u-boot:offset': len(COMPRESS_DATA_BIG),
4366 'u-boot:size': len(U_BOOT_DATA),
4367 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4368 'offset': 0,
4369 'image-pos': 0,
4370 'size': len(data),
4371 }
4372 self.assertEqual(expected, props)
4373
4374 def testCompressSectionSize(self):
4375 """Test compression of a section with a fixed size"""
4376 self._CheckLz4()
4377 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4378 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4379 dtb = fdt.Fdt(out_dtb_fname)
4380 dtb.Scan()
4381 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4382 'uncomp-size'])
4383 orig = self._decompress(data)
4384 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4385 expected = {
4386 'section/blob:offset': 0,
4387 'section/blob:size': len(COMPRESS_DATA),
4388 'section/u-boot:offset': len(COMPRESS_DATA),
4389 'section/u-boot:size': len(U_BOOT_DATA),
4390 'section:offset': 0,
4391 'section:image-pos': 0,
4392 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4393 'section:size': 0x30,
4394 'offset': 0,
4395 'image-pos': 0,
4396 'size': 0x30,
4397 }
4398 self.assertEqual(expected, props)
4399
4400 def testCompressSection(self):
4401 """Test compression of a section with no fixed size"""
4402 self._CheckLz4()
4403 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4404 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4405 dtb = fdt.Fdt(out_dtb_fname)
4406 dtb.Scan()
4407 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4408 'uncomp-size'])
4409 orig = self._decompress(data)
4410 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4411 expected = {
4412 'section/blob:offset': 0,
4413 'section/blob:size': len(COMPRESS_DATA),
4414 'section/u-boot:offset': len(COMPRESS_DATA),
4415 'section/u-boot:size': len(U_BOOT_DATA),
4416 'section:offset': 0,
4417 'section:image-pos': 0,
4418 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4419 'section:size': len(data),
4420 'offset': 0,
4421 'image-pos': 0,
4422 'size': len(data),
4423 }
4424 self.assertEqual(expected, props)
4425
4426 def testCompressExtra(self):
4427 """Test compression of a section with no fixed size"""
4428 self._CheckLz4()
4429 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4430 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4431 dtb = fdt.Fdt(out_dtb_fname)
4432 dtb.Scan()
4433 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4434 'uncomp-size'])
4435
4436 base = data[len(U_BOOT_DATA):]
4437 self.assertEquals(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
4438 rest = base[len(U_BOOT_DATA):]
4439
4440 # Check compressed data
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +02004441 bintool = self.comp_bintools['lz4']
4442 expect1 = bintool.compress(COMPRESS_DATA + U_BOOT_DATA)
Stefan Herbrechtsmeierfa24f552022-08-19 16:25:23 +02004443 data1 = rest[:len(expect1)]
4444 section1 = self._decompress(data1)
4445 self.assertEquals(expect1, data1)
Simon Glass8f5ef892020-10-26 17:40:25 -06004446 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, section1)
4447 rest1 = rest[len(expect1):]
4448
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +02004449 expect2 = bintool.compress(COMPRESS_DATA + COMPRESS_DATA)
Stefan Herbrechtsmeierfa24f552022-08-19 16:25:23 +02004450 data2 = rest1[:len(expect2)]
4451 section2 = self._decompress(data2)
4452 self.assertEquals(expect2, data2)
Simon Glass8f5ef892020-10-26 17:40:25 -06004453 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA, section2)
4454 rest2 = rest1[len(expect2):]
4455
4456 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4457 len(expect2) + len(U_BOOT_DATA))
4458 #self.assertEquals(expect_size, len(data))
4459
4460 #self.assertEquals(U_BOOT_DATA, rest2)
4461
4462 self.maxDiff = None
4463 expected = {
4464 'u-boot:offset': 0,
4465 'u-boot:image-pos': 0,
4466 'u-boot:size': len(U_BOOT_DATA),
4467
4468 'base:offset': len(U_BOOT_DATA),
4469 'base:image-pos': len(U_BOOT_DATA),
4470 'base:size': len(data) - len(U_BOOT_DATA),
4471 'base/u-boot:offset': 0,
4472 'base/u-boot:image-pos': len(U_BOOT_DATA),
4473 'base/u-boot:size': len(U_BOOT_DATA),
4474 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4475 len(expect2),
4476 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4477 len(expect2),
4478 'base/u-boot2:size': len(U_BOOT_DATA),
4479
4480 'base/section:offset': len(U_BOOT_DATA),
4481 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4482 'base/section:size': len(expect1),
4483 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4484 'base/section/blob:offset': 0,
4485 'base/section/blob:size': len(COMPRESS_DATA),
4486 'base/section/u-boot:offset': len(COMPRESS_DATA),
4487 'base/section/u-boot:size': len(U_BOOT_DATA),
4488
4489 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4490 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4491 'base/section2:size': len(expect2),
4492 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4493 'base/section2/blob:offset': 0,
4494 'base/section2/blob:size': len(COMPRESS_DATA),
4495 'base/section2/blob2:offset': len(COMPRESS_DATA),
4496 'base/section2/blob2:size': len(COMPRESS_DATA),
4497
4498 'offset': 0,
4499 'image-pos': 0,
4500 'size': len(data),
4501 }
4502 self.assertEqual(expected, props)
4503
Simon Glass870a9ea2021-01-06 21:35:15 -07004504 def testSymbolsSubsection(self):
4505 """Test binman can assign symbols from a subsection"""
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03004506 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glass870a9ea2021-01-06 21:35:15 -07004507
Simon Glass939d1062021-01-06 21:35:16 -07004508 def testReadImageEntryArg(self):
4509 """Test reading an image that would need an entry arg to generate"""
4510 entry_args = {
4511 'cros-ec-rw-path': 'ecrw.bin',
4512 }
4513 data = self.data = self._DoReadFileDtb(
4514 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4515 entry_args=entry_args)
4516
Simon Glassc1aa66e2022-01-29 14:14:04 -07004517 image_fname = tools.get_output_filename('image.bin')
Simon Glass939d1062021-01-06 21:35:16 -07004518 orig_image = control.images['image']
4519
4520 # This should not generate an error about the missing 'cros-ec-rw-path'
4521 # since we are reading the image from a file. Compare with
4522 # testEntryArgsRequired()
4523 image = Image.FromFile(image_fname)
4524 self.assertEqual(orig_image.GetEntries().keys(),
4525 image.GetEntries().keys())
4526
Simon Glass6eb99322021-01-06 21:35:18 -07004527 def testFilesAlign(self):
4528 """Test alignment with files"""
4529 data = self._DoReadFile('190_files_align.dts')
4530
4531 # The first string is 15 bytes so will align to 16
4532 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4533 self.assertEqual(expect, data)
4534
Simon Glass5c6ba712021-01-06 21:35:19 -07004535 def testReadImageSkip(self):
4536 """Test reading an image and accessing its FDT map"""
4537 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004538 image_fname = tools.get_output_filename('image.bin')
Simon Glass5c6ba712021-01-06 21:35:19 -07004539 orig_image = control.images['image']
4540 image = Image.FromFile(image_fname)
4541 self.assertEqual(orig_image.GetEntries().keys(),
4542 image.GetEntries().keys())
4543
4544 orig_entry = orig_image.GetEntries()['fdtmap']
4545 entry = image.GetEntries()['fdtmap']
4546 self.assertEqual(orig_entry.offset, entry.offset)
4547 self.assertEqual(orig_entry.size, entry.size)
4548 self.assertEqual(16, entry.image_pos)
4549
4550 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4551
4552 self.assertEquals(U_BOOT_DATA, u_boot.ReadData())
4553
Simon Glass77a64e02021-03-18 20:24:57 +13004554 def testTplNoDtb(self):
4555 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
Simon Glass0fe44dc2021-04-25 08:39:32 +12004556 self._SetupTplElf()
Simon Glass77a64e02021-03-18 20:24:57 +13004557 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4558 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4559 data[:len(U_BOOT_TPL_NODTB_DATA)])
4560
Simon Glassd26efc82021-03-18 20:24:58 +13004561 def testTplBssPad(self):
4562 """Test that we can pad TPL's BSS with zeros"""
4563 # ELF file with a '__bss_size' symbol
4564 self._SetupTplElf()
4565 data = self._DoReadFile('193_tpl_bss_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004566 self.assertEqual(U_BOOT_TPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glassd26efc82021-03-18 20:24:58 +13004567 data)
4568
4569 def testTplBssPadMissing(self):
4570 """Test that a missing symbol is detected"""
4571 self._SetupTplElf('u_boot_ucode_ptr')
4572 with self.assertRaises(ValueError) as e:
4573 self._DoReadFile('193_tpl_bss_pad.dts')
4574 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4575 str(e.exception))
4576
Simon Glass06684922021-03-18 20:25:07 +13004577 def checkDtbSizes(self, data, pad_len, start):
4578 """Check the size arguments in a dtb embedded in an image
4579
4580 Args:
4581 data: The image data
4582 pad_len: Length of the pad section in the image, in bytes
4583 start: Start offset of the devicetree to examine, within the image
4584
4585 Returns:
4586 Size of the devicetree in bytes
4587 """
4588 dtb_data = data[start:]
4589 dtb = fdt.Fdt.FromData(dtb_data)
4590 fdt_size = dtb.GetFdtObj().totalsize()
4591 dtb.Scan()
4592 props = self._GetPropTree(dtb, 'size')
4593 self.assertEqual({
4594 'size': len(data),
4595 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4596 'u-boot-spl/u-boot-spl-dtb:size': 801,
4597 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4598 'u-boot-spl:size': 860,
4599 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4600 'u-boot/u-boot-dtb:size': 781,
4601 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4602 'u-boot:size': 827,
4603 }, props)
4604 return fdt_size
4605
4606 def testExpanded(self):
4607 """Test that an expanded entry type is selected when needed"""
4608 self._SetupSplElf()
4609 self._SetupTplElf()
4610
4611 # SPL has a devicetree, TPL does not
4612 entry_args = {
4613 'spl-dtb': '1',
4614 'spl-bss-pad': 'y',
4615 'tpl-dtb': '',
4616 }
4617 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4618 entry_args=entry_args)
4619 image = control.images['image']
4620 entries = image.GetEntries()
4621 self.assertEqual(3, len(entries))
4622
4623 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4624 self.assertIn('u-boot', entries)
4625 entry = entries['u-boot']
4626 self.assertEqual('u-boot-expanded', entry.etype)
4627 subent = entry.GetEntries()
4628 self.assertEqual(2, len(subent))
4629 self.assertIn('u-boot-nodtb', subent)
4630 self.assertIn('u-boot-dtb', subent)
4631
4632 # Second, u-boot-spl, which should be expanded into three parts
4633 self.assertIn('u-boot-spl', entries)
4634 entry = entries['u-boot-spl']
4635 self.assertEqual('u-boot-spl-expanded', entry.etype)
4636 subent = entry.GetEntries()
4637 self.assertEqual(3, len(subent))
4638 self.assertIn('u-boot-spl-nodtb', subent)
4639 self.assertIn('u-boot-spl-bss-pad', subent)
4640 self.assertIn('u-boot-spl-dtb', subent)
4641
4642 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4643 # devicetree
4644 self.assertIn('u-boot-tpl', entries)
4645 entry = entries['u-boot-tpl']
4646 self.assertEqual('u-boot-tpl', entry.etype)
4647 self.assertEqual(None, entry.GetEntries())
4648
4649 def testExpandedTpl(self):
4650 """Test that an expanded entry type is selected for TPL when needed"""
4651 self._SetupTplElf()
4652
4653 entry_args = {
4654 'tpl-bss-pad': 'y',
4655 'tpl-dtb': 'y',
4656 }
4657 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4658 entry_args=entry_args)
4659 image = control.images['image']
4660 entries = image.GetEntries()
4661 self.assertEqual(1, len(entries))
4662
4663 # We only have u-boot-tpl, which be expanded
4664 self.assertIn('u-boot-tpl', entries)
4665 entry = entries['u-boot-tpl']
4666 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4667 subent = entry.GetEntries()
4668 self.assertEqual(3, len(subent))
4669 self.assertIn('u-boot-tpl-nodtb', subent)
4670 self.assertIn('u-boot-tpl-bss-pad', subent)
4671 self.assertIn('u-boot-tpl-dtb', subent)
4672
4673 def testExpandedNoPad(self):
4674 """Test an expanded entry without BSS pad enabled"""
4675 self._SetupSplElf()
4676 self._SetupTplElf()
4677
4678 # SPL has a devicetree, TPL does not
4679 entry_args = {
4680 'spl-dtb': 'something',
4681 'spl-bss-pad': 'n',
4682 'tpl-dtb': '',
4683 }
4684 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4685 entry_args=entry_args)
4686 image = control.images['image']
4687 entries = image.GetEntries()
4688
4689 # Just check u-boot-spl, which should be expanded into two parts
4690 self.assertIn('u-boot-spl', entries)
4691 entry = entries['u-boot-spl']
4692 self.assertEqual('u-boot-spl-expanded', entry.etype)
4693 subent = entry.GetEntries()
4694 self.assertEqual(2, len(subent))
4695 self.assertIn('u-boot-spl-nodtb', subent)
4696 self.assertIn('u-boot-spl-dtb', subent)
4697
4698 def testExpandedTplNoPad(self):
4699 """Test that an expanded entry type with padding disabled in TPL"""
4700 self._SetupTplElf()
4701
4702 entry_args = {
4703 'tpl-bss-pad': '',
4704 'tpl-dtb': 'y',
4705 }
4706 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4707 entry_args=entry_args)
4708 image = control.images['image']
4709 entries = image.GetEntries()
4710 self.assertEqual(1, len(entries))
4711
4712 # We only have u-boot-tpl, which be expanded
4713 self.assertIn('u-boot-tpl', entries)
4714 entry = entries['u-boot-tpl']
4715 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4716 subent = entry.GetEntries()
4717 self.assertEqual(2, len(subent))
4718 self.assertIn('u-boot-tpl-nodtb', subent)
4719 self.assertIn('u-boot-tpl-dtb', subent)
4720
4721 def testFdtInclude(self):
4722 """Test that an Fdt is update within all binaries"""
4723 self._SetupSplElf()
4724 self._SetupTplElf()
4725
4726 # SPL has a devicetree, TPL does not
4727 self.maxDiff = None
4728 entry_args = {
4729 'spl-dtb': '1',
4730 'spl-bss-pad': 'y',
4731 'tpl-dtb': '',
4732 }
4733 # Build the image. It includes two separate devicetree binaries, each
4734 # with their own contents, but all contain the binman definition.
4735 data = self._DoReadFileDtb(
4736 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4737 update_dtb=True, entry_args=entry_args)[0]
4738 pad_len = 10
4739
4740 # Check the U-Boot dtb
4741 start = len(U_BOOT_NODTB_DATA)
4742 fdt_size = self.checkDtbSizes(data, pad_len, start)
4743
4744 # Now check SPL
4745 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4746 fdt_size = self.checkDtbSizes(data, pad_len, start)
4747
4748 # TPL has no devicetree
4749 start += fdt_size + len(U_BOOT_TPL_DATA)
4750 self.assertEqual(len(data), start)
Simon Glass7d398bb2020-10-26 17:40:14 -06004751
Simon Glass3d433382021-03-21 18:24:30 +13004752 def testSymbolsExpanded(self):
4753 """Test binman can assign symbols in expanded entries"""
4754 entry_args = {
4755 'spl-dtb': '1',
4756 }
4757 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4758 U_BOOT_SPL_DTB_DATA, 0x38,
4759 entry_args=entry_args, use_expanded=True)
4760
Simon Glass189f2912021-03-21 18:24:31 +13004761 def testCollection(self):
4762 """Test a collection"""
4763 data = self._DoReadFile('198_collection.dts')
4764 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
Simon Glassc1aa66e2022-01-29 14:14:04 -07004765 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
4766 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
Simon Glass189f2912021-03-21 18:24:31 +13004767 data)
4768
Simon Glass631f7522021-03-21 18:24:32 +13004769 def testCollectionSection(self):
4770 """Test a collection where a section must be built first"""
4771 # Sections never have their contents when GetData() is called, but when
Simon Glassd34bcdd2021-11-23 11:03:47 -07004772 # BuildSectionData() is called with required=True, a section will force
Simon Glass631f7522021-03-21 18:24:32 +13004773 # building the contents, producing an error is anything is still
4774 # missing.
4775 data = self._DoReadFile('199_collection_section.dts')
4776 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
Simon Glassc1aa66e2022-01-29 14:14:04 -07004777 self.assertEqual(section + U_BOOT_DATA + tools.get_bytes(0xff, 2) +
4778 section + tools.get_bytes(0xfe, 3) + U_BOOT_DATA,
Simon Glass631f7522021-03-21 18:24:32 +13004779 data)
4780
Simon Glass5ff9fed2021-03-21 18:24:33 +13004781 def testAlignDefault(self):
4782 """Test that default alignment works on sections"""
4783 data = self._DoReadFile('200_align_default.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004784 expected = (U_BOOT_DATA + tools.get_bytes(0, 8 - len(U_BOOT_DATA)) +
Simon Glass5ff9fed2021-03-21 18:24:33 +13004785 U_BOOT_DATA)
4786 # Special alignment for section
Simon Glassc1aa66e2022-01-29 14:14:04 -07004787 expected += tools.get_bytes(0, 32 - len(expected))
Simon Glass5ff9fed2021-03-21 18:24:33 +13004788 # No alignment within the nested section
4789 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
4790 # Now the final piece, which should be default-aligned
Simon Glassc1aa66e2022-01-29 14:14:04 -07004791 expected += tools.get_bytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
Simon Glass5ff9fed2021-03-21 18:24:33 +13004792 self.assertEqual(expected, data)
Simon Glass631f7522021-03-21 18:24:32 +13004793
Bin Meng4c4d6072021-05-10 20:23:33 +08004794 def testPackOpenSBI(self):
4795 """Test that an image with an OpenSBI binary can be created"""
4796 data = self._DoReadFile('201_opensbi.dts')
4797 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
4798
Simon Glassc69d19c2021-07-06 10:36:37 -06004799 def testSectionsSingleThread(self):
4800 """Test sections without multithreading"""
4801 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
Simon Glassc1aa66e2022-01-29 14:14:04 -07004802 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4803 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
4804 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glassc69d19c2021-07-06 10:36:37 -06004805 self.assertEqual(expected, data)
4806
4807 def testThreadTimeout(self):
4808 """Test handling a thread that takes too long"""
4809 with self.assertRaises(ValueError) as e:
4810 self._DoTestFile('202_section_timeout.dts',
4811 test_section_timeout=True)
Simon Glassb2dfe832021-10-18 12:13:15 -06004812 self.assertIn("Timed out obtaining contents", str(e.exception))
Simon Glassc69d19c2021-07-06 10:36:37 -06004813
Simon Glass03ebc202021-07-06 10:36:41 -06004814 def testTiming(self):
4815 """Test output of timing information"""
4816 data = self._DoReadFile('055_sections.dts')
4817 with test_util.capture_sys_output() as (stdout, stderr):
4818 state.TimingShow()
4819 self.assertIn('read:', stdout.getvalue())
4820 self.assertIn('compress:', stdout.getvalue())
4821
Simon Glass0427bed2021-11-03 21:09:18 -06004822 def testUpdateFdtInElf(self):
4823 """Test that we can update the devicetree in an ELF file"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02004824 if not elf.ELF_TOOLS:
4825 self.skipTest('Python elftools not available')
Simon Glass0427bed2021-11-03 21:09:18 -06004826 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4827 outfile = os.path.join(self._indir, 'u-boot.out')
4828 begin_sym = 'dtb_embed_begin'
4829 end_sym = 'dtb_embed_end'
4830 retcode = self._DoTestFile(
4831 '060_fdt_update.dts', update_dtb=True,
4832 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4833 self.assertEqual(0, retcode)
4834
4835 # Check that the output file does in fact contact a dtb with the binman
4836 # definition in the correct place
4837 syms = elf.GetSymbolFileOffset(infile,
4838 ['dtb_embed_begin', 'dtb_embed_end'])
Simon Glassc1aa66e2022-01-29 14:14:04 -07004839 data = tools.read_file(outfile)
Simon Glass0427bed2021-11-03 21:09:18 -06004840 dtb_data = data[syms['dtb_embed_begin'].offset:
4841 syms['dtb_embed_end'].offset]
4842
4843 dtb = fdt.Fdt.FromData(dtb_data)
4844 dtb.Scan()
4845 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4846 self.assertEqual({
4847 'image-pos': 0,
4848 'offset': 0,
4849 '_testing:offset': 32,
4850 '_testing:size': 2,
4851 '_testing:image-pos': 32,
4852 'section@0/u-boot:offset': 0,
4853 'section@0/u-boot:size': len(U_BOOT_DATA),
4854 'section@0/u-boot:image-pos': 0,
4855 'section@0:offset': 0,
4856 'section@0:size': 16,
4857 'section@0:image-pos': 0,
4858
4859 'section@1/u-boot:offset': 0,
4860 'section@1/u-boot:size': len(U_BOOT_DATA),
4861 'section@1/u-boot:image-pos': 16,
4862 'section@1:offset': 16,
4863 'section@1:size': 16,
4864 'section@1:image-pos': 16,
4865 'size': 40
4866 }, props)
4867
4868 def testUpdateFdtInElfInvalid(self):
4869 """Test that invalid args are detected with --update-fdt-in-elf"""
4870 with self.assertRaises(ValueError) as e:
4871 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
4872 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
4873 str(e.exception))
4874
4875 def testUpdateFdtInElfNoSyms(self):
4876 """Test that missing symbols are detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02004877 if not elf.ELF_TOOLS:
4878 self.skipTest('Python elftools not available')
Simon Glass0427bed2021-11-03 21:09:18 -06004879 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4880 outfile = ''
4881 begin_sym = 'wrong_begin'
4882 end_sym = 'wrong_end'
4883 with self.assertRaises(ValueError) as e:
4884 self._DoTestFile(
4885 '060_fdt_update.dts',
4886 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4887 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
4888 str(e.exception))
4889
4890 def testUpdateFdtInElfTooSmall(self):
4891 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02004892 if not elf.ELF_TOOLS:
4893 self.skipTest('Python elftools not available')
Simon Glass0427bed2021-11-03 21:09:18 -06004894 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
4895 outfile = os.path.join(self._indir, 'u-boot.out')
4896 begin_sym = 'dtb_embed_begin'
4897 end_sym = 'dtb_embed_end'
4898 with self.assertRaises(ValueError) as e:
4899 self._DoTestFile(
4900 '060_fdt_update.dts', update_dtb=True,
4901 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4902 self.assertRegex(
4903 str(e.exception),
4904 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
4905
Simon Glassc475dec2021-11-23 11:03:42 -07004906 def testVersion(self):
4907 """Test we can get the binman version"""
4908 version = '(unreleased)'
4909 self.assertEqual(version, state.GetVersion(self._indir))
4910
4911 with self.assertRaises(SystemExit):
4912 with test_util.capture_sys_output() as (_, stderr):
4913 self._DoBinman('-V')
4914 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
4915
4916 # Try running the tool too, just to be safe
4917 result = self._RunBinman('-V')
4918 self.assertEqual('Binman %s\n' % version, result.stderr)
4919
4920 # Set up a version file to make sure that works
4921 version = 'v2025.01-rc2'
Simon Glassc1aa66e2022-01-29 14:14:04 -07004922 tools.write_file(os.path.join(self._indir, 'version'), version,
Simon Glassc475dec2021-11-23 11:03:42 -07004923 binary=False)
4924 self.assertEqual(version, state.GetVersion(self._indir))
4925
Simon Glass943bf782021-11-23 21:09:50 -07004926 def testAltFormat(self):
4927 """Test that alternative formats can be used to extract"""
4928 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
4929
4930 try:
4931 tmpdir, updated_fname = self._SetupImageInTmpdir()
4932 with test_util.capture_sys_output() as (stdout, _):
4933 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
4934 self.assertEqual(
4935 '''Flag (-F) Entry type Description
4936fdt fdtmap Extract the devicetree blob from the fdtmap
4937''',
4938 stdout.getvalue())
4939
4940 dtb = os.path.join(tmpdir, 'fdt.dtb')
4941 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
4942 dtb, 'fdtmap')
4943
4944 # Check that we can read it and it can be scanning, meaning it does
4945 # not have a 16-byte fdtmap header
Simon Glassc1aa66e2022-01-29 14:14:04 -07004946 data = tools.read_file(dtb)
Simon Glass943bf782021-11-23 21:09:50 -07004947 dtb = fdt.Fdt.FromData(data)
4948 dtb.Scan()
4949
4950 # Now check u-boot which has no alt_format
4951 fname = os.path.join(tmpdir, 'fdt.dtb')
4952 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
4953 '-f', fname, 'u-boot')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004954 data = tools.read_file(fname)
Simon Glass943bf782021-11-23 21:09:50 -07004955 self.assertEqual(U_BOOT_DATA, data)
4956
4957 finally:
4958 shutil.rmtree(tmpdir)
4959
Simon Glasscc2c5002021-11-23 21:09:52 -07004960 def testExtblobList(self):
4961 """Test an image with an external blob list"""
4962 data = self._DoReadFile('215_blob_ext_list.dts')
4963 self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
4964
4965 def testExtblobListMissing(self):
4966 """Test an image with a missing external blob"""
4967 with self.assertRaises(ValueError) as e:
4968 self._DoReadFile('216_blob_ext_list_missing.dts')
4969 self.assertIn("Filename 'missing-file' not found in input path",
4970 str(e.exception))
4971
4972 def testExtblobListMissingOk(self):
4973 """Test an image with an missing external blob that is allowed"""
4974 with test_util.capture_sys_output() as (stdout, stderr):
4975 self._DoTestFile('216_blob_ext_list_missing.dts',
4976 allow_missing=True)
4977 err = stderr.getvalue()
4978 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
4979
Simon Glass75989722021-11-23 21:08:59 -07004980 def testFip(self):
4981 """Basic test of generation of an ARM Firmware Image Package (FIP)"""
4982 data = self._DoReadFile('203_fip.dts')
4983 hdr, fents = fip_util.decode_fip(data)
4984 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
4985 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
4986 self.assertEqual(0x123, hdr.flags)
4987
4988 self.assertEqual(2, len(fents))
4989
4990 fent = fents[0]
4991 self.assertEqual(
4992 bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
4993 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
4994 self.assertEqual('soc-fw', fent.fip_type)
4995 self.assertEqual(0x88, fent.offset)
4996 self.assertEqual(len(ATF_BL31_DATA), fent.size)
4997 self.assertEqual(0x123456789abcdef, fent.flags)
4998 self.assertEqual(ATF_BL31_DATA, fent.data)
4999 self.assertEqual(True, fent.valid)
5000
5001 fent = fents[1]
5002 self.assertEqual(
5003 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
5004 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
5005 self.assertEqual('scp-fwu-cfg', fent.fip_type)
5006 self.assertEqual(0x8c, fent.offset)
5007 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5008 self.assertEqual(0, fent.flags)
5009 self.assertEqual(ATF_BL2U_DATA, fent.data)
5010 self.assertEqual(True, fent.valid)
5011
5012 def testFipOther(self):
5013 """Basic FIP with something that isn't a external blob"""
5014 data = self._DoReadFile('204_fip_other.dts')
5015 hdr, fents = fip_util.decode_fip(data)
5016
5017 self.assertEqual(2, len(fents))
5018 fent = fents[1]
5019 self.assertEqual('rot-cert', fent.fip_type)
5020 self.assertEqual(b'aa', fent.data)
5021
Simon Glass75989722021-11-23 21:08:59 -07005022 def testFipNoType(self):
5023 """FIP with an entry of an unknown type"""
5024 with self.assertRaises(ValueError) as e:
5025 self._DoReadFile('205_fip_no_type.dts')
5026 self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
5027 str(e.exception))
5028
5029 def testFipUuid(self):
5030 """Basic FIP with a manual uuid"""
5031 data = self._DoReadFile('206_fip_uuid.dts')
5032 hdr, fents = fip_util.decode_fip(data)
5033
5034 self.assertEqual(2, len(fents))
5035 fent = fents[1]
5036 self.assertEqual(None, fent.fip_type)
5037 self.assertEqual(
5038 bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
5039 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
5040 fent.uuid)
5041 self.assertEqual(U_BOOT_DATA, fent.data)
5042
5043 def testFipLs(self):
5044 """Test listing a FIP"""
5045 data = self._DoReadFileRealDtb('207_fip_ls.dts')
5046 hdr, fents = fip_util.decode_fip(data)
5047
5048 try:
5049 tmpdir, updated_fname = self._SetupImageInTmpdir()
5050 with test_util.capture_sys_output() as (stdout, stderr):
5051 self._DoBinman('ls', '-i', updated_fname)
5052 finally:
5053 shutil.rmtree(tmpdir)
5054 lines = stdout.getvalue().splitlines()
5055 expected = [
5056'Name Image-pos Size Entry-type Offset Uncomp-size',
5057'----------------------------------------------------------------',
5058'main-section 0 2d3 section 0',
5059' atf-fip 0 90 atf-fip 0',
5060' soc-fw 88 4 blob-ext 88',
5061' u-boot 8c 4 u-boot 8c',
5062' fdtmap 90 243 fdtmap 90',
5063]
5064 self.assertEqual(expected, lines)
5065
5066 image = control.images['image']
5067 entries = image.GetEntries()
5068 fdtmap = entries['fdtmap']
5069
5070 fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
5071 magic = fdtmap_data[:8]
5072 self.assertEqual(b'_FDTMAP_', magic)
Simon Glassc1aa66e2022-01-29 14:14:04 -07005073 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass75989722021-11-23 21:08:59 -07005074
5075 fdt_data = fdtmap_data[16:]
5076 dtb = fdt.Fdt.FromData(fdt_data)
5077 dtb.Scan()
5078 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
5079 self.assertEqual({
5080 'atf-fip/soc-fw:image-pos': 136,
5081 'atf-fip/soc-fw:offset': 136,
5082 'atf-fip/soc-fw:size': 4,
5083 'atf-fip/u-boot:image-pos': 140,
5084 'atf-fip/u-boot:offset': 140,
5085 'atf-fip/u-boot:size': 4,
5086 'atf-fip:image-pos': 0,
5087 'atf-fip:offset': 0,
5088 'atf-fip:size': 144,
5089 'image-pos': 0,
5090 'offset': 0,
5091 'fdtmap:image-pos': fdtmap.image_pos,
5092 'fdtmap:offset': fdtmap.offset,
5093 'fdtmap:size': len(fdtmap_data),
5094 'size': len(data),
5095 }, props)
5096
5097 def testFipExtractOneEntry(self):
5098 """Test extracting a single entry fron an FIP"""
5099 self._DoReadFileRealDtb('207_fip_ls.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07005100 image_fname = tools.get_output_filename('image.bin')
Simon Glass75989722021-11-23 21:08:59 -07005101 fname = os.path.join(self._indir, 'output.extact')
5102 control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
Simon Glassc1aa66e2022-01-29 14:14:04 -07005103 data = tools.read_file(fname)
Simon Glass75989722021-11-23 21:08:59 -07005104 self.assertEqual(U_BOOT_DATA, data)
5105
5106 def testFipReplace(self):
5107 """Test replacing a single file in a FIP"""
Simon Glassc1aa66e2022-01-29 14:14:04 -07005108 expected = U_BOOT_DATA + tools.get_bytes(0x78, 50)
Simon Glass75989722021-11-23 21:08:59 -07005109 data = self._DoReadFileRealDtb('208_fip_replace.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07005110 updated_fname = tools.get_output_filename('image-updated.bin')
5111 tools.write_file(updated_fname, data)
Simon Glass75989722021-11-23 21:08:59 -07005112 entry_name = 'atf-fip/u-boot'
5113 control.WriteEntry(updated_fname, entry_name, expected,
5114 allow_resize=True)
5115 actual = control.ReadEntry(updated_fname, entry_name)
5116 self.assertEqual(expected, actual)
5117
Simon Glassc1aa66e2022-01-29 14:14:04 -07005118 new_data = tools.read_file(updated_fname)
Simon Glass75989722021-11-23 21:08:59 -07005119 hdr, fents = fip_util.decode_fip(new_data)
5120
5121 self.assertEqual(2, len(fents))
5122
5123 # Check that the FIP entry is updated
5124 fent = fents[1]
5125 self.assertEqual(0x8c, fent.offset)
5126 self.assertEqual(len(expected), fent.size)
5127 self.assertEqual(0, fent.flags)
5128 self.assertEqual(expected, fent.data)
5129 self.assertEqual(True, fent.valid)
5130
5131 def testFipMissing(self):
5132 with test_util.capture_sys_output() as (stdout, stderr):
5133 self._DoTestFile('209_fip_missing.dts', allow_missing=True)
5134 err = stderr.getvalue()
5135 self.assertRegex(err, "Image 'main-section'.*missing.*: rmm-fw")
5136
5137 def testFipSize(self):
5138 """Test a FIP with a size property"""
5139 data = self._DoReadFile('210_fip_size.dts')
5140 self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
5141 hdr, fents = fip_util.decode_fip(data)
5142 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5143 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5144
5145 self.assertEqual(1, len(fents))
5146
5147 fent = fents[0]
5148 self.assertEqual('soc-fw', fent.fip_type)
5149 self.assertEqual(0x60, fent.offset)
5150 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5151 self.assertEqual(ATF_BL31_DATA, fent.data)
5152 self.assertEqual(True, fent.valid)
5153
5154 rest = data[0x60 + len(ATF_BL31_DATA):0x100]
Simon Glassc1aa66e2022-01-29 14:14:04 -07005155 self.assertEqual(tools.get_bytes(0xff, len(rest)), rest)
Simon Glass75989722021-11-23 21:08:59 -07005156
5157 def testFipBadAlign(self):
5158 """Test that an invalid alignment value in a FIP is detected"""
5159 with self.assertRaises(ValueError) as e:
5160 self._DoTestFile('211_fip_bad_align.dts')
5161 self.assertIn(
5162 "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
5163 str(e.exception))
5164
5165 def testFipCollection(self):
5166 """Test using a FIP in a collection"""
5167 data = self._DoReadFile('212_fip_collection.dts')
5168 entry1 = control.images['image'].GetEntries()['collection']
5169 data1 = data[:entry1.size]
5170 hdr1, fents2 = fip_util.decode_fip(data1)
5171
5172 entry2 = control.images['image'].GetEntries()['atf-fip']
5173 data2 = data[entry2.offset:entry2.offset + entry2.size]
5174 hdr1, fents2 = fip_util.decode_fip(data2)
5175
5176 # The 'collection' entry should have U-Boot included at the end
5177 self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
5178 self.assertEqual(data1, data2 + U_BOOT_DATA)
5179 self.assertEqual(U_BOOT_DATA, data1[-4:])
5180
5181 # There should be a U-Boot after the final FIP
5182 self.assertEqual(U_BOOT_DATA, data[-4:])
Simon Glassc69d19c2021-07-06 10:36:37 -06005183
Simon Glass32d4f102022-01-12 13:10:35 -07005184 def testFakeBlob(self):
5185 """Test handling of faking an external blob"""
5186 with test_util.capture_sys_output() as (stdout, stderr):
5187 self._DoTestFile('217_fake_blob.dts', allow_missing=True,
5188 allow_fake_blobs=True)
5189 err = stderr.getvalue()
5190 self.assertRegex(
5191 err,
5192 "Image '.*' has faked external blobs and is non-functional: .*")
Simon Glass32d4f102022-01-12 13:10:35 -07005193
Simon Glassf4590e02022-01-09 20:13:46 -07005194 def testExtblobListFaked(self):
5195 """Test an extblob with missing external blob that are faked"""
5196 with test_util.capture_sys_output() as (stdout, stderr):
5197 self._DoTestFile('216_blob_ext_list_missing.dts',
5198 allow_fake_blobs=True)
5199 err = stderr.getvalue()
5200 self.assertRegex(err, "Image 'main-section'.*faked.*: blob-ext-list")
5201
Simon Glass56ee85e2022-01-09 20:13:57 -07005202 def testListBintools(self):
5203 args = ['tool', '--list']
5204 with test_util.capture_sys_output() as (stdout, _):
5205 self._DoBinman(*args)
5206 out = stdout.getvalue().splitlines()
5207 self.assertTrue(len(out) >= 2)
5208
5209 def testFetchBintools(self):
5210 def fail_download(url):
Simon Glassc1aa66e2022-01-29 14:14:04 -07005211 """Take the tools.download() function by raising an exception"""
Simon Glass56ee85e2022-01-09 20:13:57 -07005212 raise urllib.error.URLError('my error')
5213
5214 args = ['tool']
5215 with self.assertRaises(ValueError) as e:
5216 self._DoBinman(*args)
5217 self.assertIn("Invalid arguments to 'tool' subcommand",
5218 str(e.exception))
5219
5220 args = ['tool', '--fetch']
5221 with self.assertRaises(ValueError) as e:
5222 self._DoBinman(*args)
5223 self.assertIn('Please specify bintools to fetch', str(e.exception))
5224
5225 args = ['tool', '--fetch', '_testing']
Simon Glassc1aa66e2022-01-29 14:14:04 -07005226 with unittest.mock.patch.object(tools, 'download',
Simon Glass56ee85e2022-01-09 20:13:57 -07005227 side_effect=fail_download):
5228 with test_util.capture_sys_output() as (stdout, _):
5229 self._DoBinman(*args)
5230 self.assertIn('failed to fetch with all methods', stdout.getvalue())
5231
Simon Glassa00d9712022-01-09 20:14:10 -07005232 def testInvalidCompress(self):
5233 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier4f463e32022-08-19 16:25:27 +02005234 comp_util.compress(b'', 'invalid')
Simon Glassa00d9712022-01-09 20:14:10 -07005235 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
5236
5237 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier4f463e32022-08-19 16:25:27 +02005238 comp_util.decompress(b'1234', 'invalid')
Simon Glassa00d9712022-01-09 20:14:10 -07005239 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
5240
Simon Glassbc570642022-01-09 20:14:11 -07005241 def testBintoolDocs(self):
5242 """Test for creation of bintool documentation"""
5243 with test_util.capture_sys_output() as (stdout, stderr):
5244 control.write_bintool_docs(control.bintool.Bintool.get_tool_list())
5245 self.assertTrue(len(stdout.getvalue()) > 0)
5246
5247 def testBintoolDocsMissing(self):
5248 """Test handling of missing bintool documentation"""
5249 with self.assertRaises(ValueError) as e:
5250 with test_util.capture_sys_output() as (stdout, stderr):
5251 control.write_bintool_docs(
5252 control.bintool.Bintool.get_tool_list(), 'mkimage')
5253 self.assertIn('Documentation is missing for modules: mkimage',
5254 str(e.exception))
5255
Jan Kiszkafcc87ef2022-01-28 20:37:53 +01005256 def testListWithGenNode(self):
5257 """Check handling of an FDT map when the section cannot be found"""
5258 entry_args = {
5259 'of-list': 'test-fdt1 test-fdt2',
5260 }
5261 data = self._DoReadFileDtb(
5262 '219_fit_gennode.dts',
5263 entry_args=entry_args,
5264 use_real_dtb=True,
5265 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])
5266
5267 try:
5268 tmpdir, updated_fname = self._SetupImageInTmpdir()
5269 with test_util.capture_sys_output() as (stdout, stderr):
5270 self._RunBinman('ls', '-i', updated_fname)
5271 finally:
5272 shutil.rmtree(tmpdir)
5273
Alper Nebi Yasaked293c32022-02-08 01:08:05 +03005274 def testFitSubentryUsesBintool(self):
5275 """Test that binman FIT subentries can use bintools"""
5276 command.test_result = self._HandleGbbCommand
5277 entry_args = {
5278 'keydir': 'devkeys',
5279 'bmpblk': 'bmpblk.bin',
5280 }
5281 data, _, _, _ = self._DoReadFileDtb('220_fit_subentry_bintool.dts',
5282 entry_args=entry_args)
5283
Alper Nebi Yasakf3078d42022-02-08 01:08:07 +03005284 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
5285 tools.get_bytes(0, 0x2180 - 16))
Alper Nebi Yasaked293c32022-02-08 01:08:05 +03005286 self.assertIn(expected, data)
5287
5288 def testFitSubentryMissingBintool(self):
5289 """Test that binman reports missing bintools for FIT subentries"""
5290 entry_args = {
5291 'keydir': 'devkeys',
5292 }
5293 with test_util.capture_sys_output() as (_, stderr):
5294 self._DoTestFile('220_fit_subentry_bintool.dts',
5295 force_missing_bintools='futility', entry_args=entry_args)
5296 err = stderr.getvalue()
5297 self.assertRegex(err,
5298 "Image 'main-section'.*missing bintools.*: futility")
Simon Glass32d4f102022-01-12 13:10:35 -07005299
Alper Nebi Yasakee813c82022-02-09 22:02:35 +03005300 def testFitSubentryHashSubnode(self):
5301 """Test an image with a FIT inside"""
5302 data, _, _, out_dtb_name = self._DoReadFileDtb(
5303 '221_fit_subentry_hash.dts', use_real_dtb=True, update_dtb=True)
5304
5305 mkimage_dtb = fdt.Fdt.FromData(data)
5306 mkimage_dtb.Scan()
5307 binman_dtb = fdt.Fdt(out_dtb_name)
5308 binman_dtb.Scan()
5309
5310 # Check that binman didn't add hash values
5311 fnode = binman_dtb.GetNode('/binman/fit/images/kernel/hash')
5312 self.assertNotIn('value', fnode.props)
5313
5314 fnode = binman_dtb.GetNode('/binman/fit/images/fdt-1/hash')
5315 self.assertNotIn('value', fnode.props)
5316
5317 # Check that mkimage added hash values
5318 fnode = mkimage_dtb.GetNode('/images/kernel/hash')
5319 self.assertIn('value', fnode.props)
5320
5321 fnode = mkimage_dtb.GetNode('/images/fdt-1/hash')
5322 self.assertIn('value', fnode.props)
5323
Roger Quadros47f420a2022-02-19 20:50:04 +02005324 def testPackTeeOs(self):
5325 """Test that an image with an TEE binary can be created"""
5326 data = self._DoReadFile('222_tee_os.dts')
5327 self.assertEqual(TEE_OS_DATA, data[:len(TEE_OS_DATA)])
5328
Simon Glass6a0b5f82022-02-08 11:50:03 -07005329 def testFitFdtOper(self):
5330 """Check handling of a specified FIT operation"""
5331 entry_args = {
5332 'of-list': 'test-fdt1 test-fdt2',
5333 'default-dt': 'test-fdt2',
5334 }
5335 self._DoReadFileDtb(
5336 '223_fit_fdt_oper.dts',
5337 entry_args=entry_args,
5338 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
5339
5340 def testFitFdtBadOper(self):
5341 """Check handling of an FDT map when the section cannot be found"""
5342 with self.assertRaises(ValueError) as exc:
5343 self._DoReadFileDtb('224_fit_bad_oper.dts')
Simon Glassce4e4022022-03-05 20:19:09 -07005344 self.assertIn("Node '/binman/fit': subnode 'images/@fdt-SEQ': Unknown operation 'unknown'",
Simon Glass6a0b5f82022-02-08 11:50:03 -07005345 str(exc.exception))
5346
Simon Glass80a66ae2022-03-05 20:18:59 -07005347 def test_uses_expand_size(self):
5348 """Test that the 'expand-size' property cannot be used anymore"""
5349 with self.assertRaises(ValueError) as e:
5350 data = self._DoReadFile('225_expand_size_bad.dts')
5351 self.assertIn(
5352 "Node '/binman/u-boot': Please use 'extend-size' instead of 'expand-size'",
5353 str(e.exception))
5354
Simon Glass72e423c2022-03-05 20:19:05 -07005355 def testMkimageMissingBlob(self):
5356 """Test using mkimage to build an image"""
5357 with test_util.capture_sys_output() as (stdout, stderr):
5358 self._DoTestFile('229_mkimage_missing.dts', allow_missing=True,
5359 allow_fake_blobs=True)
5360 err = stderr.getvalue()
5361 self.assertRegex(
5362 err,
5363 "Image '.*' has faked external blobs and is non-functional: .*")
5364
Simon Glass40c8bdd2022-03-05 20:19:12 -07005365 def testFitSplitElf(self):
5366 """Test an image with an FIT with an split-elf operation"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02005367 if not elf.ELF_TOOLS:
5368 self.skipTest('Python elftools not available')
Simon Glass40c8bdd2022-03-05 20:19:12 -07005369 entry_args = {
5370 'of-list': 'test-fdt1 test-fdt2',
5371 'default-dt': 'test-fdt2',
5372 'atf-bl31-path': 'bl31.elf',
5373 'tee-os-path': 'tee.elf',
5374 }
5375 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5376 data = self._DoReadFileDtb(
5377 '226_fit_split_elf.dts',
5378 entry_args=entry_args,
5379 extra_indirs=[test_subdir])[0]
5380
5381 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
5382 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
5383
5384 base_keys = {'description', 'type', 'arch', 'os', 'compression',
5385 'data', 'load'}
5386 dtb = fdt.Fdt.FromData(fit_data)
5387 dtb.Scan()
5388
5389 elf_data = tools.read_file(os.path.join(self._indir, 'bl31.elf'))
5390 segments, entry = elf.read_loadable_segments(elf_data)
5391
5392 # We assume there are two segments
5393 self.assertEquals(2, len(segments))
5394
5395 atf1 = dtb.GetNode('/images/atf-1')
5396 _, start, data = segments[0]
5397 self.assertEqual(base_keys | {'entry'}, atf1.props.keys())
5398 self.assertEqual(entry,
5399 fdt_util.fdt32_to_cpu(atf1.props['entry'].value))
5400 self.assertEqual(start,
5401 fdt_util.fdt32_to_cpu(atf1.props['load'].value))
5402 self.assertEqual(data, atf1.props['data'].bytes)
5403
5404 atf2 = dtb.GetNode('/images/atf-2')
5405 self.assertEqual(base_keys, atf2.props.keys())
5406 _, start, data = segments[1]
5407 self.assertEqual(start,
5408 fdt_util.fdt32_to_cpu(atf2.props['load'].value))
5409 self.assertEqual(data, atf2.props['data'].bytes)
5410
5411 conf = dtb.GetNode('/configurations')
5412 self.assertEqual({'default'}, conf.props.keys())
5413
5414 for subnode in conf.subnodes:
5415 self.assertEqual({'description', 'fdt', 'loadables'},
5416 subnode.props.keys())
5417 self.assertEqual(
5418 ['atf-1', 'atf-2', 'tee-1', 'tee-2'],
5419 fdt_util.GetStringList(subnode, 'loadables'))
5420
5421 def _check_bad_fit(self, dts):
5422 """Check a bad FIT
5423
5424 This runs with the given dts and returns the assertion raised
5425
5426 Args:
5427 dts (str): dts filename to use
5428
5429 Returns:
5430 str: Assertion string raised
5431 """
5432 entry_args = {
5433 'of-list': 'test-fdt1 test-fdt2',
5434 'default-dt': 'test-fdt2',
5435 'atf-bl31-path': 'bl31.elf',
5436 'tee-os-path': 'tee.elf',
5437 }
5438 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5439 with self.assertRaises(ValueError) as exc:
5440 self._DoReadFileDtb(dts, entry_args=entry_args,
5441 extra_indirs=[test_subdir])[0]
5442 return str(exc.exception)
5443
5444 def testFitSplitElfBadElf(self):
5445 """Test a FIT split-elf operation with an invalid ELF file"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02005446 if not elf.ELF_TOOLS:
5447 self.skipTest('Python elftools not available')
Simon Glass40c8bdd2022-03-05 20:19:12 -07005448 TestFunctional._MakeInputFile('bad.elf', tools.get_bytes(100, 100))
5449 entry_args = {
5450 'of-list': 'test-fdt1 test-fdt2',
5451 'default-dt': 'test-fdt2',
5452 'atf-bl31-path': 'bad.elf',
5453 'tee-os-path': 'tee.elf',
5454 }
5455 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5456 with self.assertRaises(ValueError) as exc:
5457 self._DoReadFileDtb(
5458 '226_fit_split_elf.dts',
5459 entry_args=entry_args,
5460 extra_indirs=[test_subdir])[0]
5461 self.assertIn(
5462 "Node '/binman/fit': subnode 'images/@atf-SEQ': Failed to read ELF file: Magic number does not match",
5463 str(exc.exception))
5464
5465 def testFitSplitElfBadDirective(self):
5466 """Test a FIT split-elf invalid fit,xxx directive in an image node"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02005467 if not elf.ELF_TOOLS:
5468 self.skipTest('Python elftools not available')
Simon Glass40c8bdd2022-03-05 20:19:12 -07005469 err = self._check_bad_fit('227_fit_bad_dir.dts')
5470 self.assertIn(
5471 "Node '/binman/fit': subnode 'images/@atf-SEQ': Unknown directive 'fit,something'",
5472 err)
5473
5474 def testFitSplitElfBadDirectiveConfig(self):
5475 """Test a FIT split-elf with invalid fit,xxx directive in config"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02005476 if not elf.ELF_TOOLS:
5477 self.skipTest('Python elftools not available')
Simon Glass40c8bdd2022-03-05 20:19:12 -07005478 err = self._check_bad_fit('228_fit_bad_dir_config.dts')
5479 self.assertEqual(
5480 "Node '/binman/fit': subnode 'configurations/@config-SEQ': Unknown directive 'fit,config'",
5481 err)
5482
5483 def checkFitSplitElf(self, **kwargs):
Simon Glass7960a0a2022-08-07 09:46:46 -06005484 """Test an split-elf FIT with a missing ELF file
5485
5486 Args:
5487 kwargs (dict of str): Arguments to pass to _DoTestFile()
5488
5489 Returns:
5490 tuple:
5491 str: stdout result
5492 str: stderr result
5493 """
Simon Glass40c8bdd2022-03-05 20:19:12 -07005494 entry_args = {
5495 'of-list': 'test-fdt1 test-fdt2',
5496 'default-dt': 'test-fdt2',
5497 'atf-bl31-path': 'bl31.elf',
5498 'tee-os-path': 'missing.elf',
5499 }
5500 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5501 with test_util.capture_sys_output() as (stdout, stderr):
5502 self._DoTestFile(
5503 '226_fit_split_elf.dts', entry_args=entry_args,
Simon Glass7960a0a2022-08-07 09:46:46 -06005504 extra_indirs=[test_subdir], verbosity=3, **kwargs)
5505 out = stdout.getvalue()
5506 err = stderr.getvalue()
5507 return out, err
Simon Glass40c8bdd2022-03-05 20:19:12 -07005508
5509 def testFitSplitElfMissing(self):
5510 """Test an split-elf FIT with a missing ELF file"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02005511 if not elf.ELF_TOOLS:
5512 self.skipTest('Python elftools not available')
Simon Glass7960a0a2022-08-07 09:46:46 -06005513 out, err = self.checkFitSplitElf(allow_missing=True)
Simon Glass40c8bdd2022-03-05 20:19:12 -07005514 self.assertRegex(
5515 err,
5516 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7960a0a2022-08-07 09:46:46 -06005517 self.assertNotRegex(out, '.*Faked blob.*')
5518 fname = tools.get_output_filename('binman-fake/missing.elf')
5519 self.assertFalse(os.path.exists(fname))
Simon Glass40c8bdd2022-03-05 20:19:12 -07005520
5521 def testFitSplitElfFaked(self):
5522 """Test an split-elf FIT with faked ELF file"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02005523 if not elf.ELF_TOOLS:
5524 self.skipTest('Python elftools not available')
Simon Glass7960a0a2022-08-07 09:46:46 -06005525 out, err = self.checkFitSplitElf(allow_missing=True, allow_fake_blobs=True)
Simon Glass40c8bdd2022-03-05 20:19:12 -07005526 self.assertRegex(
5527 err,
5528 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7960a0a2022-08-07 09:46:46 -06005529 self.assertRegex(
5530 out,
5531 "Entry '/binman/fit/images/@tee-SEQ/tee-os': Faked blob '.*binman-fake/missing.elf")
5532 fname = tools.get_output_filename('binman-fake/missing.elf')
5533 self.assertTrue(os.path.exists(fname))
Simon Glass40c8bdd2022-03-05 20:19:12 -07005534
Philippe Reynesb1c50932022-03-28 22:57:04 +02005535 def testPreLoad(self):
5536 """Test an image with a pre-load header"""
5537 entry_args = {
5538 'pre-load-key-path': '.',
5539 }
5540 data, _, _, _ = self._DoReadFileDtb('225_pre_load.dts',
5541 entry_args=entry_args)
5542 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5543 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5544 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5545 data = self._DoReadFile('225_pre_load.dts')
5546 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5547 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5548 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5549
5550 def testPreLoadPkcs(self):
5551 """Test an image with a pre-load header with padding pkcs"""
5552 data = self._DoReadFile('226_pre_load_pkcs.dts')
5553 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5554 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5555 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5556
5557 def testPreLoadPss(self):
5558 """Test an image with a pre-load header with padding pss"""
5559 data = self._DoReadFile('227_pre_load_pss.dts')
5560 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5561 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5562 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5563
5564 def testPreLoadInvalidPadding(self):
5565 """Test an image with a pre-load header with an invalid padding"""
5566 with self.assertRaises(ValueError) as e:
5567 data = self._DoReadFile('228_pre_load_invalid_padding.dts')
5568
5569 def testPreLoadInvalidSha(self):
5570 """Test an image with a pre-load header with an invalid hash"""
5571 with self.assertRaises(ValueError) as e:
5572 data = self._DoReadFile('229_pre_load_invalid_sha.dts')
5573
5574 def testPreLoadInvalidAlgo(self):
5575 """Test an image with a pre-load header with an invalid algo"""
5576 with self.assertRaises(ValueError) as e:
5577 data = self._DoReadFile('230_pre_load_invalid_algo.dts')
5578
5579 def testPreLoadInvalidKey(self):
5580 """Test an image with a pre-load header with an invalid key"""
5581 with self.assertRaises(ValueError) as e:
5582 data = self._DoReadFile('231_pre_load_invalid_key.dts')
Roger Quadros47f420a2022-02-19 20:50:04 +02005583
Alper Nebi Yasak67bf2c82022-03-27 18:31:44 +03005584 def _CheckSafeUniqueNames(self, *images):
5585 """Check all entries of given images for unsafe unique names"""
5586 for image in images:
5587 entries = {}
5588 image._CollectEntries(entries, {}, image)
5589 for entry in entries.values():
5590 uniq = entry.GetUniqueName()
5591
5592 # Used as part of a filename, so must not be absolute paths.
5593 self.assertFalse(os.path.isabs(uniq))
5594
5595 def testSafeUniqueNames(self):
5596 """Test entry unique names are safe in single image configuration"""
5597 data = self._DoReadFileRealDtb('230_unique_names.dts')
5598
5599 orig_image = control.images['image']
5600 image_fname = tools.get_output_filename('image.bin')
5601 image = Image.FromFile(image_fname)
5602
5603 self._CheckSafeUniqueNames(orig_image, image)
5604
5605 def testSafeUniqueNamesMulti(self):
5606 """Test entry unique names are safe with multiple images"""
5607 data = self._DoReadFileRealDtb('231_unique_names_multi.dts')
5608
5609 orig_image = control.images['image']
5610 image_fname = tools.get_output_filename('image.bin')
5611 image = Image.FromFile(image_fname)
5612
5613 self._CheckSafeUniqueNames(orig_image, image)
5614
Alper Nebi Yasak8ee4ec92022-03-27 18:31:45 +03005615 def testReplaceCmdWithBintool(self):
5616 """Test replacing an entry that needs a bintool to pack"""
5617 data = self._DoReadFileRealDtb('232_replace_with_bintool.dts')
5618 expected = U_BOOT_DATA + b'aa'
5619 self.assertEqual(expected, data[:len(expected)])
5620
5621 try:
5622 tmpdir, updated_fname = self._SetupImageInTmpdir()
5623 fname = os.path.join(tmpdir, 'update-testing.bin')
5624 tools.write_file(fname, b'zz')
5625 self._DoBinman('replace', '-i', updated_fname,
5626 '_testing', '-f', fname)
5627
5628 data = tools.read_file(updated_fname)
5629 expected = U_BOOT_DATA + b'zz'
5630 self.assertEqual(expected, data[:len(expected)])
5631 finally:
5632 shutil.rmtree(tmpdir)
5633
5634 def testReplaceCmdOtherWithBintool(self):
5635 """Test replacing an entry when another needs a bintool to pack"""
5636 data = self._DoReadFileRealDtb('232_replace_with_bintool.dts')
5637 expected = U_BOOT_DATA + b'aa'
5638 self.assertEqual(expected, data[:len(expected)])
5639
5640 try:
5641 tmpdir, updated_fname = self._SetupImageInTmpdir()
5642 fname = os.path.join(tmpdir, 'update-u-boot.bin')
5643 tools.write_file(fname, b'x' * len(U_BOOT_DATA))
5644 self._DoBinman('replace', '-i', updated_fname,
5645 'u-boot', '-f', fname)
5646
5647 data = tools.read_file(updated_fname)
5648 expected = b'x' * len(U_BOOT_DATA) + b'aa'
5649 self.assertEqual(expected, data[:len(expected)])
5650 finally:
5651 shutil.rmtree(tmpdir)
5652
Alper Nebi Yasake2ce4fb2022-03-27 18:31:46 +03005653 def testReplaceResizeNoRepackSameSize(self):
5654 """Test replacing entries with same-size data without repacking"""
5655 expected = b'x' * len(U_BOOT_DATA)
5656 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected)
5657 self.assertEqual(expected, data)
5658
5659 path, fdtmap = state.GetFdtContents('fdtmap')
5660 self.assertIsNotNone(path)
5661 self.assertEqual(expected_fdtmap, fdtmap)
5662
5663 def testReplaceResizeNoRepackSmallerSize(self):
5664 """Test replacing entries with smaller-size data without repacking"""
5665 new_data = b'x'
5666 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', new_data)
5667 expected = new_data.ljust(len(U_BOOT_DATA), b'\0')
5668 self.assertEqual(expected, data)
5669
5670 path, fdtmap = state.GetFdtContents('fdtmap')
5671 self.assertIsNotNone(path)
5672 self.assertEqual(expected_fdtmap, fdtmap)
5673
Alper Nebi Yasak74d3b232022-03-27 18:31:48 +03005674 def testExtractFit(self):
5675 """Test extracting a FIT section"""
5676 self._DoReadFileRealDtb('233_fit_extract_replace.dts')
5677 image_fname = tools.get_output_filename('image.bin')
5678
5679 fit_data = control.ReadEntry(image_fname, 'fit')
5680 fit = fdt.Fdt.FromData(fit_data)
5681 fit.Scan()
5682
5683 # Check subentry data inside the extracted fit
5684 for node_path, expected in [
5685 ('/images/kernel', U_BOOT_DATA),
5686 ('/images/fdt-1', U_BOOT_NODTB_DATA),
5687 ('/images/scr-1', COMPRESS_DATA),
5688 ]:
5689 node = fit.GetNode(node_path)
5690 data = fit.GetProps(node)['data'].bytes
5691 self.assertEqual(expected, data)
5692
5693 def testExtractFitSubentries(self):
5694 """Test extracting FIT section subentries"""
5695 self._DoReadFileRealDtb('233_fit_extract_replace.dts')
5696 image_fname = tools.get_output_filename('image.bin')
5697
5698 for entry_path, expected in [
5699 ('fit/kernel', U_BOOT_DATA),
5700 ('fit/kernel/u-boot', U_BOOT_DATA),
5701 ('fit/fdt-1', U_BOOT_NODTB_DATA),
5702 ('fit/fdt-1/u-boot-nodtb', U_BOOT_NODTB_DATA),
5703 ('fit/scr-1', COMPRESS_DATA),
5704 ('fit/scr-1/blob', COMPRESS_DATA),
5705 ]:
5706 data = control.ReadEntry(image_fname, entry_path)
5707 self.assertEqual(expected, data)
5708
Alper Nebi Yasak99283e52022-03-27 18:31:49 +03005709 def testReplaceFitSubentryLeafSameSize(self):
5710 """Test replacing a FIT leaf subentry with same-size data"""
5711 new_data = b'x' * len(U_BOOT_DATA)
5712 data, expected_fdtmap, _ = self._RunReplaceCmd(
5713 'fit/kernel/u-boot', new_data,
5714 dts='233_fit_extract_replace.dts')
5715 self.assertEqual(new_data, data)
5716
5717 path, fdtmap = state.GetFdtContents('fdtmap')
5718 self.assertIsNotNone(path)
5719 self.assertEqual(expected_fdtmap, fdtmap)
5720
5721 def testReplaceFitSubentryLeafBiggerSize(self):
5722 """Test replacing a FIT leaf subentry with bigger-size data"""
5723 new_data = b'ub' * len(U_BOOT_NODTB_DATA)
5724 data, expected_fdtmap, _ = self._RunReplaceCmd(
5725 'fit/fdt-1/u-boot-nodtb', new_data,
5726 dts='233_fit_extract_replace.dts')
5727 self.assertEqual(new_data, data)
5728
5729 # Will be repacked, so fdtmap must change
5730 path, fdtmap = state.GetFdtContents('fdtmap')
5731 self.assertIsNotNone(path)
5732 self.assertNotEqual(expected_fdtmap, fdtmap)
5733
5734 def testReplaceFitSubentryLeafSmallerSize(self):
5735 """Test replacing a FIT leaf subentry with smaller-size data"""
5736 new_data = b'x'
5737 expected = new_data.ljust(len(U_BOOT_NODTB_DATA), b'\0')
5738 data, expected_fdtmap, _ = self._RunReplaceCmd(
5739 'fit/fdt-1/u-boot-nodtb', new_data,
5740 dts='233_fit_extract_replace.dts')
5741 self.assertEqual(expected, data)
5742
5743 path, fdtmap = state.GetFdtContents('fdtmap')
5744 self.assertIsNotNone(path)
5745 self.assertEqual(expected_fdtmap, fdtmap)
5746
Alper Nebi Yasak82337bb2022-03-27 18:31:50 +03005747 def testReplaceSectionSimple(self):
5748 """Test replacing a simple section with arbitrary data"""
5749 new_data = b'w' * len(COMPRESS_DATA + U_BOOT_DATA)
Simon Glass73593e42022-08-13 11:40:46 -06005750 with self.assertRaises(ValueError) as exc:
5751 self._RunReplaceCmd('section', new_data,
5752 dts='234_replace_section_simple.dts')
5753 self.assertIn(
5754 "Node '/section': Replacing sections is not implemented yet",
5755 str(exc.exception))
Alper Nebi Yasak82337bb2022-03-27 18:31:50 +03005756
Simon Glassdfe1db42022-08-13 11:40:48 -06005757 def testMkimageImagename(self):
5758 """Test using mkimage with -n holding the data too"""
5759 data = self._DoReadFile('235_mkimage_name.dts')
5760
5761 # Check that the data appears in the file somewhere
5762 self.assertIn(U_BOOT_SPL_DATA, data)
5763
5764 # Get struct image_header -> ih_name
5765 name = data[0x20:0x40]
5766
5767 # Build the filename that we expect to be placed in there, by virtue of
5768 # the -n paraameter
5769 expect = os.path.join(tools.get_output_dir(), 'mkimage.mkimage')
5770
5771 # Check that the image name is set to the temporary filename used
5772 self.assertEqual(expect.encode('utf-8')[:0x20], name)
5773
Simon Glass9db9e932022-08-13 11:40:49 -06005774 def testMkimageImage(self):
5775 """Test using mkimage with -n holding the data too"""
5776 data = self._DoReadFile('236_mkimage_image.dts')
5777
5778 # Check that the data appears in the file somewhere
5779 self.assertIn(U_BOOT_SPL_DATA, data)
5780
5781 # Get struct image_header -> ih_name
5782 name = data[0x20:0x40]
5783
5784 # Build the filename that we expect to be placed in there, by virtue of
5785 # the -n paraameter
5786 expect = os.path.join(tools.get_output_dir(), 'mkimage-n.mkimage')
5787
5788 # Check that the image name is set to the temporary filename used
5789 self.assertEqual(expect.encode('utf-8')[:0x20], name)
5790
5791 # Check the corect data is in the imagename file
5792 self.assertEqual(U_BOOT_DATA, tools.read_file(expect))
5793
5794 def testMkimageImageNoContent(self):
5795 """Test using mkimage with -n and no data"""
5796 with self.assertRaises(ValueError) as exc:
5797 self._DoReadFile('237_mkimage_image_no_content.dts')
5798 self.assertIn('Could not complete processing of contents',
5799 str(exc.exception))
5800
5801 def testMkimageImageBad(self):
5802 """Test using mkimage with imagename node and data-to-imagename"""
5803 with self.assertRaises(ValueError) as exc:
5804 self._DoReadFile('238_mkimage_image_bad.dts')
5805 self.assertIn('Cannot use both imagename node and data-to-imagename',
5806 str(exc.exception))
5807
Simon Glassd626e822022-08-13 11:40:50 -06005808 def testCollectionOther(self):
5809 """Test a collection where the data comes from another section"""
5810 data = self._DoReadFile('239_collection_other.dts')
5811 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
5812 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
5813 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
5814 data)
5815
5816 def testMkimageCollection(self):
5817 """Test using a collection referring to an entry in a mkimage entry"""
5818 data = self._DoReadFile('240_mkimage_coll.dts')
5819 expect = U_BOOT_SPL_DATA + U_BOOT_DATA
5820 self.assertEqual(expect, data[:len(expect)])
5821
Stefan Herbrechtsmeier6aa80002022-08-19 16:25:25 +02005822 def testCompressDtbPrependInvalid(self):
5823 """Test that invalid header is detected"""
5824 with self.assertRaises(ValueError) as e:
5825 self._DoReadFileDtb('235_compress_dtb_prepend_invalid.dts')
5826 self.assertIn("Node '/binman/u-boot-dtb': Invalid prepend in "
5827 "'u-boot-dtb': 'invalid'", str(e.exception))
5828
5829 def testCompressDtbPrependLength(self):
5830 """Test that compress with length header works as expected"""
5831 data = self._DoReadFileRealDtb('236_compress_dtb_prepend_length.dts')
5832 image = control.images['image']
5833 entries = image.GetEntries()
5834 self.assertIn('u-boot-dtb', entries)
5835 u_boot_dtb = entries['u-boot-dtb']
5836 self.assertIn('fdtmap', entries)
5837 fdtmap = entries['fdtmap']
5838
5839 image_fname = tools.get_output_filename('image.bin')
5840 orig = control.ReadEntry(image_fname, 'u-boot-dtb')
5841 dtb = fdt.Fdt.FromData(orig)
5842 dtb.Scan()
5843 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
5844 expected = {
5845 'u-boot:size': len(U_BOOT_DATA),
5846 'u-boot-dtb:uncomp-size': len(orig),
5847 'u-boot-dtb:size': u_boot_dtb.size,
5848 'fdtmap:size': fdtmap.size,
5849 'size': len(data),
5850 }
5851 self.assertEqual(expected, props)
5852
5853 # Check implementation
5854 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
5855 rest = data[len(U_BOOT_DATA):]
5856 comp_data_len = struct.unpack('<I', rest[:4])[0]
5857 comp_data = rest[4:4 + comp_data_len]
5858 orig2 = self._decompress(comp_data)
5859 self.assertEqual(orig, orig2)
5860
Alper Nebi Yasak8ee4ec92022-03-27 18:31:45 +03005861
Simon Glass9fc60b42017-11-12 21:52:22 -07005862if __name__ == "__main__":
5863 unittest.main()