blob: 81ecc8829f975ea6e9a43408e23b3e7f42c51661 [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
26from binman import control
27from binman import elf
28from binman import elf_test
Simon Glass75989722021-11-23 21:08:59 -070029from binman import fip_util
Simon Glass16287932020-04-17 18:09:03 -060030from binman import fmap_util
Simon Glass16287932020-04-17 18:09:03 -060031from binman import state
32from dtoc import fdt
33from dtoc import fdt_util
34from binman.etype import fdtmap
35from binman.etype import image_header
Simon Glass07237982020-08-05 13:27:47 -060036from binman.image import Image
Simon Glassbf776672020-04-17 18:09:04 -060037from patman import command
38from patman import test_util
39from patman import tools
40from patman import tout
Simon Glass4f443042016-11-25 20:15:52 -070041
42# Contents of test files, corresponding to different entry types
Simon Glassc6c10e72019-05-17 22:00:46 -060043U_BOOT_DATA = b'1234'
44U_BOOT_IMG_DATA = b'img'
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +030045U_BOOT_SPL_DATA = b'56780123456789abcdefghijklm'
46U_BOOT_TPL_DATA = b'tpl9876543210fedcbazywvuts'
Simon Glassc6c10e72019-05-17 22:00:46 -060047BLOB_DATA = b'89'
48ME_DATA = b'0abcd'
49VGA_DATA = b'vga'
50U_BOOT_DTB_DATA = b'udtb'
51U_BOOT_SPL_DTB_DATA = b'spldtb'
52U_BOOT_TPL_DTB_DATA = b'tpldtb'
53X86_START16_DATA = b'start16'
54X86_START16_SPL_DATA = b'start16spl'
55X86_START16_TPL_DATA = b'start16tpl'
Simon Glass2250ee62019-08-24 07:22:48 -060056X86_RESET16_DATA = b'reset16'
57X86_RESET16_SPL_DATA = b'reset16spl'
58X86_RESET16_TPL_DATA = b'reset16tpl'
Simon Glassc6c10e72019-05-17 22:00:46 -060059PPC_MPC85XX_BR_DATA = b'ppcmpc85xxbr'
60U_BOOT_NODTB_DATA = b'nodtb with microcode pointer somewhere in here'
61U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here'
62U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here'
Alper Nebi Yasak21353312022-02-08 01:08:04 +030063U_BOOT_EXP_DATA = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
64U_BOOT_SPL_EXP_DATA = U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA
65U_BOOT_TPL_EXP_DATA = U_BOOT_TPL_NODTB_DATA + U_BOOT_TPL_DTB_DATA
Simon Glassc6c10e72019-05-17 22:00:46 -060066FSP_DATA = b'fsp'
67CMC_DATA = b'cmc'
68VBT_DATA = b'vbt'
69MRC_DATA = b'mrc'
Simon Glassbb748372018-07-17 13:25:33 -060070TEXT_DATA = 'text'
71TEXT_DATA2 = 'text2'
72TEXT_DATA3 = 'text3'
Simon Glassc6c10e72019-05-17 22:00:46 -060073CROS_EC_RW_DATA = b'ecrw'
74GBB_DATA = b'gbbd'
75BMPBLK_DATA = b'bmp'
76VBLOCK_DATA = b'vblk'
77FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
78 b"sorry you're alive\n")
Simon Glassff5c7e32019-07-08 13:18:42 -060079COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
Simon Glass8f5ef892020-10-26 17:40:25 -060080COMPRESS_DATA_BIG = COMPRESS_DATA * 2
Simon Glassc6c10e72019-05-17 22:00:46 -060081REFCODE_DATA = b'refcode'
Simon Glassea0fff92019-08-24 07:23:07 -060082FSP_M_DATA = b'fsp_m'
Simon Glassbc6a88f2019-10-20 21:31:35 -060083FSP_S_DATA = b'fsp_s'
Simon Glass998d1482019-10-20 21:31:36 -060084FSP_T_DATA = b'fsp_t'
Simon Glassdc2f81a2020-09-01 05:13:58 -060085ATF_BL31_DATA = b'bl31'
Roger Quadros47f420a2022-02-19 20:50:04 +020086TEE_OS_DATA = b'this is some tee OS data'
Simon Glass75989722021-11-23 21:08:59 -070087ATF_BL2U_DATA = b'bl2u'
Bin Meng4c4d6072021-05-10 20:23:33 +080088OPENSBI_DATA = b'opensbi'
Samuel Holland18bd4552020-10-21 21:12:15 -050089SCP_DATA = b'scp'
Simon Glass6cf99532020-09-01 05:13:59 -060090TEST_FDT1_DATA = b'fdt1'
91TEST_FDT2_DATA = b'test-fdt2'
Simon Glassfb91d562020-09-06 10:35:33 -060092ENV_DATA = b'var1=1\nvar2="2"'
Philippe Reynesb1c50932022-03-28 22:57:04 +020093PRE_LOAD_MAGIC = b'UBSH'
94PRE_LOAD_VERSION = 0x11223344.to_bytes(4, 'big')
95PRE_LOAD_HDR_SIZE = 0x00001000.to_bytes(4, 'big')
Simon Glass6cf99532020-09-01 05:13:59 -060096
97# Subdirectory of the input dir to use to put test FDTs
98TEST_FDT_SUBDIR = 'fdts'
Simon Glassec127af2018-07-17 13:25:39 -060099
Simon Glass6ccbfcd2019-07-20 12:23:47 -0600100# The expected size for the device tree in some tests
Simon Glassf667e452019-07-08 14:25:50 -0600101EXTRACT_DTB_SIZE = 0x3c9
102
Simon Glass6ccbfcd2019-07-20 12:23:47 -0600103# Properties expected to be in the device tree when update_dtb is used
104BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
105
Simon Glass12bb1a92019-07-20 12:23:51 -0600106# Extra properties expected to be in the device tree when allow-repack is used
107REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
108
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +0200109# Supported compression bintools
110COMP_BINTOOLS = ['lz4', 'lzma_alone']
Simon Glass4f443042016-11-25 20:15:52 -0700111
112class TestFunctional(unittest.TestCase):
113 """Functional tests for binman
114
115 Most of these use a sample .dts file to build an image and then check
116 that it looks correct. The sample files are in the test/ subdirectory
117 and are numbered.
118
119 For each entry type a very small test file is created using fixed
120 string contents. This makes it easy to test that things look right, and
121 debug problems.
122
123 In some cases a 'real' file must be used - these are also supplied in
124 the test/ diurectory.
125 """
126 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600127 def setUpClass(cls):
Simon Glass4d5994f2017-11-12 21:52:20 -0700128 global entry
Simon Glass16287932020-04-17 18:09:03 -0600129 from binman import entry
Simon Glass4d5994f2017-11-12 21:52:20 -0700130
Simon Glass4f443042016-11-25 20:15:52 -0700131 # Handle the case where argv[0] is 'python'
Simon Glassb986b3b2019-08-24 07:22:43 -0600132 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
133 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
Simon Glass4f443042016-11-25 20:15:52 -0700134
135 # Create a temporary directory for input files
Simon Glassb986b3b2019-08-24 07:22:43 -0600136 cls._indir = tempfile.mkdtemp(prefix='binmant.')
Simon Glass4f443042016-11-25 20:15:52 -0700137
138 # Create some test files
139 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
140 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
141 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glassb8ef5b62018-07-17 13:25:48 -0600142 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700143 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -0700144 TestFunctional._MakeInputFile('me.bin', ME_DATA)
145 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glassb986b3b2019-08-24 07:22:43 -0600146 cls._ResetDtbs()
Simon Glass2250ee62019-08-24 07:22:48 -0600147
Jagdish Gediya9d368f32018-09-03 21:35:08 +0530148 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glass2250ee62019-08-24 07:22:48 -0600149
Simon Glass5e239182019-08-24 07:22:49 -0600150 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
151 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
Simon Glass87722132017-11-12 21:52:26 -0700152 X86_START16_SPL_DATA)
Simon Glass5e239182019-08-24 07:22:49 -0600153 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
Simon Glass35b384c2018-09-14 04:57:10 -0600154 X86_START16_TPL_DATA)
Simon Glass2250ee62019-08-24 07:22:48 -0600155
156 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
157 X86_RESET16_DATA)
158 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
159 X86_RESET16_SPL_DATA)
160 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
161 X86_RESET16_TPL_DATA)
162
Simon Glass4f443042016-11-25 20:15:52 -0700163 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass6b187df2017-11-12 21:52:27 -0700164 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
165 U_BOOT_SPL_NODTB_DATA)
Simon Glassf0253632018-09-14 04:57:32 -0600166 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
167 U_BOOT_TPL_NODTB_DATA)
Simon Glassda229092016-11-25 20:15:56 -0700168 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
169 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Meng59ea8c22017-08-15 22:41:54 -0700170 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassca4f4ff2017-11-12 21:52:28 -0700171 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassec127af2018-07-17 13:25:39 -0600172 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glass0ef87aa2018-07-17 13:25:44 -0600173 TestFunctional._MakeInputDir('devkeys')
174 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass3ae192c2018-10-01 12:22:31 -0600175 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glassea0fff92019-08-24 07:23:07 -0600176 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
Simon Glassbc6a88f2019-10-20 21:31:35 -0600177 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
Simon Glass998d1482019-10-20 21:31:36 -0600178 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700179
Simon Glass53e22bf2019-08-24 07:22:53 -0600180 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
181 elf_test.BuildElfTestFiles(cls._elf_testdir)
182
Simon Glasse0ff8552016-11-25 20:15:53 -0700183 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glassf514d8f2019-08-24 07:22:54 -0600184 TestFunctional._MakeInputFile('u-boot',
Simon Glassc1aa66e2022-01-29 14:14:04 -0700185 tools.read_file(cls.ElfTestFile('u_boot_ucode_ptr')))
Simon Glasse0ff8552016-11-25 20:15:53 -0700186
187 # Intel flash descriptor file
Simon Glass0ba4b3d2020-07-09 18:39:41 -0600188 cls._SetupDescriptor()
Simon Glasse0ff8552016-11-25 20:15:53 -0700189
Simon Glassb986b3b2019-08-24 07:22:43 -0600190 shutil.copytree(cls.TestFile('files'),
191 os.path.join(cls._indir, 'files'))
Simon Glass0a98b282018-09-14 04:57:28 -0600192
Simon Glass83d73c22018-09-14 04:57:26 -0600193 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
Simon Glass8f5ef892020-10-26 17:40:25 -0600194 TestFunctional._MakeInputFile('compress_big', COMPRESS_DATA_BIG)
Simon Glassdc2f81a2020-09-01 05:13:58 -0600195 TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
Roger Quadros47f420a2022-02-19 20:50:04 +0200196 TestFunctional._MakeInputFile('tee-pager.bin', TEE_OS_DATA)
Simon Glass75989722021-11-23 21:08:59 -0700197 TestFunctional._MakeInputFile('bl2u.bin', ATF_BL2U_DATA)
Bin Meng4c4d6072021-05-10 20:23:33 +0800198 TestFunctional._MakeInputFile('fw_dynamic.bin', OPENSBI_DATA)
Samuel Holland18bd4552020-10-21 21:12:15 -0500199 TestFunctional._MakeInputFile('scp.bin', SCP_DATA)
Simon Glass83d73c22018-09-14 04:57:26 -0600200
Simon Glass6cf99532020-09-01 05:13:59 -0600201 # Add a few .dtb files for testing
202 TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR,
203 TEST_FDT1_DATA)
204 TestFunctional._MakeInputFile('%s/test-fdt2.dtb' % TEST_FDT_SUBDIR,
205 TEST_FDT2_DATA)
206
Simon Glassfb91d562020-09-06 10:35:33 -0600207 TestFunctional._MakeInputFile('env.txt', ENV_DATA)
208
Simon Glass40c8bdd2022-03-05 20:19:12 -0700209 # ELF file with two sections in different parts of memory, used for both
210 # ATF and OP_TEE
211 TestFunctional._MakeInputFile('bl31.elf',
212 tools.read_file(cls.ElfTestFile('elf_sections')))
213 TestFunctional._MakeInputFile('tee.elf',
214 tools.read_file(cls.ElfTestFile('elf_sections')))
215
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +0200216 cls.comp_bintools = {}
217 for name in COMP_BINTOOLS:
218 cls.comp_bintools[name] = bintool.Bintool.create(name)
Simon Glassac62fba2019-07-08 13:18:53 -0600219
Simon Glass4f443042016-11-25 20:15:52 -0700220 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600221 def tearDownClass(cls):
Simon Glass4f443042016-11-25 20:15:52 -0700222 """Remove the temporary input directory and its contents"""
Simon Glassb986b3b2019-08-24 07:22:43 -0600223 if cls.preserve_indir:
224 print('Preserving input dir: %s' % cls._indir)
Simon Glassd5164a72019-07-08 13:18:49 -0600225 else:
Simon Glassb986b3b2019-08-24 07:22:43 -0600226 if cls._indir:
227 shutil.rmtree(cls._indir)
228 cls._indir = None
Simon Glass4f443042016-11-25 20:15:52 -0700229
Simon Glassd5164a72019-07-08 13:18:49 -0600230 @classmethod
Simon Glass8acce602019-07-08 13:18:50 -0600231 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
Simon Glass53cd5d92019-07-08 14:25:29 -0600232 toolpath=None, verbosity=None):
Simon Glassd5164a72019-07-08 13:18:49 -0600233 """Accept arguments controlling test execution
234
235 Args:
236 preserve_indir: Preserve the shared input directory used by all
237 tests in this class.
238 preserve_outdir: Preserve the output directories used by tests. Each
239 test has its own, so this is normally only useful when running a
240 single test.
Simon Glass8acce602019-07-08 13:18:50 -0600241 toolpath: ist of paths to use for tools
Simon Glassd5164a72019-07-08 13:18:49 -0600242 """
243 cls.preserve_indir = preserve_indir
244 cls.preserve_outdirs = preserve_outdirs
Simon Glass8acce602019-07-08 13:18:50 -0600245 cls.toolpath = toolpath
Simon Glass53cd5d92019-07-08 14:25:29 -0600246 cls.verbosity = verbosity
Simon Glassd5164a72019-07-08 13:18:49 -0600247
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +0200248 def _CheckBintool(self, bintool):
249 if not bintool.is_present():
250 self.skipTest('%s not available' % bintool.name)
251
Simon Glassac62fba2019-07-08 13:18:53 -0600252 def _CheckLz4(self):
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +0200253 bintool = self.comp_bintools['lz4']
254 self._CheckBintool(bintool)
Simon Glassac62fba2019-07-08 13:18:53 -0600255
Simon Glassbf574f12019-07-20 12:24:09 -0600256 def _CleanupOutputDir(self):
257 """Remove the temporary output directory"""
258 if self.preserve_outdirs:
259 print('Preserving output dir: %s' % tools.outdir)
260 else:
Simon Glassc1aa66e2022-01-29 14:14:04 -0700261 tools._finalise_for_test()
Simon Glassbf574f12019-07-20 12:24:09 -0600262
Simon Glass4f443042016-11-25 20:15:52 -0700263 def setUp(self):
264 # Enable this to turn on debugging output
Simon Glassf3385a52022-01-29 14:14:15 -0700265 # tout.init(tout.DEBUG)
Simon Glass4f443042016-11-25 20:15:52 -0700266 command.test_result = None
267
268 def tearDown(self):
269 """Remove the temporary output directory"""
Simon Glassbf574f12019-07-20 12:24:09 -0600270 self._CleanupOutputDir()
Simon Glass4f443042016-11-25 20:15:52 -0700271
Simon Glassf86a7362019-07-20 12:24:10 -0600272 def _SetupImageInTmpdir(self):
273 """Set up the output image in a new temporary directory
274
275 This is used when an image has been generated in the output directory,
276 but we want to run binman again. This will create a new output
277 directory and fail to delete the original one.
278
279 This creates a new temporary directory, copies the image to it (with a
280 new name) and removes the old output directory.
281
282 Returns:
283 Tuple:
284 Temporary directory to use
285 New image filename
286 """
Simon Glassc1aa66e2022-01-29 14:14:04 -0700287 image_fname = tools.get_output_filename('image.bin')
Simon Glassf86a7362019-07-20 12:24:10 -0600288 tmpdir = tempfile.mkdtemp(prefix='binman.')
289 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
Simon Glassc1aa66e2022-01-29 14:14:04 -0700290 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassf86a7362019-07-20 12:24:10 -0600291 self._CleanupOutputDir()
292 return tmpdir, updated_fname
293
Simon Glassb8ef5b62018-07-17 13:25:48 -0600294 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600295 def _ResetDtbs(cls):
Simon Glassb8ef5b62018-07-17 13:25:48 -0600296 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
297 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
298 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
299
Simon Glass4f443042016-11-25 20:15:52 -0700300 def _RunBinman(self, *args, **kwargs):
301 """Run binman using the command line
302
303 Args:
304 Arguments to pass, as a list of strings
305 kwargs: Arguments to pass to Command.RunPipe()
306 """
Simon Glassd9800692022-01-29 14:14:05 -0700307 result = command.run_pipe([[self._binman_pathname] + list(args)],
Simon Glass4f443042016-11-25 20:15:52 -0700308 capture=True, capture_stderr=True, raise_on_error=False)
309 if result.return_code and kwargs.get('raise_on_error', True):
310 raise Exception("Error running '%s': %s" % (' '.join(args),
311 result.stdout + result.stderr))
312 return result
313
Simon Glass53cd5d92019-07-08 14:25:29 -0600314 def _DoBinman(self, *argv):
Simon Glass4f443042016-11-25 20:15:52 -0700315 """Run binman using directly (in the same process)
316
317 Args:
318 Arguments to pass, as a list of strings
319 Returns:
320 Return value (0 for success)
321 """
Simon Glass53cd5d92019-07-08 14:25:29 -0600322 argv = list(argv)
323 args = cmdline.ParseArgs(argv)
324 args.pager = 'binman-invalid-pager'
325 args.build_dir = self._indir
Simon Glass4f443042016-11-25 20:15:52 -0700326
327 # For testing, you can force an increase in verbosity here
Simon Glass53cd5d92019-07-08 14:25:29 -0600328 # args.verbosity = tout.DEBUG
329 return control.Binman(args)
Simon Glass4f443042016-11-25 20:15:52 -0700330
Simon Glass53af22a2018-07-17 13:25:32 -0600331 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glasseb833d82019-04-25 21:58:34 -0600332 entry_args=None, images=None, use_real_dtb=False,
Simon Glass63aeaeb2021-03-18 20:25:05 +1300333 use_expanded=False, verbosity=None, allow_missing=False,
Heiko Thierya89c8f22022-01-06 11:49:41 +0100334 allow_fake_blobs=False, extra_indirs=None, threads=None,
Simon Glass4f9ee832022-01-09 20:14:09 -0700335 test_section_timeout=False, update_fdt_in_elf=None,
336 force_missing_bintools=''):
Simon Glass4f443042016-11-25 20:15:52 -0700337 """Run binman with a given test file
338
339 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600340 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600341 debug: True to enable debugging output
Simon Glass3b0c38212018-06-01 09:38:20 -0600342 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600343 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600344 tree before packing it into the image
Simon Glass0bfa7b02018-09-14 04:57:12 -0600345 entry_args: Dict of entry args to supply to binman
346 key: arg name
347 value: value of that arg
348 images: List of image names to build
Simon Glasse9d336d2020-09-01 05:13:55 -0600349 use_real_dtb: True to use the test file as the contents of
350 the u-boot-dtb entry. Normally this is not needed and the
351 test contents (the U_BOOT_DTB_DATA string) can be used.
352 But in some test we need the real contents.
Simon Glass63aeaeb2021-03-18 20:25:05 +1300353 use_expanded: True to use expanded entries where available, e.g.
354 'u-boot-expanded' instead of 'u-boot'
Simon Glasse9d336d2020-09-01 05:13:55 -0600355 verbosity: Verbosity level to use (0-3, None=don't set it)
356 allow_missing: Set the '--allow-missing' flag so that missing
357 external binaries just produce a warning instead of an error
Heiko Thierya89c8f22022-01-06 11:49:41 +0100358 allow_fake_blobs: Set the '--fake-ext-blobs' flag
Simon Glass6cf99532020-09-01 05:13:59 -0600359 extra_indirs: Extra input directories to add using -I
Simon Glassc69d19c2021-07-06 10:36:37 -0600360 threads: Number of threads to use (None for default, 0 for
361 single-threaded)
Simon Glass7115f002021-11-03 21:09:17 -0600362 test_section_timeout: True to force the first time to timeout, as
363 used in testThreadTimeout()
Simon Glass0427bed2021-11-03 21:09:18 -0600364 update_fdt_in_elf: Value to pass with --update-fdt-in-elf=xxx
Simon Glass4f9ee832022-01-09 20:14:09 -0700365 force_missing_tools (str): comma-separated list of bintools to
366 regard as missing
Simon Glass7115f002021-11-03 21:09:17 -0600367
368 Returns:
369 int return code, 0 on success
Simon Glass4f443042016-11-25 20:15:52 -0700370 """
Simon Glass53cd5d92019-07-08 14:25:29 -0600371 args = []
Simon Glass7fe91732017-11-13 18:55:00 -0700372 if debug:
373 args.append('-D')
Simon Glass53cd5d92019-07-08 14:25:29 -0600374 if verbosity is not None:
375 args.append('-v%d' % verbosity)
376 elif self.verbosity:
377 args.append('-v%d' % self.verbosity)
378 if self.toolpath:
379 for path in self.toolpath:
380 args += ['--toolpath', path]
Simon Glassc69d19c2021-07-06 10:36:37 -0600381 if threads is not None:
382 args.append('-T%d' % threads)
383 if test_section_timeout:
384 args.append('--test-section-timeout')
Simon Glass53cd5d92019-07-08 14:25:29 -0600385 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass3b0c38212018-06-01 09:38:20 -0600386 if map:
387 args.append('-m')
Simon Glass16b8d6b2018-07-06 10:27:42 -0600388 if update_dtb:
Simon Glass2569e102019-07-08 13:18:47 -0600389 args.append('-u')
Simon Glass93d17412018-09-14 04:57:23 -0600390 if not use_real_dtb:
391 args.append('--fake-dtb')
Simon Glass63aeaeb2021-03-18 20:25:05 +1300392 if not use_expanded:
393 args.append('--no-expanded')
Simon Glass53af22a2018-07-17 13:25:32 -0600394 if entry_args:
Simon Glass50979152019-05-14 15:53:41 -0600395 for arg, value in entry_args.items():
Simon Glass53af22a2018-07-17 13:25:32 -0600396 args.append('-a%s=%s' % (arg, value))
Simon Glass4f9f1052020-07-09 18:39:38 -0600397 if allow_missing:
398 args.append('-M')
Heiko Thierya89c8f22022-01-06 11:49:41 +0100399 if allow_fake_blobs:
400 args.append('--fake-ext-blobs')
Simon Glass4f9ee832022-01-09 20:14:09 -0700401 if force_missing_bintools:
402 args += ['--force-missing-bintools', force_missing_bintools]
Simon Glass0427bed2021-11-03 21:09:18 -0600403 if update_fdt_in_elf:
404 args += ['--update-fdt-in-elf', update_fdt_in_elf]
Simon Glass0bfa7b02018-09-14 04:57:12 -0600405 if images:
406 for image in images:
407 args += ['-i', image]
Simon Glass6cf99532020-09-01 05:13:59 -0600408 if extra_indirs:
409 for indir in extra_indirs:
410 args += ['-I', indir]
Simon Glass7fe91732017-11-13 18:55:00 -0700411 return self._DoBinman(*args)
Simon Glass4f443042016-11-25 20:15:52 -0700412
413 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glasse0ff8552016-11-25 20:15:53 -0700414 """Set up a new test device-tree file
415
416 The given file is compiled and set up as the device tree to be used
417 for ths test.
418
419 Args:
420 fname: Filename of .dts file to read
Simon Glass7ae5f312018-06-01 09:38:19 -0600421 outfile: Output filename for compiled device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700422
423 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600424 Contents of device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700425 """
Simon Glassa004f292019-07-20 12:23:49 -0600426 tmpdir = tempfile.mkdtemp(prefix='binmant.')
427 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
Simon Glass1d0ebf72019-05-14 15:53:42 -0600428 with open(dtb, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700429 data = fd.read()
430 TestFunctional._MakeInputFile(outfile, data)
Simon Glassa004f292019-07-20 12:23:49 -0600431 shutil.rmtree(tmpdir)
Simon Glasse0e62752018-10-01 21:12:41 -0600432 return data
Simon Glass4f443042016-11-25 20:15:52 -0700433
Simon Glass6ed45ba2018-09-14 04:57:24 -0600434 def _GetDtbContentsForSplTpl(self, dtb_data, name):
435 """Create a version of the main DTB for SPL or SPL
436
437 For testing we don't actually have different versions of the DTB. With
438 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
439 we don't normally have any unwanted nodes.
440
441 We still want the DTBs for SPL and TPL to be different though, since
442 otherwise it is confusing to know which one we are looking at. So add
443 an 'spl' or 'tpl' property to the top-level node.
Simon Glasse9d336d2020-09-01 05:13:55 -0600444
445 Args:
446 dtb_data: dtb data to modify (this should be a value devicetree)
447 name: Name of a new property to add
448
449 Returns:
450 New dtb data with the property added
Simon Glass6ed45ba2018-09-14 04:57:24 -0600451 """
452 dtb = fdt.Fdt.FromData(dtb_data)
453 dtb.Scan()
454 dtb.GetNode('/binman').AddZeroProp(name)
455 dtb.Sync(auto_resize=True)
456 dtb.Pack()
457 return dtb.GetContents()
458
Simon Glass63aeaeb2021-03-18 20:25:05 +1300459 def _DoReadFileDtb(self, fname, use_real_dtb=False, use_expanded=False,
460 map=False, update_dtb=False, entry_args=None,
Simon Glassc69d19c2021-07-06 10:36:37 -0600461 reset_dtbs=True, extra_indirs=None, threads=None):
Simon Glass4f443042016-11-25 20:15:52 -0700462 """Run binman and return the resulting image
463
464 This runs binman with a given test file and then reads the resulting
465 output file. It is a shortcut function since most tests need to do
466 these steps.
467
468 Raises an assertion failure if binman returns a non-zero exit code.
469
470 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600471 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass4f443042016-11-25 20:15:52 -0700472 use_real_dtb: True to use the test file as the contents of
473 the u-boot-dtb entry. Normally this is not needed and the
474 test contents (the U_BOOT_DTB_DATA string) can be used.
475 But in some test we need the real contents.
Simon Glass63aeaeb2021-03-18 20:25:05 +1300476 use_expanded: True to use expanded entries where available, e.g.
477 'u-boot-expanded' instead of 'u-boot'
Simon Glass3b0c38212018-06-01 09:38:20 -0600478 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600479 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600480 tree before packing it into the image
Simon Glasse9d336d2020-09-01 05:13:55 -0600481 entry_args: Dict of entry args to supply to binman
482 key: arg name
483 value: value of that arg
484 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
485 function. If reset_dtbs is True, then the original test dtb
486 is written back before this function finishes
Simon Glass6cf99532020-09-01 05:13:59 -0600487 extra_indirs: Extra input directories to add using -I
Simon Glassc69d19c2021-07-06 10:36:37 -0600488 threads: Number of threads to use (None for default, 0 for
489 single-threaded)
Simon Glasse0ff8552016-11-25 20:15:53 -0700490
491 Returns:
492 Tuple:
493 Resulting image contents
494 Device tree contents
Simon Glass3b0c38212018-06-01 09:38:20 -0600495 Map data showing contents of image (or None if none)
Simon Glassea6922e2018-07-17 13:25:27 -0600496 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass4f443042016-11-25 20:15:52 -0700497 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700498 dtb_data = None
Simon Glass4f443042016-11-25 20:15:52 -0700499 # Use the compiled test file as the u-boot-dtb input
500 if use_real_dtb:
Simon Glasse0ff8552016-11-25 20:15:53 -0700501 dtb_data = self._SetupDtb(fname)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600502
503 # For testing purposes, make a copy of the DT for SPL and TPL. Add
504 # a node indicating which it is, so aid verification.
505 for name in ['spl', 'tpl']:
506 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
507 outfile = os.path.join(self._indir, dtb_fname)
508 TestFunctional._MakeInputFile(dtb_fname,
509 self._GetDtbContentsForSplTpl(dtb_data, name))
Simon Glass4f443042016-11-25 20:15:52 -0700510
511 try:
Simon Glass53af22a2018-07-17 13:25:32 -0600512 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glass6cf99532020-09-01 05:13:59 -0600513 entry_args=entry_args, use_real_dtb=use_real_dtb,
Simon Glassc69d19c2021-07-06 10:36:37 -0600514 use_expanded=use_expanded, extra_indirs=extra_indirs,
515 threads=threads)
Simon Glass4f443042016-11-25 20:15:52 -0700516 self.assertEqual(0, retcode)
Simon Glassc1aa66e2022-01-29 14:14:04 -0700517 out_dtb_fname = tools.get_output_filename('u-boot.dtb.out')
Simon Glass4f443042016-11-25 20:15:52 -0700518
519 # Find the (only) image, read it and return its contents
520 image = control.images['image']
Simon Glassc1aa66e2022-01-29 14:14:04 -0700521 image_fname = tools.get_output_filename('image.bin')
Simon Glass16b8d6b2018-07-06 10:27:42 -0600522 self.assertTrue(os.path.exists(image_fname))
Simon Glass3b0c38212018-06-01 09:38:20 -0600523 if map:
Simon Glassc1aa66e2022-01-29 14:14:04 -0700524 map_fname = tools.get_output_filename('image.map')
Simon Glass3b0c38212018-06-01 09:38:20 -0600525 with open(map_fname) as fd:
526 map_data = fd.read()
527 else:
528 map_data = None
Simon Glass1d0ebf72019-05-14 15:53:42 -0600529 with open(image_fname, 'rb') as fd:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600530 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass4f443042016-11-25 20:15:52 -0700531 finally:
532 # Put the test file back
Simon Glass6ed45ba2018-09-14 04:57:24 -0600533 if reset_dtbs and use_real_dtb:
Simon Glassb8ef5b62018-07-17 13:25:48 -0600534 self._ResetDtbs()
Simon Glass4f443042016-11-25 20:15:52 -0700535
Simon Glass3c081312019-07-08 14:25:26 -0600536 def _DoReadFileRealDtb(self, fname):
537 """Run binman with a real .dtb file and return the resulting data
538
539 Args:
540 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
541
542 Returns:
543 Resulting image contents
544 """
545 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
546
Simon Glasse0ff8552016-11-25 20:15:53 -0700547 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass7ae5f312018-06-01 09:38:19 -0600548 """Helper function which discards the device-tree binary
549
550 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600551 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600552 use_real_dtb: True to use the test file as the contents of
553 the u-boot-dtb entry. Normally this is not needed and the
554 test contents (the U_BOOT_DTB_DATA string) can be used.
555 But in some test we need the real contents.
Simon Glassea6922e2018-07-17 13:25:27 -0600556
557 Returns:
558 Resulting image contents
Simon Glass7ae5f312018-06-01 09:38:19 -0600559 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700560 return self._DoReadFileDtb(fname, use_real_dtb)[0]
561
Simon Glass4f443042016-11-25 20:15:52 -0700562 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600563 def _MakeInputFile(cls, fname, contents):
Simon Glass4f443042016-11-25 20:15:52 -0700564 """Create a new test input file, creating directories as needed
565
566 Args:
Simon Glass3ab95982018-08-01 15:22:37 -0600567 fname: Filename to create
Simon Glass4f443042016-11-25 20:15:52 -0700568 contents: File contents to write in to the file
569 Returns:
570 Full pathname of file created
571 """
Simon Glassb986b3b2019-08-24 07:22:43 -0600572 pathname = os.path.join(cls._indir, fname)
Simon Glass4f443042016-11-25 20:15:52 -0700573 dirname = os.path.dirname(pathname)
574 if dirname and not os.path.exists(dirname):
575 os.makedirs(dirname)
576 with open(pathname, 'wb') as fd:
577 fd.write(contents)
578 return pathname
579
580 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600581 def _MakeInputDir(cls, dirname):
Simon Glass0ef87aa2018-07-17 13:25:44 -0600582 """Create a new test input directory, creating directories as needed
583
584 Args:
585 dirname: Directory name to create
586
587 Returns:
588 Full pathname of directory created
589 """
Simon Glassb986b3b2019-08-24 07:22:43 -0600590 pathname = os.path.join(cls._indir, dirname)
Simon Glass0ef87aa2018-07-17 13:25:44 -0600591 if not os.path.exists(pathname):
592 os.makedirs(pathname)
593 return pathname
594
595 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600596 def _SetupSplElf(cls, src_fname='bss_data'):
Simon Glass11ae93e2018-10-01 21:12:47 -0600597 """Set up an ELF file with a '_dt_ucode_base_size' symbol
598
599 Args:
600 Filename of ELF file to use as SPL
601 """
Simon Glassc9a0b272019-08-24 07:22:59 -0600602 TestFunctional._MakeInputFile('spl/u-boot-spl',
Simon Glassc1aa66e2022-01-29 14:14:04 -0700603 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass11ae93e2018-10-01 21:12:47 -0600604
605 @classmethod
Simon Glass2090f1e2019-08-24 07:23:00 -0600606 def _SetupTplElf(cls, src_fname='bss_data'):
607 """Set up an ELF file with a '_dt_ucode_base_size' symbol
608
609 Args:
610 Filename of ELF file to use as TPL
611 """
612 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
Simon Glassc1aa66e2022-01-29 14:14:04 -0700613 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass2090f1e2019-08-24 07:23:00 -0600614
615 @classmethod
Simon Glass0ba4b3d2020-07-09 18:39:41 -0600616 def _SetupDescriptor(cls):
617 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
618 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
619
620 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600621 def TestFile(cls, fname):
622 return os.path.join(cls._binman_dir, 'test', fname)
Simon Glass4f443042016-11-25 20:15:52 -0700623
Simon Glass53e22bf2019-08-24 07:22:53 -0600624 @classmethod
625 def ElfTestFile(cls, fname):
626 return os.path.join(cls._elf_testdir, fname)
627
Simon Glass4f443042016-11-25 20:15:52 -0700628 def AssertInList(self, grep_list, target):
629 """Assert that at least one of a list of things is in a target
630
631 Args:
632 grep_list: List of strings to check
633 target: Target string
634 """
635 for grep in grep_list:
636 if grep in target:
637 return
Simon Glass1fc62de2019-05-17 22:00:50 -0600638 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass4f443042016-11-25 20:15:52 -0700639
640 def CheckNoGaps(self, entries):
641 """Check that all entries fit together without gaps
642
643 Args:
644 entries: List of entries to check
645 """
Simon Glass3ab95982018-08-01 15:22:37 -0600646 offset = 0
Simon Glass4f443042016-11-25 20:15:52 -0700647 for entry in entries.values():
Simon Glass3ab95982018-08-01 15:22:37 -0600648 self.assertEqual(offset, entry.offset)
649 offset += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700650
Simon Glasse0ff8552016-11-25 20:15:53 -0700651 def GetFdtLen(self, dtb):
Simon Glass7ae5f312018-06-01 09:38:19 -0600652 """Get the totalsize field from a device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700653
654 Args:
Simon Glass7ae5f312018-06-01 09:38:19 -0600655 dtb: Device-tree binary contents
Simon Glasse0ff8552016-11-25 20:15:53 -0700656
657 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600658 Total size of device-tree binary, from the header
Simon Glasse0ff8552016-11-25 20:15:53 -0700659 """
660 return struct.unpack('>L', dtb[4:8])[0]
661
Simon Glass086cec92019-07-08 14:25:27 -0600662 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glass16b8d6b2018-07-06 10:27:42 -0600663 def AddNode(node, path):
664 if node.name != '/':
665 path += '/' + node.name
Simon Glass086cec92019-07-08 14:25:27 -0600666 for prop in node.props.values():
667 if prop.name in prop_names:
668 prop_path = path + ':' + prop.name
669 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
670 prop.value)
Simon Glass16b8d6b2018-07-06 10:27:42 -0600671 for subnode in node.subnodes:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600672 AddNode(subnode, path)
673
674 tree = {}
Simon Glass16b8d6b2018-07-06 10:27:42 -0600675 AddNode(dtb.GetRoot(), '')
676 return tree
677
Simon Glass4f443042016-11-25 20:15:52 -0700678 def testRun(self):
679 """Test a basic run with valid args"""
680 result = self._RunBinman('-h')
681
682 def testFullHelp(self):
683 """Test that the full help is displayed with -H"""
684 result = self._RunBinman('-H')
Simon Glass61adb2d2021-03-18 20:25:13 +1300685 help_file = os.path.join(self._binman_dir, 'README.rst')
Tom Rini3759df02018-01-16 15:29:50 -0500686 # Remove possible extraneous strings
687 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
688 gothelp = result.stdout.replace(extra, '')
689 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass4f443042016-11-25 20:15:52 -0700690 self.assertEqual(0, len(result.stderr))
691 self.assertEqual(0, result.return_code)
692
693 def testFullHelpInternal(self):
694 """Test that the full help is displayed with -H"""
695 try:
696 command.test_result = command.CommandResult()
697 result = self._DoBinman('-H')
Simon Glass61adb2d2021-03-18 20:25:13 +1300698 help_file = os.path.join(self._binman_dir, 'README.rst')
Simon Glass4f443042016-11-25 20:15:52 -0700699 finally:
700 command.test_result = None
701
702 def testHelp(self):
703 """Test that the basic help is displayed with -h"""
704 result = self._RunBinman('-h')
705 self.assertTrue(len(result.stdout) > 200)
706 self.assertEqual(0, len(result.stderr))
707 self.assertEqual(0, result.return_code)
708
Simon Glass4f443042016-11-25 20:15:52 -0700709 def testBoard(self):
710 """Test that we can run it with a specific board"""
Simon Glass741f2d62018-10-01 12:22:30 -0600711 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass4f443042016-11-25 20:15:52 -0700712 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glass63aeaeb2021-03-18 20:25:05 +1300713 result = self._DoBinman('build', '-n', '-b', 'sandbox')
Simon Glass4f443042016-11-25 20:15:52 -0700714 self.assertEqual(0, result)
715
716 def testNeedBoard(self):
717 """Test that we get an error when no board ius supplied"""
718 with self.assertRaises(ValueError) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600719 result = self._DoBinman('build')
Simon Glass4f443042016-11-25 20:15:52 -0700720 self.assertIn("Must provide a board to process (use -b <board>)",
721 str(e.exception))
722
723 def testMissingDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600724 """Test that an invalid device-tree file generates an error"""
Simon Glass4f443042016-11-25 20:15:52 -0700725 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600726 self._RunBinman('build', '-d', 'missing_file')
Simon Glass4f443042016-11-25 20:15:52 -0700727 # We get one error from libfdt, and a different one from fdtget.
728 self.AssertInList(["Couldn't open blob from 'missing_file'",
729 'No such file or directory'], str(e.exception))
730
731 def testBrokenDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600732 """Test that an invalid device-tree source file generates an error
Simon Glass4f443042016-11-25 20:15:52 -0700733
734 Since this is a source file it should be compiled and the error
735 will come from the device-tree compiler (dtc).
736 """
737 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600738 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700739 self.assertIn("FATAL ERROR: Unable to parse input tree",
740 str(e.exception))
741
742 def testMissingNode(self):
743 """Test that a device tree without a 'binman' node generates an error"""
744 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600745 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700746 self.assertIn("does not have a 'binman' node", str(e.exception))
747
748 def testEmpty(self):
749 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glass53cd5d92019-07-08 14:25:29 -0600750 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700751 self.assertEqual(0, len(result.stderr))
752 self.assertEqual(0, result.return_code)
753
754 def testInvalidEntry(self):
755 """Test that an invalid entry is flagged"""
756 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600757 result = self._RunBinman('build', '-d',
Simon Glass741f2d62018-10-01 12:22:30 -0600758 self.TestFile('004_invalid_entry.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700759 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
760 "'/binman/not-a-valid-type'", str(e.exception))
761
762 def testSimple(self):
763 """Test a simple binman with a single file"""
Simon Glass741f2d62018-10-01 12:22:30 -0600764 data = self._DoReadFile('005_simple.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700765 self.assertEqual(U_BOOT_DATA, data)
766
Simon Glass7fe91732017-11-13 18:55:00 -0700767 def testSimpleDebug(self):
768 """Test a simple binman run with debugging enabled"""
Simon Glasse2705fa2019-07-08 14:25:53 -0600769 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass7fe91732017-11-13 18:55:00 -0700770
Simon Glass4f443042016-11-25 20:15:52 -0700771 def testDual(self):
772 """Test that we can handle creating two images
773
774 This also tests image padding.
775 """
Simon Glass741f2d62018-10-01 12:22:30 -0600776 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700777 self.assertEqual(0, retcode)
778
779 image = control.images['image1']
Simon Glass8beb11e2019-07-08 14:25:47 -0600780 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glassc1aa66e2022-01-29 14:14:04 -0700781 fname = tools.get_output_filename('image1.bin')
Simon Glass4f443042016-11-25 20:15:52 -0700782 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600783 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700784 data = fd.read()
785 self.assertEqual(U_BOOT_DATA, data)
786
787 image = control.images['image2']
Simon Glass8beb11e2019-07-08 14:25:47 -0600788 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glassc1aa66e2022-01-29 14:14:04 -0700789 fname = tools.get_output_filename('image2.bin')
Simon Glass4f443042016-11-25 20:15:52 -0700790 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600791 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700792 data = fd.read()
793 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glassc1aa66e2022-01-29 14:14:04 -0700794 self.assertEqual(tools.get_bytes(0, 3), data[:3])
795 self.assertEqual(tools.get_bytes(0, 5), data[7:])
Simon Glass4f443042016-11-25 20:15:52 -0700796
797 def testBadAlign(self):
798 """Test that an invalid alignment value is detected"""
799 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600800 self._DoTestFile('007_bad_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700801 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
802 "of two", str(e.exception))
803
804 def testPackSimple(self):
805 """Test that packing works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600806 retcode = self._DoTestFile('008_pack.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700807 self.assertEqual(0, retcode)
808 self.assertIn('image', control.images)
809 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600810 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700811 self.assertEqual(5, len(entries))
812
813 # First u-boot
814 self.assertIn('u-boot', entries)
815 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600816 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700817 self.assertEqual(len(U_BOOT_DATA), entry.size)
818
819 # Second u-boot, aligned to 16-byte boundary
820 self.assertIn('u-boot-align', entries)
821 entry = entries['u-boot-align']
Simon Glass3ab95982018-08-01 15:22:37 -0600822 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700823 self.assertEqual(len(U_BOOT_DATA), entry.size)
824
825 # Third u-boot, size 23 bytes
826 self.assertIn('u-boot-size', entries)
827 entry = entries['u-boot-size']
Simon Glass3ab95982018-08-01 15:22:37 -0600828 self.assertEqual(20, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700829 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
830 self.assertEqual(23, entry.size)
831
832 # Fourth u-boot, placed immediate after the above
833 self.assertIn('u-boot-next', entries)
834 entry = entries['u-boot-next']
Simon Glass3ab95982018-08-01 15:22:37 -0600835 self.assertEqual(43, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700836 self.assertEqual(len(U_BOOT_DATA), entry.size)
837
Simon Glass3ab95982018-08-01 15:22:37 -0600838 # Fifth u-boot, placed at a fixed offset
Simon Glass4f443042016-11-25 20:15:52 -0700839 self.assertIn('u-boot-fixed', entries)
840 entry = entries['u-boot-fixed']
Simon Glass3ab95982018-08-01 15:22:37 -0600841 self.assertEqual(61, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700842 self.assertEqual(len(U_BOOT_DATA), entry.size)
843
Simon Glass8beb11e2019-07-08 14:25:47 -0600844 self.assertEqual(65, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700845
846 def testPackExtra(self):
847 """Test that extra packing feature works as expected"""
Simon Glass4eec34c2020-10-26 17:40:10 -0600848 data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
849 update_dtb=True)
Simon Glass4f443042016-11-25 20:15:52 -0700850
Simon Glass4f443042016-11-25 20:15:52 -0700851 self.assertIn('image', control.images)
852 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600853 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700854 self.assertEqual(5, len(entries))
855
856 # First u-boot with padding before and after
857 self.assertIn('u-boot', entries)
858 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600859 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700860 self.assertEqual(3, entry.pad_before)
861 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600862 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassc1aa66e2022-01-29 14:14:04 -0700863 self.assertEqual(tools.get_bytes(0, 3) + U_BOOT_DATA +
864 tools.get_bytes(0, 5), data[:entry.size])
Simon Glassef439ed2020-10-26 17:40:08 -0600865 pos = entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700866
867 # Second u-boot has an aligned size, but it has no effect
868 self.assertIn('u-boot-align-size-nop', entries)
869 entry = entries['u-boot-align-size-nop']
Simon Glassef439ed2020-10-26 17:40:08 -0600870 self.assertEqual(pos, entry.offset)
871 self.assertEqual(len(U_BOOT_DATA), entry.size)
872 self.assertEqual(U_BOOT_DATA, entry.data)
873 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
874 pos += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700875
876 # Third u-boot has an aligned size too
877 self.assertIn('u-boot-align-size', entries)
878 entry = entries['u-boot-align-size']
Simon Glassef439ed2020-10-26 17:40:08 -0600879 self.assertEqual(pos, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700880 self.assertEqual(32, entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600881 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassc1aa66e2022-01-29 14:14:04 -0700882 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
Simon Glassef439ed2020-10-26 17:40:08 -0600883 data[pos:pos + entry.size])
884 pos += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700885
886 # Fourth u-boot has an aligned end
887 self.assertIn('u-boot-align-end', entries)
888 entry = entries['u-boot-align-end']
Simon Glass3ab95982018-08-01 15:22:37 -0600889 self.assertEqual(48, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700890 self.assertEqual(16, entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600891 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glassc1aa66e2022-01-29 14:14:04 -0700892 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 16 - len(U_BOOT_DATA)),
Simon Glassef439ed2020-10-26 17:40:08 -0600893 data[pos:pos + entry.size])
894 pos += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700895
896 # Fifth u-boot immediately afterwards
897 self.assertIn('u-boot-align-both', entries)
898 entry = entries['u-boot-align-both']
Simon Glass3ab95982018-08-01 15:22:37 -0600899 self.assertEqual(64, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700900 self.assertEqual(64, entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600901 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glassc1aa66e2022-01-29 14:14:04 -0700902 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 64 - len(U_BOOT_DATA)),
Simon Glassef439ed2020-10-26 17:40:08 -0600903 data[pos:pos + entry.size])
Simon Glass4f443042016-11-25 20:15:52 -0700904
905 self.CheckNoGaps(entries)
Simon Glass8beb11e2019-07-08 14:25:47 -0600906 self.assertEqual(128, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700907
Simon Glass4eec34c2020-10-26 17:40:10 -0600908 dtb = fdt.Fdt(out_dtb_fname)
909 dtb.Scan()
910 props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
911 expected = {
912 'image-pos': 0,
913 'offset': 0,
914 'size': 128,
915
916 'u-boot:image-pos': 0,
917 'u-boot:offset': 0,
918 'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
919
920 'u-boot-align-size-nop:image-pos': 12,
921 'u-boot-align-size-nop:offset': 12,
922 'u-boot-align-size-nop:size': 4,
923
924 'u-boot-align-size:image-pos': 16,
925 'u-boot-align-size:offset': 16,
926 'u-boot-align-size:size': 32,
927
928 'u-boot-align-end:image-pos': 48,
929 'u-boot-align-end:offset': 48,
930 'u-boot-align-end:size': 16,
931
932 'u-boot-align-both:image-pos': 64,
933 'u-boot-align-both:offset': 64,
934 'u-boot-align-both:size': 64,
935 }
936 self.assertEqual(expected, props)
937
Simon Glass4f443042016-11-25 20:15:52 -0700938 def testPackAlignPowerOf2(self):
939 """Test that invalid entry alignment is detected"""
940 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600941 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700942 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
943 "of two", str(e.exception))
944
945 def testPackAlignSizePowerOf2(self):
946 """Test that invalid entry size alignment is detected"""
947 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600948 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700949 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
950 "power of two", str(e.exception))
951
952 def testPackInvalidAlign(self):
Simon Glass3ab95982018-08-01 15:22:37 -0600953 """Test detection of an offset that does not match its alignment"""
Simon Glass4f443042016-11-25 20:15:52 -0700954 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600955 self._DoTestFile('012_pack_inv_align.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600956 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700957 "align 0x4 (4)", str(e.exception))
958
959 def testPackInvalidSizeAlign(self):
960 """Test that invalid entry size alignment is detected"""
961 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600962 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700963 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
964 "align-size 0x4 (4)", str(e.exception))
965
966 def testPackOverlap(self):
967 """Test that overlapping regions are detected"""
968 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600969 self._DoTestFile('014_pack_overlap.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600970 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -0700971 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
972 str(e.exception))
973
974 def testPackEntryOverflow(self):
975 """Test that entries that overflow their size are detected"""
976 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600977 self._DoTestFile('015_pack_overflow.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700978 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
979 "but entry size is 0x3 (3)", str(e.exception))
980
981 def testPackImageOverflow(self):
982 """Test that entries which overflow the image size are detected"""
983 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600984 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600985 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass4f443042016-11-25 20:15:52 -0700986 "size 0x3 (3)", str(e.exception))
987
988 def testPackImageSize(self):
989 """Test that the image size can be set"""
Simon Glass741f2d62018-10-01 12:22:30 -0600990 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700991 self.assertEqual(0, retcode)
992 self.assertIn('image', control.images)
993 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -0600994 self.assertEqual(7, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700995
996 def testPackImageSizeAlign(self):
997 """Test that image size alignemnt works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600998 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700999 self.assertEqual(0, retcode)
1000 self.assertIn('image', control.images)
1001 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -06001002 self.assertEqual(16, image.size)
Simon Glass4f443042016-11-25 20:15:52 -07001003
1004 def testPackInvalidImageAlign(self):
1005 """Test that invalid image alignment is detected"""
1006 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001007 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glass8f1da502018-06-01 09:38:12 -06001008 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass4f443042016-11-25 20:15:52 -07001009 "align-size 0x8 (8)", str(e.exception))
1010
Simon Glass8d2ef3e2022-02-11 13:23:21 -07001011 def testPackAlignPowerOf2Inv(self):
Simon Glass4f443042016-11-25 20:15:52 -07001012 """Test that invalid image alignment is detected"""
1013 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001014 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -06001015 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass4f443042016-11-25 20:15:52 -07001016 "two", str(e.exception))
1017
1018 def testImagePadByte(self):
1019 """Test that the image pad byte can be specified"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001020 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001021 data = self._DoReadFile('021_image_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001022 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0xff, 1) +
Simon Glasse6d85ff2019-05-14 15:53:47 -06001023 U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -07001024
1025 def testImageName(self):
1026 """Test that image files can be named"""
Simon Glass741f2d62018-10-01 12:22:30 -06001027 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001028 self.assertEqual(0, retcode)
1029 image = control.images['image1']
Simon Glassc1aa66e2022-01-29 14:14:04 -07001030 fname = tools.get_output_filename('test-name')
Simon Glass4f443042016-11-25 20:15:52 -07001031 self.assertTrue(os.path.exists(fname))
1032
1033 image = control.images['image2']
Simon Glassc1aa66e2022-01-29 14:14:04 -07001034 fname = tools.get_output_filename('test-name.xx')
Simon Glass4f443042016-11-25 20:15:52 -07001035 self.assertTrue(os.path.exists(fname))
1036
1037 def testBlobFilename(self):
1038 """Test that generic blobs can be provided by filename"""
Simon Glass741f2d62018-10-01 12:22:30 -06001039 data = self._DoReadFile('023_blob.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001040 self.assertEqual(BLOB_DATA, data)
1041
1042 def testPackSorted(self):
1043 """Test that entries can be sorted"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001044 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001045 data = self._DoReadFile('024_sorted.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001046 self.assertEqual(tools.get_bytes(0, 1) + U_BOOT_SPL_DATA +
1047 tools.get_bytes(0, 2) + U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -07001048
Simon Glass3ab95982018-08-01 15:22:37 -06001049 def testPackZeroOffset(self):
1050 """Test that an entry at offset 0 is not given a new offset"""
Simon Glass4f443042016-11-25 20:15:52 -07001051 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001052 self._DoTestFile('025_pack_zero_size.dts')
Simon Glass3ab95982018-08-01 15:22:37 -06001053 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -07001054 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1055 str(e.exception))
1056
1057 def testPackUbootDtb(self):
1058 """Test that a device tree can be added to U-Boot"""
Simon Glass741f2d62018-10-01 12:22:30 -06001059 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001060 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glasse0ff8552016-11-25 20:15:53 -07001061
1062 def testPackX86RomNoSize(self):
1063 """Test that the end-at-4gb property requires a size property"""
1064 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001065 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -06001066 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glasse0ff8552016-11-25 20:15:53 -07001067 "using end-at-4gb", str(e.exception))
1068
Jagdish Gediya94b57db2018-09-03 21:35:07 +05301069 def test4gbAndSkipAtStartTogether(self):
1070 """Test that the end-at-4gb and skip-at-size property can't be used
1071 together"""
1072 with self.assertRaises(ValueError) as e:
Simon Glassdfdd2b62019-08-24 07:23:02 -06001073 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -06001074 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya94b57db2018-09-03 21:35:07 +05301075 "'skip-at-start'", str(e.exception))
1076
Simon Glasse0ff8552016-11-25 20:15:53 -07001077 def testPackX86RomOutside(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001078 """Test that the end-at-4gb property checks for offset boundaries"""
Simon Glasse0ff8552016-11-25 20:15:53 -07001079 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001080 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glasse6bed4f2020-10-26 17:40:05 -06001081 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
1082 "is outside the section '/binman' starting at "
1083 '0xffffffe0 (4294967264) of size 0x20 (32)',
Simon Glasse0ff8552016-11-25 20:15:53 -07001084 str(e.exception))
1085
1086 def testPackX86Rom(self):
1087 """Test that a basic x86 ROM can be created"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001088 self._SetupSplElf()
Simon Glass9255f3c2019-08-24 07:23:01 -06001089 data = self._DoReadFile('029_x86_rom.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001090 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 3) + U_BOOT_SPL_DATA +
1091 tools.get_bytes(0, 2), data)
Simon Glasse0ff8552016-11-25 20:15:53 -07001092
1093 def testPackX86RomMeNoDesc(self):
1094 """Test that an invalid Intel descriptor entry is detected"""
Simon Glass0ba4b3d2020-07-09 18:39:41 -06001095 try:
Simon Glass52b10dd2020-07-25 15:11:19 -06001096 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
Simon Glass0ba4b3d2020-07-09 18:39:41 -06001097 with self.assertRaises(ValueError) as e:
Simon Glass52b10dd2020-07-25 15:11:19 -06001098 self._DoTestFile('163_x86_rom_me_empty.dts')
Simon Glass0ba4b3d2020-07-09 18:39:41 -06001099 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1100 str(e.exception))
1101 finally:
1102 self._SetupDescriptor()
Simon Glasse0ff8552016-11-25 20:15:53 -07001103
1104 def testPackX86RomBadDesc(self):
1105 """Test that the Intel requires a descriptor entry"""
1106 with self.assertRaises(ValueError) as e:
Simon Glass9255f3c2019-08-24 07:23:01 -06001107 self._DoTestFile('030_x86_rom_me_no_desc.dts')
Simon Glass3ab95982018-08-01 15:22:37 -06001108 self.assertIn("Node '/binman/intel-me': No offset set with "
1109 "offset-unset: should another entry provide this correct "
1110 "offset?", str(e.exception))
Simon Glasse0ff8552016-11-25 20:15:53 -07001111
1112 def testPackX86RomMe(self):
1113 """Test that an x86 ROM with an ME region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001114 data = self._DoReadFile('031_x86_rom_me.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001115 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glassc5ac1382019-07-08 13:18:54 -06001116 if data[:0x1000] != expected_desc:
1117 self.fail('Expected descriptor binary at start of image')
Simon Glasse0ff8552016-11-25 20:15:53 -07001118 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1119
1120 def testPackVga(self):
1121 """Test that an image with a VGA binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001122 data = self._DoReadFile('032_intel_vga.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -07001123 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1124
1125 def testPackStart16(self):
1126 """Test that an image with an x86 start16 region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001127 data = self._DoReadFile('033_x86_start16.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -07001128 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1129
Jagdish Gediya9d368f32018-09-03 21:35:08 +05301130 def testPackPowerpcMpc85xxBootpgResetvec(self):
1131 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1132 created"""
Simon Glassdfdd2b62019-08-24 07:23:02 -06001133 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
Jagdish Gediya9d368f32018-09-03 21:35:08 +05301134 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1135
Simon Glass736bb0a2018-07-06 10:27:17 -06001136 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glassadc57012018-07-06 10:27:16 -06001137 """Handle running a test for insertion of microcode
1138
1139 Args:
1140 dts_fname: Name of test .dts file
1141 nodtb_data: Data that we expect in the first section
Simon Glass736bb0a2018-07-06 10:27:17 -06001142 ucode_second: True if the microsecond entry is second instead of
1143 third
Simon Glassadc57012018-07-06 10:27:16 -06001144
1145 Returns:
1146 Tuple:
1147 Contents of first region (U-Boot or SPL)
Simon Glass3ab95982018-08-01 15:22:37 -06001148 Offset and size components of microcode pointer, as inserted
Simon Glassadc57012018-07-06 10:27:16 -06001149 in the above (two 4-byte words)
1150 """
Simon Glass6b187df2017-11-12 21:52:27 -07001151 data = self._DoReadFile(dts_fname, True)
Simon Glasse0ff8552016-11-25 20:15:53 -07001152
1153 # Now check the device tree has no microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001154 if ucode_second:
1155 ucode_content = data[len(nodtb_data):]
1156 ucode_pos = len(nodtb_data)
1157 dtb_with_ucode = ucode_content[16:]
1158 fdt_len = self.GetFdtLen(dtb_with_ucode)
1159 else:
1160 dtb_with_ucode = data[len(nodtb_data):]
1161 fdt_len = self.GetFdtLen(dtb_with_ucode)
1162 ucode_content = dtb_with_ucode[fdt_len:]
1163 ucode_pos = len(nodtb_data) + fdt_len
Simon Glassc1aa66e2022-01-29 14:14:04 -07001164 fname = tools.get_output_filename('test.dtb')
Simon Glasse0ff8552016-11-25 20:15:53 -07001165 with open(fname, 'wb') as fd:
Simon Glassadc57012018-07-06 10:27:16 -06001166 fd.write(dtb_with_ucode)
Simon Glassec3f3782017-05-27 07:38:29 -06001167 dtb = fdt.FdtScan(fname)
1168 ucode = dtb.GetNode('/microcode')
Simon Glasse0ff8552016-11-25 20:15:53 -07001169 self.assertTrue(ucode)
1170 for node in ucode.subnodes:
1171 self.assertFalse(node.props.get('data'))
1172
Simon Glasse0ff8552016-11-25 20:15:53 -07001173 # Check that the microcode appears immediately after the Fdt
1174 # This matches the concatenation of the data properties in
Simon Glass87722132017-11-12 21:52:26 -07001175 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glasse0ff8552016-11-25 20:15:53 -07001176 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1177 0x78235609)
Simon Glassadc57012018-07-06 10:27:16 -06001178 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glasse0ff8552016-11-25 20:15:53 -07001179
1180 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -06001181 # expected offset and size
Simon Glasse0ff8552016-11-25 20:15:53 -07001182 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1183 len(ucode_data))
Simon Glass736bb0a2018-07-06 10:27:17 -06001184 u_boot = data[:len(nodtb_data)]
1185 return u_boot, pos_and_size
Simon Glass6b187df2017-11-12 21:52:27 -07001186
1187 def testPackUbootMicrocode(self):
1188 """Test that x86 microcode can be handled correctly
1189
1190 We expect to see the following in the image, in order:
1191 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1192 place
1193 u-boot.dtb with the microcode removed
1194 the microcode
1195 """
Simon Glass741f2d62018-10-01 12:22:30 -06001196 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass6b187df2017-11-12 21:52:27 -07001197 U_BOOT_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001198 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1199 b' somewhere in here', first)
Simon Glasse0ff8552016-11-25 20:15:53 -07001200
Simon Glass160a7662017-05-27 07:38:26 -06001201 def _RunPackUbootSingleMicrocode(self):
Simon Glasse0ff8552016-11-25 20:15:53 -07001202 """Test that x86 microcode can be handled correctly
1203
1204 We expect to see the following in the image, in order:
1205 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1206 place
1207 u-boot.dtb with the microcode
1208 an empty microcode region
1209 """
1210 # We need the libfdt library to run this test since only that allows
1211 # finding the offset of a property. This is required by
1212 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass741f2d62018-10-01 12:22:30 -06001213 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glasse0ff8552016-11-25 20:15:53 -07001214
1215 second = data[len(U_BOOT_NODTB_DATA):]
1216
1217 fdt_len = self.GetFdtLen(second)
1218 third = second[fdt_len:]
1219 second = second[:fdt_len]
1220
Simon Glass160a7662017-05-27 07:38:26 -06001221 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1222 self.assertIn(ucode_data, second)
1223 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -07001224
Simon Glass160a7662017-05-27 07:38:26 -06001225 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -06001226 # expected offset and size
Simon Glass160a7662017-05-27 07:38:26 -06001227 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1228 len(ucode_data))
1229 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glassc6c10e72019-05-17 22:00:46 -06001230 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1231 b' somewhere in here', first)
Simon Glassc49deb82016-11-25 20:15:54 -07001232
Simon Glass75db0862016-11-25 20:15:55 -07001233 def testPackUbootSingleMicrocode(self):
1234 """Test that x86 microcode can be handled correctly with fdt_normal.
1235 """
Simon Glass160a7662017-05-27 07:38:26 -06001236 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001237
Simon Glassc49deb82016-11-25 20:15:54 -07001238 def testUBootImg(self):
1239 """Test that u-boot.img can be put in a file"""
Simon Glass741f2d62018-10-01 12:22:30 -06001240 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glassc49deb82016-11-25 20:15:54 -07001241 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glass75db0862016-11-25 20:15:55 -07001242
1243 def testNoMicrocode(self):
1244 """Test that a missing microcode region is detected"""
1245 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001246 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001247 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1248 "node found in ", str(e.exception))
1249
1250 def testMicrocodeWithoutNode(self):
1251 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1252 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001253 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001254 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1255 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1256
1257 def testMicrocodeWithoutNode2(self):
1258 """Test that a missing u-boot-ucode node is detected"""
1259 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001260 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001261 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1262 "microcode region u-boot-ucode", str(e.exception))
1263
1264 def testMicrocodeWithoutPtrInElf(self):
1265 """Test that a U-Boot binary without the microcode symbol is detected"""
1266 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glass75db0862016-11-25 20:15:55 -07001267 try:
Simon Glassbccd91d2019-08-24 07:22:55 -06001268 TestFunctional._MakeInputFile('u-boot',
Simon Glassc1aa66e2022-01-29 14:14:04 -07001269 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass75db0862016-11-25 20:15:55 -07001270
1271 with self.assertRaises(ValueError) as e:
Simon Glass160a7662017-05-27 07:38:26 -06001272 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001273 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1274 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1275
1276 finally:
1277 # Put the original file back
Simon Glassf514d8f2019-08-24 07:22:54 -06001278 TestFunctional._MakeInputFile('u-boot',
Simon Glassc1aa66e2022-01-29 14:14:04 -07001279 tools.read_file(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glass75db0862016-11-25 20:15:55 -07001280
1281 def testMicrocodeNotInImage(self):
1282 """Test that microcode must be placed within the image"""
1283 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001284 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001285 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1286 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glass25ac0e62018-06-01 09:38:14 -06001287 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glass75db0862016-11-25 20:15:55 -07001288
1289 def testWithoutMicrocode(self):
1290 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glassbccd91d2019-08-24 07:22:55 -06001291 TestFunctional._MakeInputFile('u-boot',
Simon Glassc1aa66e2022-01-29 14:14:04 -07001292 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass741f2d62018-10-01 12:22:30 -06001293 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001294
1295 # Now check the device tree has no microcode
1296 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1297 second = data[len(U_BOOT_NODTB_DATA):]
1298
1299 fdt_len = self.GetFdtLen(second)
1300 self.assertEqual(dtb, second[:fdt_len])
1301
1302 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1303 third = data[used_len:]
Simon Glassc1aa66e2022-01-29 14:14:04 -07001304 self.assertEqual(tools.get_bytes(0, 0x200 - used_len), third)
Simon Glass75db0862016-11-25 20:15:55 -07001305
1306 def testUnknownPosSize(self):
1307 """Test that microcode must be placed within the image"""
1308 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001309 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glass3ab95982018-08-01 15:22:37 -06001310 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glass75db0862016-11-25 20:15:55 -07001311 "entry 'invalid-entry'", str(e.exception))
Simon Glassda229092016-11-25 20:15:56 -07001312
1313 def testPackFsp(self):
1314 """Test that an image with a FSP binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001315 data = self._DoReadFile('042_intel_fsp.dts')
Simon Glassda229092016-11-25 20:15:56 -07001316 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1317
1318 def testPackCmc(self):
Bin Meng59ea8c22017-08-15 22:41:54 -07001319 """Test that an image with a CMC binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001320 data = self._DoReadFile('043_intel_cmc.dts')
Simon Glassda229092016-11-25 20:15:56 -07001321 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Meng59ea8c22017-08-15 22:41:54 -07001322
1323 def testPackVbt(self):
1324 """Test that an image with a VBT binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001325 data = self._DoReadFile('046_intel_vbt.dts')
Bin Meng59ea8c22017-08-15 22:41:54 -07001326 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glass9fc60b42017-11-12 21:52:22 -07001327
Simon Glass56509842017-11-12 21:52:25 -07001328 def testSplBssPad(self):
1329 """Test that we can pad SPL's BSS with zeros"""
Simon Glass6b187df2017-11-12 21:52:27 -07001330 # ELF file with a '__bss_size' symbol
Simon Glass11ae93e2018-10-01 21:12:47 -06001331 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001332 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001333 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glasse6d85ff2019-05-14 15:53:47 -06001334 data)
Simon Glass56509842017-11-12 21:52:25 -07001335
Simon Glass86af5112018-10-01 21:12:42 -06001336 def testSplBssPadMissing(self):
1337 """Test that a missing symbol is detected"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001338 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glassb50e5612017-11-13 18:54:54 -07001339 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001340 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassb50e5612017-11-13 18:54:54 -07001341 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1342 str(e.exception))
1343
Simon Glass87722132017-11-12 21:52:26 -07001344 def testPackStart16Spl(self):
Simon Glass35b384c2018-09-14 04:57:10 -06001345 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001346 data = self._DoReadFile('048_x86_start16_spl.dts')
Simon Glass87722132017-11-12 21:52:26 -07001347 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1348
Simon Glass736bb0a2018-07-06 10:27:17 -06001349 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1350 """Helper function for microcode tests
Simon Glass6b187df2017-11-12 21:52:27 -07001351
1352 We expect to see the following in the image, in order:
1353 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1354 correct place
1355 u-boot.dtb with the microcode removed
1356 the microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001357
1358 Args:
1359 dts: Device tree file to use for test
1360 ucode_second: True if the microsecond entry is second instead of
1361 third
Simon Glass6b187df2017-11-12 21:52:27 -07001362 """
Simon Glass11ae93e2018-10-01 21:12:47 -06001363 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass736bb0a2018-07-06 10:27:17 -06001364 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1365 ucode_second=ucode_second)
Simon Glassc6c10e72019-05-17 22:00:46 -06001366 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1367 b'ter somewhere in here', first)
Simon Glass6b187df2017-11-12 21:52:27 -07001368
Simon Glass736bb0a2018-07-06 10:27:17 -06001369 def testPackUbootSplMicrocode(self):
1370 """Test that x86 microcode can be handled correctly in SPL"""
Simon Glass741f2d62018-10-01 12:22:30 -06001371 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass736bb0a2018-07-06 10:27:17 -06001372
1373 def testPackUbootSplMicrocodeReorder(self):
1374 """Test that order doesn't matter for microcode entries
1375
1376 This is the same as testPackUbootSplMicrocode but when we process the
1377 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1378 entry, so we reply on binman to try later.
1379 """
Simon Glass741f2d62018-10-01 12:22:30 -06001380 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass736bb0a2018-07-06 10:27:17 -06001381 ucode_second=True)
1382
Simon Glassca4f4ff2017-11-12 21:52:28 -07001383 def testPackMrc(self):
1384 """Test that an image with an MRC binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001385 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassca4f4ff2017-11-12 21:52:28 -07001386 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1387
Simon Glass47419ea2017-11-13 18:54:55 -07001388 def testSplDtb(self):
1389 """Test that an image with spl/u-boot-spl.dtb can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001390 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass47419ea2017-11-13 18:54:55 -07001391 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1392
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001393 def testSplNoDtb(self):
1394 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass0fe44dc2021-04-25 08:39:32 +12001395 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001396 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001397 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1398
Simon Glass3d433382021-03-21 18:24:30 +13001399 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
1400 use_expanded=False):
Simon Glassf5898822021-03-18 20:24:56 +13001401 """Check the image contains the expected symbol values
1402
1403 Args:
1404 dts: Device tree file to use for test
1405 base_data: Data before and after 'u-boot' section
1406 u_boot_offset: Offset of 'u-boot' section in image
Simon Glass3d433382021-03-21 18:24:30 +13001407 entry_args: Dict of entry args to supply to binman
1408 key: arg name
1409 value: value of that arg
1410 use_expanded: True to use expanded entries where available, e.g.
1411 'u-boot-expanded' instead of 'u-boot'
Simon Glassf5898822021-03-18 20:24:56 +13001412 """
Simon Glass1542c8b2019-08-24 07:22:56 -06001413 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass19790632017-11-13 18:55:01 -07001414 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1415 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03001416 self.assertEqual(syms['_binman_sym_magic'].address, addr)
Simon Glassf5898822021-03-18 20:24:56 +13001417 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03001418 addr + 4)
Simon Glass19790632017-11-13 18:55:01 -07001419
Simon Glass11ae93e2018-10-01 21:12:47 -06001420 self._SetupSplElf('u_boot_binman_syms')
Simon Glass3d433382021-03-21 18:24:30 +13001421 data = self._DoReadFileDtb(dts, entry_args=entry_args,
1422 use_expanded=use_expanded)[0]
Simon Glassf5898822021-03-18 20:24:56 +13001423 # The image should contain the symbols from u_boot_binman_syms.c
1424 # Note that image_pos is adjusted by the base address of the image,
1425 # which is 0x10 in our test image
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03001426 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE,
1427 0x00, u_boot_offset + len(U_BOOT_DATA),
Simon Glassf5898822021-03-18 20:24:56 +13001428 0x10 + u_boot_offset, 0x04)
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03001429 expected = (sym_values + base_data[24:] +
Simon Glassc1aa66e2022-01-29 14:14:04 -07001430 tools.get_bytes(0xff, 1) + U_BOOT_DATA + sym_values +
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03001431 base_data[24:])
Simon Glass19790632017-11-13 18:55:01 -07001432 self.assertEqual(expected, data)
1433
Simon Glassf5898822021-03-18 20:24:56 +13001434 def testSymbols(self):
1435 """Test binman can assign symbols embedded in U-Boot"""
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03001436 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glassf5898822021-03-18 20:24:56 +13001437
1438 def testSymbolsNoDtb(self):
1439 """Test binman can assign symbols embedded in U-Boot SPL"""
Simon Glasse9e0db82021-03-21 18:24:29 +13001440 self.checkSymbols('196_symbols_nodtb.dts',
Simon Glassf5898822021-03-18 20:24:56 +13001441 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1442 0x38)
1443
Simon Glassdd57c132018-06-01 09:38:11 -06001444 def testPackUnitAddress(self):
1445 """Test that we support multiple binaries with the same name"""
Simon Glass741f2d62018-10-01 12:22:30 -06001446 data = self._DoReadFile('054_unit_address.dts')
Simon Glassdd57c132018-06-01 09:38:11 -06001447 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1448
Simon Glass18546952018-06-01 09:38:16 -06001449 def testSections(self):
1450 """Basic test of sections"""
Simon Glass741f2d62018-10-01 12:22:30 -06001451 data = self._DoReadFile('055_sections.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001452 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1453 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
1454 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glass18546952018-06-01 09:38:16 -06001455 self.assertEqual(expected, data)
Simon Glass9fc60b42017-11-12 21:52:22 -07001456
Simon Glass3b0c38212018-06-01 09:38:20 -06001457 def testMap(self):
1458 """Tests outputting a map of the images"""
Simon Glass741f2d62018-10-01 12:22:30 -06001459 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001460 self.assertEqual('''ImagePos Offset Size Name
146100000000 00000000 00000028 main-section
146200000000 00000000 00000010 section@0
146300000000 00000000 00000004 u-boot
146400000010 00000010 00000010 section@1
146500000010 00000000 00000004 u-boot
146600000020 00000020 00000004 section@2
146700000020 00000000 00000004 u-boot
Simon Glass3b0c38212018-06-01 09:38:20 -06001468''', map_data)
1469
Simon Glassc8d48ef2018-06-01 09:38:21 -06001470 def testNamePrefix(self):
1471 """Tests that name prefixes are used"""
Simon Glass741f2d62018-10-01 12:22:30 -06001472 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001473 self.assertEqual('''ImagePos Offset Size Name
147400000000 00000000 00000028 main-section
147500000000 00000000 00000010 section@0
147600000000 00000000 00000004 ro-u-boot
147700000010 00000010 00000010 section@1
147800000010 00000000 00000004 rw-u-boot
Simon Glassc8d48ef2018-06-01 09:38:21 -06001479''', map_data)
1480
Simon Glass736bb0a2018-07-06 10:27:17 -06001481 def testUnknownContents(self):
1482 """Test that obtaining the contents works as expected"""
1483 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001484 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass8beb11e2019-07-08 14:25:47 -06001485 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glass16287932020-04-17 18:09:03 -06001486 "processing of contents: remaining ["
1487 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass736bb0a2018-07-06 10:27:17 -06001488
Simon Glass5c890232018-07-06 10:27:19 -06001489 def testBadChangeSize(self):
1490 """Test that trying to change the size of an entry fails"""
Simon Glassc52c9e72019-07-08 14:25:37 -06001491 try:
1492 state.SetAllowEntryExpansion(False)
1493 with self.assertRaises(ValueError) as e:
1494 self._DoReadFile('059_change_size.dts', True)
Simon Glass79d3c582019-07-20 12:23:57 -06001495 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glassc52c9e72019-07-08 14:25:37 -06001496 str(e.exception))
1497 finally:
1498 state.SetAllowEntryExpansion(True)
Simon Glass5c890232018-07-06 10:27:19 -06001499
Simon Glass16b8d6b2018-07-06 10:27:42 -06001500 def testUpdateFdt(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001501 """Test that we can update the device tree with offset/size info"""
Simon Glass741f2d62018-10-01 12:22:30 -06001502 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glass16b8d6b2018-07-06 10:27:42 -06001503 update_dtb=True)
Simon Glasscee02e62018-07-17 13:25:52 -06001504 dtb = fdt.Fdt(out_dtb_fname)
1505 dtb.Scan()
Simon Glass12bb1a92019-07-20 12:23:51 -06001506 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001507 self.assertEqual({
Simon Glassdbf6be92018-08-01 15:22:42 -06001508 'image-pos': 0,
Simon Glass8122f392018-07-17 13:25:28 -06001509 'offset': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001510 '_testing:offset': 32,
Simon Glass79d3c582019-07-20 12:23:57 -06001511 '_testing:size': 2,
Simon Glassdbf6be92018-08-01 15:22:42 -06001512 '_testing:image-pos': 32,
Simon Glass3ab95982018-08-01 15:22:37 -06001513 'section@0/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001514 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001515 'section@0/u-boot:image-pos': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001516 'section@0:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001517 'section@0:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001518 'section@0:image-pos': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001519
Simon Glass3ab95982018-08-01 15:22:37 -06001520 'section@1/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001521 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001522 'section@1/u-boot:image-pos': 16,
Simon Glass3ab95982018-08-01 15:22:37 -06001523 'section@1:offset': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001524 'section@1:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001525 'section@1:image-pos': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001526 'size': 40
1527 }, props)
1528
1529 def testUpdateFdtBad(self):
1530 """Test that we detect when ProcessFdt never completes"""
1531 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001532 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001533 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glass16287932020-04-17 18:09:03 -06001534 '[<binman.etype._testing.Entry__testing',
1535 str(e.exception))
Simon Glass5c890232018-07-06 10:27:19 -06001536
Simon Glass53af22a2018-07-17 13:25:32 -06001537 def testEntryArgs(self):
1538 """Test passing arguments to entries from the command line"""
1539 entry_args = {
1540 'test-str-arg': 'test1',
1541 'test-int-arg': '456',
1542 }
Simon Glass741f2d62018-10-01 12:22:30 -06001543 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001544 self.assertIn('image', control.images)
1545 entry = control.images['image'].GetEntries()['_testing']
1546 self.assertEqual('test0', entry.test_str_fdt)
1547 self.assertEqual('test1', entry.test_str_arg)
1548 self.assertEqual(123, entry.test_int_fdt)
1549 self.assertEqual(456, entry.test_int_arg)
1550
1551 def testEntryArgsMissing(self):
1552 """Test missing arguments and properties"""
1553 entry_args = {
1554 'test-int-arg': '456',
1555 }
Simon Glass741f2d62018-10-01 12:22:30 -06001556 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001557 entry = control.images['image'].GetEntries()['_testing']
1558 self.assertEqual('test0', entry.test_str_fdt)
1559 self.assertEqual(None, entry.test_str_arg)
1560 self.assertEqual(None, entry.test_int_fdt)
1561 self.assertEqual(456, entry.test_int_arg)
1562
1563 def testEntryArgsRequired(self):
1564 """Test missing arguments and properties"""
1565 entry_args = {
1566 'test-int-arg': '456',
1567 }
1568 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001569 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass3decfa32020-09-01 05:13:54 -06001570 self.assertIn("Node '/binman/_testing': "
1571 'Missing required properties/entry args: test-str-arg, '
1572 'test-int-fdt, test-int-arg',
Simon Glass53af22a2018-07-17 13:25:32 -06001573 str(e.exception))
1574
1575 def testEntryArgsInvalidFormat(self):
1576 """Test that an invalid entry-argument format is detected"""
Simon Glass53cd5d92019-07-08 14:25:29 -06001577 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1578 '-ano-value']
Simon Glass53af22a2018-07-17 13:25:32 -06001579 with self.assertRaises(ValueError) as e:
1580 self._DoBinman(*args)
1581 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1582
1583 def testEntryArgsInvalidInteger(self):
1584 """Test that an invalid entry-argument integer is detected"""
1585 entry_args = {
1586 'test-int-arg': 'abc',
1587 }
1588 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001589 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001590 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1591 "'test-int-arg' (value 'abc') to integer",
1592 str(e.exception))
1593
1594 def testEntryArgsInvalidDatatype(self):
1595 """Test that an invalid entry-argument datatype is detected
1596
1597 This test could be written in entry_test.py except that it needs
1598 access to control.entry_args, which seems more than that module should
1599 be able to see.
1600 """
1601 entry_args = {
1602 'test-bad-datatype-arg': '12',
1603 }
1604 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001605 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass53af22a2018-07-17 13:25:32 -06001606 entry_args=entry_args)
1607 self.assertIn('GetArg() internal error: Unknown data type ',
1608 str(e.exception))
1609
Simon Glassbb748372018-07-17 13:25:33 -06001610 def testText(self):
1611 """Test for a text entry type"""
1612 entry_args = {
1613 'test-id': TEXT_DATA,
1614 'test-id2': TEXT_DATA2,
1615 'test-id3': TEXT_DATA3,
1616 }
Simon Glass741f2d62018-10-01 12:22:30 -06001617 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glassbb748372018-07-17 13:25:33 -06001618 entry_args=entry_args)
Simon Glassc1aa66e2022-01-29 14:14:04 -07001619 expected = (tools.to_bytes(TEXT_DATA) +
1620 tools.get_bytes(0, 8 - len(TEXT_DATA)) +
1621 tools.to_bytes(TEXT_DATA2) + tools.to_bytes(TEXT_DATA3) +
Simon Glassaa88b502019-07-08 13:18:40 -06001622 b'some text' + b'more text')
Simon Glassbb748372018-07-17 13:25:33 -06001623 self.assertEqual(expected, data)
1624
Simon Glassfd8d1f72018-07-17 13:25:36 -06001625 def testEntryDocs(self):
1626 """Test for creation of entry documentation"""
1627 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass87d43322020-08-05 13:27:46 -06001628 control.WriteEntryDocs(control.GetEntryModules())
Simon Glassfd8d1f72018-07-17 13:25:36 -06001629 self.assertTrue(len(stdout.getvalue()) > 0)
1630
1631 def testEntryDocsMissing(self):
1632 """Test handling of missing entry documentation"""
1633 with self.assertRaises(ValueError) as e:
1634 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass87d43322020-08-05 13:27:46 -06001635 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glassfd8d1f72018-07-17 13:25:36 -06001636 self.assertIn('Documentation is missing for modules: u_boot',
1637 str(e.exception))
1638
Simon Glass11e36cc2018-07-17 13:25:38 -06001639 def testFmap(self):
1640 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001641 data = self._DoReadFile('067_fmap.dts')
Simon Glass11e36cc2018-07-17 13:25:38 -06001642 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc1aa66e2022-01-29 14:14:04 -07001643 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1644 U_BOOT_DATA + tools.get_bytes(ord('a'), 12))
Simon Glass11e36cc2018-07-17 13:25:38 -06001645 self.assertEqual(expected, data[:32])
Simon Glassc6c10e72019-05-17 22:00:46 -06001646 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass11e36cc2018-07-17 13:25:38 -06001647 self.assertEqual(1, fhdr.ver_major)
1648 self.assertEqual(0, fhdr.ver_minor)
1649 self.assertEqual(0, fhdr.base)
Simon Glass17365752021-04-03 11:05:10 +13001650 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 5
Simon Glassc7722e82021-04-03 11:05:09 +13001651 self.assertEqual(16 + 16 + expect_size, fhdr.image_size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001652 self.assertEqual(b'FMAP', fhdr.name)
Simon Glass17365752021-04-03 11:05:10 +13001653 self.assertEqual(5, fhdr.nareas)
Simon Glassc7722e82021-04-03 11:05:09 +13001654 fiter = iter(fentries)
Simon Glass11e36cc2018-07-17 13:25:38 -06001655
Simon Glassc7722e82021-04-03 11:05:09 +13001656 fentry = next(fiter)
Simon Glass17365752021-04-03 11:05:10 +13001657 self.assertEqual(b'SECTION0', fentry.name)
1658 self.assertEqual(0, fentry.offset)
1659 self.assertEqual(16, fentry.size)
1660 self.assertEqual(0, fentry.flags)
1661
1662 fentry = next(fiter)
Simon Glassc7722e82021-04-03 11:05:09 +13001663 self.assertEqual(b'RO_U_BOOT', fentry.name)
1664 self.assertEqual(0, fentry.offset)
1665 self.assertEqual(4, fentry.size)
1666 self.assertEqual(0, fentry.flags)
Simon Glass11e36cc2018-07-17 13:25:38 -06001667
Simon Glassc7722e82021-04-03 11:05:09 +13001668 fentry = next(fiter)
Simon Glass17365752021-04-03 11:05:10 +13001669 self.assertEqual(b'SECTION1', fentry.name)
1670 self.assertEqual(16, fentry.offset)
1671 self.assertEqual(16, fentry.size)
1672 self.assertEqual(0, fentry.flags)
1673
1674 fentry = next(fiter)
Simon Glassc7722e82021-04-03 11:05:09 +13001675 self.assertEqual(b'RW_U_BOOT', fentry.name)
1676 self.assertEqual(16, fentry.offset)
1677 self.assertEqual(4, fentry.size)
1678 self.assertEqual(0, fentry.flags)
Simon Glass11e36cc2018-07-17 13:25:38 -06001679
Simon Glassc7722e82021-04-03 11:05:09 +13001680 fentry = next(fiter)
1681 self.assertEqual(b'FMAP', fentry.name)
1682 self.assertEqual(32, fentry.offset)
1683 self.assertEqual(expect_size, fentry.size)
1684 self.assertEqual(0, fentry.flags)
Simon Glass11e36cc2018-07-17 13:25:38 -06001685
Simon Glassec127af2018-07-17 13:25:39 -06001686 def testBlobNamedByArg(self):
1687 """Test we can add a blob with the filename coming from an entry arg"""
1688 entry_args = {
1689 'cros-ec-rw-path': 'ecrw.bin',
1690 }
Simon Glass3decfa32020-09-01 05:13:54 -06001691 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassec127af2018-07-17 13:25:39 -06001692
Simon Glass3af8e492018-07-17 13:25:40 -06001693 def testFill(self):
1694 """Test for an fill entry type"""
Simon Glass741f2d62018-10-01 12:22:30 -06001695 data = self._DoReadFile('069_fill.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001696 expected = tools.get_bytes(0xff, 8) + tools.get_bytes(0, 8)
Simon Glass3af8e492018-07-17 13:25:40 -06001697 self.assertEqual(expected, data)
1698
1699 def testFillNoSize(self):
1700 """Test for an fill entry type with no size"""
1701 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001702 self._DoReadFile('070_fill_no_size.dts')
Simon Glasscdadada2022-08-13 11:40:44 -06001703 self.assertIn("'fill' entry is missing properties: size",
Simon Glass3af8e492018-07-17 13:25:40 -06001704 str(e.exception))
1705
Simon Glass0ef87aa2018-07-17 13:25:44 -06001706 def _HandleGbbCommand(self, pipe_list):
1707 """Fake calls to the futility utility"""
1708 if pipe_list[0][0] == 'futility':
1709 fname = pipe_list[0][-1]
1710 # Append our GBB data to the file, which will happen every time the
1711 # futility command is called.
Simon Glass1d0ebf72019-05-14 15:53:42 -06001712 with open(fname, 'ab') as fd:
Simon Glass0ef87aa2018-07-17 13:25:44 -06001713 fd.write(GBB_DATA)
1714 return command.CommandResult()
1715
1716 def testGbb(self):
1717 """Test for the Chromium OS Google Binary Block"""
1718 command.test_result = self._HandleGbbCommand
1719 entry_args = {
1720 'keydir': 'devkeys',
1721 'bmpblk': 'bmpblk.bin',
1722 }
Simon Glass741f2d62018-10-01 12:22:30 -06001723 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glass0ef87aa2018-07-17 13:25:44 -06001724
1725 # Since futility
Simon Glassc1aa66e2022-01-29 14:14:04 -07001726 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
1727 tools.get_bytes(0, 0x2180 - 16))
Simon Glass0ef87aa2018-07-17 13:25:44 -06001728 self.assertEqual(expected, data)
1729
1730 def testGbbTooSmall(self):
1731 """Test for the Chromium OS Google Binary Block being large enough"""
1732 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001733 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001734 self.assertIn("Node '/binman/gbb': GBB is too small",
1735 str(e.exception))
1736
1737 def testGbbNoSize(self):
1738 """Test for the Chromium OS Google Binary Block having a size"""
1739 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001740 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001741 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1742 str(e.exception))
1743
Simon Glass4f9ee832022-01-09 20:14:09 -07001744 def testGbbMissing(self):
1745 """Test that binman still produces an image if futility is missing"""
1746 entry_args = {
1747 'keydir': 'devkeys',
1748 }
1749 with test_util.capture_sys_output() as (_, stderr):
1750 self._DoTestFile('071_gbb.dts', force_missing_bintools='futility',
1751 entry_args=entry_args)
1752 err = stderr.getvalue()
1753 self.assertRegex(err,
1754 "Image 'main-section'.*missing bintools.*: futility")
1755
Simon Glass24d0d3c2018-07-17 13:25:47 -06001756 def _HandleVblockCommand(self, pipe_list):
Simon Glass5af9ebc2021-01-06 21:35:17 -07001757 """Fake calls to the futility utility
1758
1759 The expected pipe is:
1760
1761 [('futility', 'vbutil_firmware', '--vblock',
1762 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1763 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1764 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1765 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1766
1767 This writes to the output file (here, 'vblock.vblock'). If
1768 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1769 of the input data (here, 'input.vblock').
1770 """
Simon Glass24d0d3c2018-07-17 13:25:47 -06001771 if pipe_list[0][0] == 'futility':
1772 fname = pipe_list[0][3]
Simon Glassa326b492018-09-14 04:57:11 -06001773 with open(fname, 'wb') as fd:
Simon Glass5af9ebc2021-01-06 21:35:17 -07001774 if self._hash_data:
1775 infile = pipe_list[0][11]
1776 m = hashlib.sha256()
Simon Glassc1aa66e2022-01-29 14:14:04 -07001777 data = tools.read_file(infile)
Simon Glass5af9ebc2021-01-06 21:35:17 -07001778 m.update(data)
1779 fd.write(m.digest())
1780 else:
1781 fd.write(VBLOCK_DATA)
1782
Simon Glass24d0d3c2018-07-17 13:25:47 -06001783 return command.CommandResult()
1784
1785 def testVblock(self):
1786 """Test for the Chromium OS Verified Boot Block"""
Simon Glass5af9ebc2021-01-06 21:35:17 -07001787 self._hash_data = False
Simon Glass24d0d3c2018-07-17 13:25:47 -06001788 command.test_result = self._HandleVblockCommand
1789 entry_args = {
1790 'keydir': 'devkeys',
1791 }
Simon Glass741f2d62018-10-01 12:22:30 -06001792 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass24d0d3c2018-07-17 13:25:47 -06001793 entry_args=entry_args)
1794 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1795 self.assertEqual(expected, data)
1796
1797 def testVblockNoContent(self):
1798 """Test we detect a vblock which has no content to sign"""
1799 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001800 self._DoReadFile('075_vblock_no_content.dts')
Simon Glass189f2912021-03-21 18:24:31 +13001801 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
Simon Glass24d0d3c2018-07-17 13:25:47 -06001802 'property', str(e.exception))
1803
1804 def testVblockBadPhandle(self):
1805 """Test that we detect a vblock with an invalid phandle in contents"""
1806 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001807 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001808 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1809 '1000', str(e.exception))
1810
1811 def testVblockBadEntry(self):
1812 """Test that we detect an entry that points to a non-entry"""
1813 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001814 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001815 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1816 "'other'", str(e.exception))
1817
Simon Glass5af9ebc2021-01-06 21:35:17 -07001818 def testVblockContent(self):
1819 """Test that the vblock signs the right data"""
1820 self._hash_data = True
1821 command.test_result = self._HandleVblockCommand
1822 entry_args = {
1823 'keydir': 'devkeys',
1824 }
1825 data = self._DoReadFileDtb(
1826 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1827 entry_args=entry_args)[0]
1828 hashlen = 32 # SHA256 hash is 32 bytes
1829 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1830 hashval = data[-hashlen:]
1831 dtb = data[len(U_BOOT_DATA):-hashlen]
1832
1833 expected_data = U_BOOT_DATA + dtb
1834
1835 # The hashval should be a hash of the dtb
1836 m = hashlib.sha256()
1837 m.update(expected_data)
1838 expected_hashval = m.digest()
1839 self.assertEqual(expected_hashval, hashval)
1840
Simon Glass4f9ee832022-01-09 20:14:09 -07001841 def testVblockMissing(self):
1842 """Test that binman still produces an image if futility is missing"""
1843 entry_args = {
1844 'keydir': 'devkeys',
1845 }
1846 with test_util.capture_sys_output() as (_, stderr):
1847 self._DoTestFile('074_vblock.dts',
1848 force_missing_bintools='futility',
1849 entry_args=entry_args)
1850 err = stderr.getvalue()
1851 self.assertRegex(err,
1852 "Image 'main-section'.*missing bintools.*: futility")
1853
Simon Glassb8ef5b62018-07-17 13:25:48 -06001854 def testTpl(self):
Simon Glass2090f1e2019-08-24 07:23:00 -06001855 """Test that an image with TPL and its device tree can be created"""
Simon Glassb8ef5b62018-07-17 13:25:48 -06001856 # ELF file with a '__bss_size' symbol
Simon Glass2090f1e2019-08-24 07:23:00 -06001857 self._SetupTplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001858 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glassb8ef5b62018-07-17 13:25:48 -06001859 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1860
Simon Glass15a587c2018-07-17 13:25:51 -06001861 def testUsesPos(self):
1862 """Test that the 'pos' property cannot be used anymore"""
1863 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001864 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass15a587c2018-07-17 13:25:51 -06001865 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1866 "'pos'", str(e.exception))
1867
Simon Glassd178eab2018-09-14 04:57:08 -06001868 def testFillZero(self):
1869 """Test for an fill entry type with a size of 0"""
Simon Glass741f2d62018-10-01 12:22:30 -06001870 data = self._DoReadFile('080_fill_empty.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001871 self.assertEqual(tools.get_bytes(0, 16), data)
Simon Glassd178eab2018-09-14 04:57:08 -06001872
Simon Glass0b489362018-09-14 04:57:09 -06001873 def testTextMissing(self):
1874 """Test for a text entry type where there is no text"""
1875 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001876 self._DoReadFileDtb('066_text.dts',)
Simon Glass0b489362018-09-14 04:57:09 -06001877 self.assertIn("Node '/binman/text': No value provided for text label "
1878 "'test-id'", str(e.exception))
1879
Simon Glass35b384c2018-09-14 04:57:10 -06001880 def testPackStart16Tpl(self):
1881 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001882 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glass35b384c2018-09-14 04:57:10 -06001883 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1884
Simon Glass0bfa7b02018-09-14 04:57:12 -06001885 def testSelectImage(self):
1886 """Test that we can select which images to build"""
Simon Glasseb833d82019-04-25 21:58:34 -06001887 expected = 'Skipping images: image1'
Simon Glass0bfa7b02018-09-14 04:57:12 -06001888
Simon Glasseb833d82019-04-25 21:58:34 -06001889 # We should only get the expected message in verbose mode
Simon Glassee0c9a72019-07-08 13:18:48 -06001890 for verbosity in (0, 2):
Simon Glasseb833d82019-04-25 21:58:34 -06001891 with test_util.capture_sys_output() as (stdout, stderr):
1892 retcode = self._DoTestFile('006_dual_image.dts',
1893 verbosity=verbosity,
1894 images=['image2'])
1895 self.assertEqual(0, retcode)
1896 if verbosity:
1897 self.assertIn(expected, stdout.getvalue())
1898 else:
1899 self.assertNotIn(expected, stdout.getvalue())
1900
Simon Glassc1aa66e2022-01-29 14:14:04 -07001901 self.assertFalse(os.path.exists(tools.get_output_filename('image1.bin')))
1902 self.assertTrue(os.path.exists(tools.get_output_filename('image2.bin')))
Simon Glassf86a7362019-07-20 12:24:10 -06001903 self._CleanupOutputDir()
Simon Glass0bfa7b02018-09-14 04:57:12 -06001904
Simon Glass6ed45ba2018-09-14 04:57:24 -06001905 def testUpdateFdtAll(self):
1906 """Test that all device trees are updated with offset/size info"""
Simon Glass3c081312019-07-08 14:25:26 -06001907 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glass6ed45ba2018-09-14 04:57:24 -06001908
1909 base_expected = {
1910 'section:image-pos': 0,
1911 'u-boot-tpl-dtb:size': 513,
1912 'u-boot-spl-dtb:size': 513,
1913 'u-boot-spl-dtb:offset': 493,
1914 'image-pos': 0,
1915 'section/u-boot-dtb:image-pos': 0,
1916 'u-boot-spl-dtb:image-pos': 493,
1917 'section/u-boot-dtb:size': 493,
1918 'u-boot-tpl-dtb:image-pos': 1006,
1919 'section/u-boot-dtb:offset': 0,
1920 'section:size': 493,
1921 'offset': 0,
1922 'section:offset': 0,
1923 'u-boot-tpl-dtb:offset': 1006,
1924 'size': 1519
1925 }
1926
1927 # We expect three device-tree files in the output, one after the other.
1928 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1929 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1930 # main U-Boot tree. All three should have the same postions and offset.
1931 start = 0
1932 for item in ['', 'spl', 'tpl']:
1933 dtb = fdt.Fdt.FromData(data[start:])
1934 dtb.Scan()
Simon Glass12bb1a92019-07-20 12:23:51 -06001935 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
1936 ['spl', 'tpl'])
Simon Glass6ed45ba2018-09-14 04:57:24 -06001937 expected = dict(base_expected)
1938 if item:
1939 expected[item] = 0
1940 self.assertEqual(expected, props)
1941 start += dtb._fdt_obj.totalsize()
1942
1943 def testUpdateFdtOutput(self):
1944 """Test that output DTB files are updated"""
1945 try:
Simon Glass741f2d62018-10-01 12:22:30 -06001946 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glass6ed45ba2018-09-14 04:57:24 -06001947 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1948
1949 # Unfortunately, compiling a source file always results in a file
1950 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass741f2d62018-10-01 12:22:30 -06001951 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glass6ed45ba2018-09-14 04:57:24 -06001952 # binman as a file called u-boot.dtb. To fix this, copy the file
1953 # over to the expected place.
Simon Glass6ed45ba2018-09-14 04:57:24 -06001954 start = 0
1955 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1956 'tpl/u-boot-tpl.dtb.out']:
1957 dtb = fdt.Fdt.FromData(data[start:])
1958 size = dtb._fdt_obj.totalsize()
Simon Glassc1aa66e2022-01-29 14:14:04 -07001959 pathname = tools.get_output_filename(os.path.split(fname)[1])
1960 outdata = tools.read_file(pathname)
Simon Glass6ed45ba2018-09-14 04:57:24 -06001961 name = os.path.split(fname)[0]
1962
1963 if name:
1964 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1965 else:
1966 orig_indata = dtb_data
1967 self.assertNotEqual(outdata, orig_indata,
1968 "Expected output file '%s' be updated" % pathname)
1969 self.assertEqual(outdata, data[start:start + size],
1970 "Expected output file '%s' to match output image" %
1971 pathname)
1972 start += size
1973 finally:
1974 self._ResetDtbs()
1975
Simon Glass83d73c22018-09-14 04:57:26 -06001976 def _decompress(self, data):
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +02001977 bintool = self.comp_bintools['lz4']
1978 return bintool.decompress(data)
Simon Glass83d73c22018-09-14 04:57:26 -06001979
1980 def testCompress(self):
1981 """Test compression of blobs"""
Simon Glassac62fba2019-07-08 13:18:53 -06001982 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06001983 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass83d73c22018-09-14 04:57:26 -06001984 use_real_dtb=True, update_dtb=True)
1985 dtb = fdt.Fdt(out_dtb_fname)
1986 dtb.Scan()
1987 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1988 orig = self._decompress(data)
1989 self.assertEquals(COMPRESS_DATA, orig)
Simon Glass97c3e9a2020-10-26 17:40:15 -06001990
1991 # Do a sanity check on various fields
1992 image = control.images['image']
1993 entries = image.GetEntries()
1994 self.assertEqual(1, len(entries))
1995
1996 entry = entries['blob']
1997 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
1998 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
1999 orig = self._decompress(entry.data)
2000 self.assertEqual(orig, entry.uncomp_data)
2001
Simon Glass63e7ba62020-10-26 17:40:16 -06002002 self.assertEqual(image.data, entry.data)
2003
Simon Glass83d73c22018-09-14 04:57:26 -06002004 expected = {
2005 'blob:uncomp-size': len(COMPRESS_DATA),
2006 'blob:size': len(data),
2007 'size': len(data),
2008 }
2009 self.assertEqual(expected, props)
2010
Simon Glass0a98b282018-09-14 04:57:28 -06002011 def testFiles(self):
2012 """Test bringing in multiple files"""
Simon Glass741f2d62018-10-01 12:22:30 -06002013 data = self._DoReadFile('084_files.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06002014 self.assertEqual(FILES_DATA, data)
2015
2016 def testFilesCompress(self):
2017 """Test bringing in multiple files and compressing them"""
Simon Glassac62fba2019-07-08 13:18:53 -06002018 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06002019 data = self._DoReadFile('085_files_compress.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06002020
2021 image = control.images['image']
2022 entries = image.GetEntries()
2023 files = entries['files']
Simon Glass8beb11e2019-07-08 14:25:47 -06002024 entries = files._entries
Simon Glass0a98b282018-09-14 04:57:28 -06002025
Simon Glassc6c10e72019-05-17 22:00:46 -06002026 orig = b''
Simon Glass0a98b282018-09-14 04:57:28 -06002027 for i in range(1, 3):
2028 key = '%d.dat' % i
2029 start = entries[key].image_pos
2030 len = entries[key].size
2031 chunk = data[start:start + len]
2032 orig += self._decompress(chunk)
2033
2034 self.assertEqual(FILES_DATA, orig)
2035
2036 def testFilesMissing(self):
2037 """Test missing files"""
2038 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002039 data = self._DoReadFile('086_files_none.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06002040 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
2041 'no files', str(e.exception))
2042
2043 def testFilesNoPattern(self):
2044 """Test missing files"""
2045 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002046 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06002047 self.assertIn("Node '/binman/files': Missing 'pattern' property",
2048 str(e.exception))
2049
Simon Glass80a66ae2022-03-05 20:18:59 -07002050 def testExtendSize(self):
2051 """Test an extending entry"""
2052 data, _, map_data, _ = self._DoReadFileDtb('088_extend_size.dts',
Simon Glassba64a0b2018-09-14 04:57:29 -06002053 map=True)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002054 expect = (tools.get_bytes(ord('a'), 8) + U_BOOT_DATA +
2055 MRC_DATA + tools.get_bytes(ord('b'), 1) + U_BOOT_DATA +
2056 tools.get_bytes(ord('c'), 8) + U_BOOT_DATA +
2057 tools.get_bytes(ord('d'), 8))
Simon Glassba64a0b2018-09-14 04:57:29 -06002058 self.assertEqual(expect, data)
2059 self.assertEqual('''ImagePos Offset Size Name
206000000000 00000000 00000028 main-section
206100000000 00000000 00000008 fill
206200000008 00000008 00000004 u-boot
20630000000c 0000000c 00000004 section
20640000000c 00000000 00000003 intel-mrc
206500000010 00000010 00000004 u-boot2
206600000014 00000014 0000000c section2
206700000014 00000000 00000008 fill
20680000001c 00000008 00000004 u-boot
206900000020 00000020 00000008 fill2
2070''', map_data)
2071
Simon Glass80a66ae2022-03-05 20:18:59 -07002072 def testExtendSizeBad(self):
2073 """Test an extending entry which fails to provide contents"""
Simon Glass163ed6c2018-09-14 04:57:36 -06002074 with test_util.capture_sys_output() as (stdout, stderr):
2075 with self.assertRaises(ValueError) as e:
Simon Glass80a66ae2022-03-05 20:18:59 -07002076 self._DoReadFileDtb('089_extend_size_bad.dts', map=True)
Simon Glassba64a0b2018-09-14 04:57:29 -06002077 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
2078 'expanding entry', str(e.exception))
2079
Simon Glasse0e5df92018-09-14 04:57:31 -06002080 def testHash(self):
2081 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06002082 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06002083 use_real_dtb=True, update_dtb=True)
2084 dtb = fdt.Fdt(out_dtb_fname)
2085 dtb.Scan()
2086 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
2087 m = hashlib.sha256()
2088 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06002089 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06002090
2091 def testHashNoAlgo(self):
2092 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002093 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06002094 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2095 'hash node', str(e.exception))
2096
2097 def testHashBadAlgo(self):
2098 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002099 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glass8db1f992022-02-08 10:59:44 -07002100 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm 'invalid'",
Simon Glasse0e5df92018-09-14 04:57:31 -06002101 str(e.exception))
2102
2103 def testHashSection(self):
2104 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06002105 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06002106 use_real_dtb=True, update_dtb=True)
2107 dtb = fdt.Fdt(out_dtb_fname)
2108 dtb.Scan()
2109 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2110 m = hashlib.sha256()
2111 m.update(U_BOOT_DATA)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002112 m.update(tools.get_bytes(ord('a'), 16))
Simon Glassc6c10e72019-05-17 22:00:46 -06002113 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06002114
Simon Glassf0253632018-09-14 04:57:32 -06002115 def testPackUBootTplMicrocode(self):
2116 """Test that x86 microcode can be handled correctly in TPL
2117
2118 We expect to see the following in the image, in order:
2119 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2120 place
2121 u-boot-tpl.dtb with the microcode removed
2122 the microcode
2123 """
Simon Glass2090f1e2019-08-24 07:23:00 -06002124 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass741f2d62018-10-01 12:22:30 -06002125 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glassf0253632018-09-14 04:57:32 -06002126 U_BOOT_TPL_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06002127 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2128 b'ter somewhere in here', first)
Simon Glassf0253632018-09-14 04:57:32 -06002129
Simon Glassf8f8df62018-09-14 04:57:34 -06002130 def testFmapX86(self):
2131 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06002132 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassf8f8df62018-09-14 04:57:34 -06002133 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc1aa66e2022-01-29 14:14:04 -07002134 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('a'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06002135 self.assertEqual(expected, data[:32])
2136 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2137
2138 self.assertEqual(0x100, fhdr.image_size)
2139
2140 self.assertEqual(0, fentries[0].offset)
2141 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06002142 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06002143
2144 self.assertEqual(4, fentries[1].offset)
2145 self.assertEqual(3, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06002146 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06002147
2148 self.assertEqual(32, fentries[2].offset)
2149 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2150 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06002151 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06002152
2153 def testFmapX86Section(self):
2154 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06002155 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002156 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('b'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06002157 self.assertEqual(expected, data[:32])
2158 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2159
Simon Glass17365752021-04-03 11:05:10 +13002160 self.assertEqual(0x180, fhdr.image_size)
2161 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
Simon Glassc7722e82021-04-03 11:05:09 +13002162 fiter = iter(fentries)
Simon Glassf8f8df62018-09-14 04:57:34 -06002163
Simon Glassc7722e82021-04-03 11:05:09 +13002164 fentry = next(fiter)
2165 self.assertEqual(b'U_BOOT', fentry.name)
2166 self.assertEqual(0, fentry.offset)
2167 self.assertEqual(4, fentry.size)
Simon Glassf8f8df62018-09-14 04:57:34 -06002168
Simon Glassc7722e82021-04-03 11:05:09 +13002169 fentry = next(fiter)
Simon Glass17365752021-04-03 11:05:10 +13002170 self.assertEqual(b'SECTION', fentry.name)
2171 self.assertEqual(4, fentry.offset)
2172 self.assertEqual(0x20 + expect_size, fentry.size)
2173
2174 fentry = next(fiter)
Simon Glassc7722e82021-04-03 11:05:09 +13002175 self.assertEqual(b'INTEL_MRC', fentry.name)
2176 self.assertEqual(4, fentry.offset)
2177 self.assertEqual(3, fentry.size)
Simon Glassf8f8df62018-09-14 04:57:34 -06002178
Simon Glassc7722e82021-04-03 11:05:09 +13002179 fentry = next(fiter)
2180 self.assertEqual(b'FMAP', fentry.name)
2181 self.assertEqual(36, fentry.offset)
2182 self.assertEqual(expect_size, fentry.size)
Simon Glassf8f8df62018-09-14 04:57:34 -06002183
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002184 def testElf(self):
2185 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06002186 self._SetupSplElf()
Simon Glass2090f1e2019-08-24 07:23:00 -06002187 self._SetupTplElf()
Simon Glass53e22bf2019-08-24 07:22:53 -06002188 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002189 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06002190 data = self._DoReadFile('096_elf.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002191
Simon Glass093d1682019-07-08 13:18:25 -06002192 def testElfStrip(self):
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002193 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06002194 self._SetupSplElf()
Simon Glass53e22bf2019-08-24 07:22:53 -06002195 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002196 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06002197 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002198
Simon Glass163ed6c2018-09-14 04:57:36 -06002199 def testPackOverlapMap(self):
2200 """Test that overlapping regions are detected"""
2201 with test_util.capture_sys_output() as (stdout, stderr):
2202 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002203 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002204 map_fname = tools.get_output_filename('image.map')
Simon Glass163ed6c2018-09-14 04:57:36 -06002205 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2206 stdout.getvalue())
2207
2208 # We should not get an inmage, but there should be a map file
Simon Glassc1aa66e2022-01-29 14:14:04 -07002209 self.assertFalse(os.path.exists(tools.get_output_filename('image.bin')))
Simon Glass163ed6c2018-09-14 04:57:36 -06002210 self.assertTrue(os.path.exists(map_fname))
Simon Glassc1aa66e2022-01-29 14:14:04 -07002211 map_data = tools.read_file(map_fname, binary=False)
Simon Glass163ed6c2018-09-14 04:57:36 -06002212 self.assertEqual('''ImagePos Offset Size Name
Simon Glass0ff83da2020-10-26 17:40:24 -06002213<none> 00000000 00000008 main-section
Simon Glass163ed6c2018-09-14 04:57:36 -06002214<none> 00000000 00000004 u-boot
2215<none> 00000003 00000004 u-boot-align
2216''', map_data)
2217
Simon Glass093d1682019-07-08 13:18:25 -06002218 def testPackRefCode(self):
Simon Glass3ae192c2018-10-01 12:22:31 -06002219 """Test that an image with an Intel Reference code binary works"""
2220 data = self._DoReadFile('100_intel_refcode.dts')
2221 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2222
Simon Glass9481c802019-04-25 21:58:39 -06002223 def testSectionOffset(self):
2224 """Tests use of a section with an offset"""
2225 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2226 map=True)
2227 self.assertEqual('''ImagePos Offset Size Name
222800000000 00000000 00000038 main-section
222900000004 00000004 00000010 section@0
223000000004 00000000 00000004 u-boot
223100000018 00000018 00000010 section@1
223200000018 00000000 00000004 u-boot
22330000002c 0000002c 00000004 section@2
22340000002c 00000000 00000004 u-boot
2235''', map_data)
2236 self.assertEqual(data,
Simon Glassc1aa66e2022-01-29 14:14:04 -07002237 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2238 tools.get_bytes(0x21, 12) +
2239 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2240 tools.get_bytes(0x61, 12) +
2241 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2242 tools.get_bytes(0x26, 8))
Simon Glass9481c802019-04-25 21:58:39 -06002243
Simon Glassac62fba2019-07-08 13:18:53 -06002244 def testCbfsRaw(self):
2245 """Test base handling of a Coreboot Filesystem (CBFS)
2246
2247 The exact contents of the CBFS is verified by similar tests in
2248 cbfs_util_test.py. The tests here merely check that the files added to
2249 the CBFS can be found in the final image.
2250 """
2251 data = self._DoReadFile('102_cbfs_raw.dts')
2252 size = 0xb0
2253
2254 cbfs = cbfs_util.CbfsReader(data)
2255 self.assertEqual(size, cbfs.rom_size)
2256
2257 self.assertIn('u-boot-dtb', cbfs.files)
2258 cfile = cbfs.files['u-boot-dtb']
2259 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2260
2261 def testCbfsArch(self):
2262 """Test on non-x86 architecture"""
2263 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2264 size = 0x100
2265
2266 cbfs = cbfs_util.CbfsReader(data)
2267 self.assertEqual(size, cbfs.rom_size)
2268
2269 self.assertIn('u-boot-dtb', cbfs.files)
2270 cfile = cbfs.files['u-boot-dtb']
2271 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2272
2273 def testCbfsStage(self):
2274 """Tests handling of a Coreboot Filesystem (CBFS)"""
2275 if not elf.ELF_TOOLS:
2276 self.skipTest('Python elftools not available')
2277 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2278 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2279 size = 0xb0
2280
2281 data = self._DoReadFile('104_cbfs_stage.dts')
2282 cbfs = cbfs_util.CbfsReader(data)
2283 self.assertEqual(size, cbfs.rom_size)
2284
2285 self.assertIn('u-boot', cbfs.files)
2286 cfile = cbfs.files['u-boot']
2287 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2288
2289 def testCbfsRawCompress(self):
2290 """Test handling of compressing raw files"""
2291 self._CheckLz4()
2292 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2293 size = 0x140
2294
2295 cbfs = cbfs_util.CbfsReader(data)
2296 self.assertIn('u-boot', cbfs.files)
2297 cfile = cbfs.files['u-boot']
2298 self.assertEqual(COMPRESS_DATA, cfile.data)
2299
2300 def testCbfsBadArch(self):
2301 """Test handling of a bad architecture"""
2302 with self.assertRaises(ValueError) as e:
2303 self._DoReadFile('106_cbfs_bad_arch.dts')
2304 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2305
2306 def testCbfsNoSize(self):
2307 """Test handling of a missing size property"""
2308 with self.assertRaises(ValueError) as e:
2309 self._DoReadFile('107_cbfs_no_size.dts')
2310 self.assertIn('entry must have a size property', str(e.exception))
2311
Simon Glasse2f04742021-11-23 11:03:54 -07002312 def testCbfsNoContents(self):
Simon Glassac62fba2019-07-08 13:18:53 -06002313 """Test handling of a CBFS entry which does not provide contentsy"""
2314 with self.assertRaises(ValueError) as e:
2315 self._DoReadFile('108_cbfs_no_contents.dts')
2316 self.assertIn('Could not complete processing of contents',
2317 str(e.exception))
2318
2319 def testCbfsBadCompress(self):
2320 """Test handling of a bad architecture"""
2321 with self.assertRaises(ValueError) as e:
2322 self._DoReadFile('109_cbfs_bad_compress.dts')
2323 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2324 str(e.exception))
2325
2326 def testCbfsNamedEntries(self):
2327 """Test handling of named entries"""
2328 data = self._DoReadFile('110_cbfs_name.dts')
2329
2330 cbfs = cbfs_util.CbfsReader(data)
2331 self.assertIn('FRED', cbfs.files)
2332 cfile1 = cbfs.files['FRED']
2333 self.assertEqual(U_BOOT_DATA, cfile1.data)
2334
2335 self.assertIn('hello', cbfs.files)
2336 cfile2 = cbfs.files['hello']
2337 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2338
Simon Glassc5ac1382019-07-08 13:18:54 -06002339 def _SetupIfwi(self, fname):
2340 """Set up to run an IFWI test
2341
2342 Args:
2343 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2344 """
2345 self._SetupSplElf()
Simon Glass2090f1e2019-08-24 07:23:00 -06002346 self._SetupTplElf()
Simon Glassc5ac1382019-07-08 13:18:54 -06002347
2348 # Intel Integrated Firmware Image (IFWI) file
2349 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2350 data = fd.read()
2351 TestFunctional._MakeInputFile(fname,data)
2352
2353 def _CheckIfwi(self, data):
2354 """Check that an image with an IFWI contains the correct output
2355
2356 Args:
2357 data: Conents of output file
2358 """
Simon Glassc1aa66e2022-01-29 14:14:04 -07002359 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glassc5ac1382019-07-08 13:18:54 -06002360 if data[:0x1000] != expected_desc:
2361 self.fail('Expected descriptor binary at start of image')
2362
2363 # We expect to find the TPL wil in subpart IBBP entry IBBL
Simon Glassc1aa66e2022-01-29 14:14:04 -07002364 image_fname = tools.get_output_filename('image.bin')
2365 tpl_fname = tools.get_output_filename('tpl.out')
Simon Glass532ae702022-01-09 20:14:01 -07002366 ifwitool = bintool.Bintool.create('ifwitool')
2367 ifwitool.extract(image_fname, 'IBBP', 'IBBL', tpl_fname)
Simon Glassc5ac1382019-07-08 13:18:54 -06002368
Simon Glassc1aa66e2022-01-29 14:14:04 -07002369 tpl_data = tools.read_file(tpl_fname)
Simon Glasse95be632019-08-24 07:22:51 -06002370 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glassc5ac1382019-07-08 13:18:54 -06002371
2372 def testPackX86RomIfwi(self):
2373 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2374 self._SetupIfwi('fitimage.bin')
Simon Glass9255f3c2019-08-24 07:23:01 -06002375 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002376 self._CheckIfwi(data)
2377
2378 def testPackX86RomIfwiNoDesc(self):
2379 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2380 self._SetupIfwi('ifwi.bin')
Simon Glass9255f3c2019-08-24 07:23:01 -06002381 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002382 self._CheckIfwi(data)
2383
2384 def testPackX86RomIfwiNoData(self):
2385 """Test that an x86 ROM with IFWI handles missing data"""
2386 self._SetupIfwi('ifwi.bin')
2387 with self.assertRaises(ValueError) as e:
Simon Glass9255f3c2019-08-24 07:23:01 -06002388 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002389 self.assertIn('Could not complete processing of contents',
2390 str(e.exception))
Simon Glass53af22a2018-07-17 13:25:32 -06002391
Simon Glass4f9ee832022-01-09 20:14:09 -07002392 def testIfwiMissing(self):
2393 """Test that binman still produces an image if ifwitool is missing"""
2394 self._SetupIfwi('fitimage.bin')
2395 with test_util.capture_sys_output() as (_, stderr):
2396 self._DoTestFile('111_x86_rom_ifwi.dts',
2397 force_missing_bintools='ifwitool')
2398 err = stderr.getvalue()
2399 self.assertRegex(err,
2400 "Image 'main-section'.*missing bintools.*: ifwitool")
2401
Simon Glasse073d4e2019-07-08 13:18:56 -06002402 def testCbfsOffset(self):
2403 """Test a CBFS with files at particular offsets
2404
2405 Like all CFBS tests, this is just checking the logic that calls
2406 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2407 """
2408 data = self._DoReadFile('114_cbfs_offset.dts')
2409 size = 0x200
2410
2411 cbfs = cbfs_util.CbfsReader(data)
2412 self.assertEqual(size, cbfs.rom_size)
2413
2414 self.assertIn('u-boot', cbfs.files)
2415 cfile = cbfs.files['u-boot']
2416 self.assertEqual(U_BOOT_DATA, cfile.data)
2417 self.assertEqual(0x40, cfile.cbfs_offset)
2418
2419 self.assertIn('u-boot-dtb', cbfs.files)
2420 cfile2 = cbfs.files['u-boot-dtb']
2421 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2422 self.assertEqual(0x140, cfile2.cbfs_offset)
2423
Simon Glass086cec92019-07-08 14:25:27 -06002424 def testFdtmap(self):
2425 """Test an FDT map can be inserted in the image"""
2426 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2427 fdtmap_data = data[len(U_BOOT_DATA):]
2428 magic = fdtmap_data[:8]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002429 self.assertEqual(b'_FDTMAP_', magic)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002430 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass086cec92019-07-08 14:25:27 -06002431
2432 fdt_data = fdtmap_data[16:]
2433 dtb = fdt.Fdt.FromData(fdt_data)
2434 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002435 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass086cec92019-07-08 14:25:27 -06002436 self.assertEqual({
2437 'image-pos': 0,
2438 'offset': 0,
2439 'u-boot:offset': 0,
2440 'u-boot:size': len(U_BOOT_DATA),
2441 'u-boot:image-pos': 0,
2442 'fdtmap:image-pos': 4,
2443 'fdtmap:offset': 4,
2444 'fdtmap:size': len(fdtmap_data),
2445 'size': len(data),
2446 }, props)
2447
2448 def testFdtmapNoMatch(self):
2449 """Check handling of an FDT map when the section cannot be found"""
2450 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2451
2452 # Mangle the section name, which should cause a mismatch between the
2453 # correct FDT path and the one expected by the section
2454 image = control.images['image']
Simon Glasscf228942019-07-08 14:25:28 -06002455 image._node.path += '-suffix'
Simon Glass086cec92019-07-08 14:25:27 -06002456 entries = image.GetEntries()
2457 fdtmap = entries['fdtmap']
2458 with self.assertRaises(ValueError) as e:
2459 fdtmap._GetFdtmap()
2460 self.assertIn("Cannot locate node for path '/binman-suffix'",
2461 str(e.exception))
2462
Simon Glasscf228942019-07-08 14:25:28 -06002463 def testFdtmapHeader(self):
2464 """Test an FDT map and image header can be inserted in the image"""
2465 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2466 fdtmap_pos = len(U_BOOT_DATA)
2467 fdtmap_data = data[fdtmap_pos:]
2468 fdt_data = fdtmap_data[16:]
2469 dtb = fdt.Fdt.FromData(fdt_data)
2470 fdt_size = dtb.GetFdtObj().totalsize()
2471 hdr_data = data[-8:]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002472 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002473 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2474 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2475
2476 def testFdtmapHeaderStart(self):
2477 """Test an image header can be inserted at the image start"""
2478 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2479 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2480 hdr_data = data[:8]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002481 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002482 offset = struct.unpack('<I', hdr_data[4:])[0]
2483 self.assertEqual(fdtmap_pos, offset)
2484
2485 def testFdtmapHeaderPos(self):
2486 """Test an image header can be inserted at a chosen position"""
2487 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2488 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2489 hdr_data = data[0x80:0x88]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002490 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002491 offset = struct.unpack('<I', hdr_data[4:])[0]
2492 self.assertEqual(fdtmap_pos, offset)
2493
2494 def testHeaderMissingFdtmap(self):
2495 """Test an image header requires an fdtmap"""
2496 with self.assertRaises(ValueError) as e:
2497 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2498 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2499 str(e.exception))
2500
2501 def testHeaderNoLocation(self):
2502 """Test an image header with a no specified location is detected"""
2503 with self.assertRaises(ValueError) as e:
2504 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2505 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2506 str(e.exception))
2507
Simon Glassc52c9e72019-07-08 14:25:37 -06002508 def testEntryExpand(self):
Simon Glass80a66ae2022-03-05 20:18:59 -07002509 """Test extending an entry after it is packed"""
2510 data = self._DoReadFile('121_entry_extend.dts')
Simon Glass79d3c582019-07-20 12:23:57 -06002511 self.assertEqual(b'aaa', data[:3])
2512 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2513 self.assertEqual(b'aaa', data[-3:])
Simon Glassc52c9e72019-07-08 14:25:37 -06002514
Simon Glass80a66ae2022-03-05 20:18:59 -07002515 def testEntryExtendBad(self):
2516 """Test extending an entry after it is packed, twice"""
Simon Glassc52c9e72019-07-08 14:25:37 -06002517 with self.assertRaises(ValueError) as e:
Simon Glass80a66ae2022-03-05 20:18:59 -07002518 self._DoReadFile('122_entry_extend_twice.dts')
Simon Glass61ec04f2019-07-20 12:23:58 -06002519 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glassc52c9e72019-07-08 14:25:37 -06002520 str(e.exception))
2521
Simon Glass80a66ae2022-03-05 20:18:59 -07002522 def testEntryExtendSection(self):
2523 """Test extending an entry within a section after it is packed"""
2524 data = self._DoReadFile('123_entry_extend_section.dts')
Simon Glass79d3c582019-07-20 12:23:57 -06002525 self.assertEqual(b'aaa', data[:3])
2526 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2527 self.assertEqual(b'aaa', data[-3:])
Simon Glassc52c9e72019-07-08 14:25:37 -06002528
Simon Glass6c223fd2019-07-08 14:25:38 -06002529 def testCompressDtb(self):
2530 """Test that compress of device-tree files is supported"""
2531 self._CheckLz4()
2532 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2533 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2534 comp_data = data[len(U_BOOT_DATA):]
2535 orig = self._decompress(comp_data)
2536 dtb = fdt.Fdt.FromData(orig)
2537 dtb.Scan()
2538 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2539 expected = {
2540 'u-boot:size': len(U_BOOT_DATA),
2541 'u-boot-dtb:uncomp-size': len(orig),
2542 'u-boot-dtb:size': len(comp_data),
2543 'size': len(data),
2544 }
2545 self.assertEqual(expected, props)
2546
Simon Glass69f7cb32019-07-08 14:25:41 -06002547 def testCbfsUpdateFdt(self):
2548 """Test that we can update the device tree with CBFS offset/size info"""
2549 self._CheckLz4()
2550 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2551 update_dtb=True)
2552 dtb = fdt.Fdt(out_dtb_fname)
2553 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002554 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass69f7cb32019-07-08 14:25:41 -06002555 del props['cbfs/u-boot:size']
2556 self.assertEqual({
2557 'offset': 0,
2558 'size': len(data),
2559 'image-pos': 0,
2560 'cbfs:offset': 0,
2561 'cbfs:size': len(data),
2562 'cbfs:image-pos': 0,
2563 'cbfs/u-boot:offset': 0x38,
2564 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2565 'cbfs/u-boot:image-pos': 0x38,
2566 'cbfs/u-boot-dtb:offset': 0xb8,
2567 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2568 'cbfs/u-boot-dtb:image-pos': 0xb8,
2569 }, props)
2570
Simon Glass8a1ad062019-07-08 14:25:42 -06002571 def testCbfsBadType(self):
2572 """Test an image header with a no specified location is detected"""
2573 with self.assertRaises(ValueError) as e:
2574 self._DoReadFile('126_cbfs_bad_type.dts')
2575 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2576
Simon Glass41b8ba02019-07-08 14:25:43 -06002577 def testList(self):
2578 """Test listing the files in an image"""
2579 self._CheckLz4()
2580 data = self._DoReadFile('127_list.dts')
2581 image = control.images['image']
2582 entries = image.BuildEntryList()
2583 self.assertEqual(7, len(entries))
2584
2585 ent = entries[0]
2586 self.assertEqual(0, ent.indent)
2587 self.assertEqual('main-section', ent.name)
2588 self.assertEqual('section', ent.etype)
2589 self.assertEqual(len(data), ent.size)
2590 self.assertEqual(0, ent.image_pos)
2591 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002592 self.assertEqual(0, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002593
2594 ent = entries[1]
2595 self.assertEqual(1, ent.indent)
2596 self.assertEqual('u-boot', ent.name)
2597 self.assertEqual('u-boot', ent.etype)
2598 self.assertEqual(len(U_BOOT_DATA), ent.size)
2599 self.assertEqual(0, ent.image_pos)
2600 self.assertEqual(None, ent.uncomp_size)
2601 self.assertEqual(0, ent.offset)
2602
2603 ent = entries[2]
2604 self.assertEqual(1, ent.indent)
2605 self.assertEqual('section', ent.name)
2606 self.assertEqual('section', ent.etype)
2607 section_size = ent.size
2608 self.assertEqual(0x100, ent.image_pos)
2609 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002610 self.assertEqual(0x100, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002611
2612 ent = entries[3]
2613 self.assertEqual(2, ent.indent)
2614 self.assertEqual('cbfs', ent.name)
2615 self.assertEqual('cbfs', ent.etype)
2616 self.assertEqual(0x400, ent.size)
2617 self.assertEqual(0x100, ent.image_pos)
2618 self.assertEqual(None, ent.uncomp_size)
2619 self.assertEqual(0, ent.offset)
2620
2621 ent = entries[4]
2622 self.assertEqual(3, ent.indent)
2623 self.assertEqual('u-boot', ent.name)
2624 self.assertEqual('u-boot', ent.etype)
2625 self.assertEqual(len(U_BOOT_DATA), ent.size)
2626 self.assertEqual(0x138, ent.image_pos)
2627 self.assertEqual(None, ent.uncomp_size)
2628 self.assertEqual(0x38, ent.offset)
2629
2630 ent = entries[5]
2631 self.assertEqual(3, ent.indent)
2632 self.assertEqual('u-boot-dtb', ent.name)
2633 self.assertEqual('text', ent.etype)
2634 self.assertGreater(len(COMPRESS_DATA), ent.size)
2635 self.assertEqual(0x178, ent.image_pos)
2636 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2637 self.assertEqual(0x78, ent.offset)
2638
2639 ent = entries[6]
2640 self.assertEqual(2, ent.indent)
2641 self.assertEqual('u-boot-dtb', ent.name)
2642 self.assertEqual('u-boot-dtb', ent.etype)
2643 self.assertEqual(0x500, ent.image_pos)
2644 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2645 dtb_size = ent.size
2646 # Compressing this data expands it since headers are added
2647 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2648 self.assertEqual(0x400, ent.offset)
2649
2650 self.assertEqual(len(data), 0x100 + section_size)
2651 self.assertEqual(section_size, 0x400 + dtb_size)
2652
Simon Glasse1925fa2019-07-08 14:25:44 -06002653 def testFindFdtmap(self):
2654 """Test locating an FDT map in an image"""
2655 self._CheckLz4()
2656 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2657 image = control.images['image']
2658 entries = image.GetEntries()
2659 entry = entries['fdtmap']
2660 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2661
2662 def testFindFdtmapMissing(self):
2663 """Test failing to locate an FDP map"""
2664 data = self._DoReadFile('005_simple.dts')
2665 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2666
Simon Glass2d260032019-07-08 14:25:45 -06002667 def testFindImageHeader(self):
2668 """Test locating a image header"""
2669 self._CheckLz4()
Simon Glassffded752019-07-08 14:25:46 -06002670 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002671 image = control.images['image']
2672 entries = image.GetEntries()
2673 entry = entries['fdtmap']
2674 # The header should point to the FDT map
2675 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2676
2677 def testFindImageHeaderStart(self):
2678 """Test locating a image header located at the start of an image"""
Simon Glassffded752019-07-08 14:25:46 -06002679 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002680 image = control.images['image']
2681 entries = image.GetEntries()
2682 entry = entries['fdtmap']
2683 # The header should point to the FDT map
2684 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2685
2686 def testFindImageHeaderMissing(self):
2687 """Test failing to locate an image header"""
2688 data = self._DoReadFile('005_simple.dts')
2689 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2690
Simon Glassffded752019-07-08 14:25:46 -06002691 def testReadImage(self):
2692 """Test reading an image and accessing its FDT map"""
2693 self._CheckLz4()
2694 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002695 image_fname = tools.get_output_filename('image.bin')
Simon Glassffded752019-07-08 14:25:46 -06002696 orig_image = control.images['image']
2697 image = Image.FromFile(image_fname)
2698 self.assertEqual(orig_image.GetEntries().keys(),
2699 image.GetEntries().keys())
2700
2701 orig_entry = orig_image.GetEntries()['fdtmap']
2702 entry = image.GetEntries()['fdtmap']
2703 self.assertEquals(orig_entry.offset, entry.offset)
2704 self.assertEquals(orig_entry.size, entry.size)
2705 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2706
2707 def testReadImageNoHeader(self):
2708 """Test accessing an image's FDT map without an image header"""
2709 self._CheckLz4()
2710 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002711 image_fname = tools.get_output_filename('image.bin')
Simon Glassffded752019-07-08 14:25:46 -06002712 image = Image.FromFile(image_fname)
2713 self.assertTrue(isinstance(image, Image))
Simon Glass10f9d002019-07-20 12:23:50 -06002714 self.assertEqual('image', image.image_name[-5:])
Simon Glassffded752019-07-08 14:25:46 -06002715
2716 def testReadImageFail(self):
2717 """Test failing to read an image image's FDT map"""
2718 self._DoReadFile('005_simple.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002719 image_fname = tools.get_output_filename('image.bin')
Simon Glassffded752019-07-08 14:25:46 -06002720 with self.assertRaises(ValueError) as e:
2721 image = Image.FromFile(image_fname)
2722 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glasse073d4e2019-07-08 13:18:56 -06002723
Simon Glass61f564d2019-07-08 14:25:48 -06002724 def testListCmd(self):
2725 """Test listing the files in an image using an Fdtmap"""
2726 self._CheckLz4()
2727 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2728
2729 # lz4 compression size differs depending on the version
2730 image = control.images['image']
2731 entries = image.GetEntries()
2732 section_size = entries['section'].size
2733 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2734 fdtmap_offset = entries['fdtmap'].offset
2735
Simon Glassf86a7362019-07-20 12:24:10 -06002736 try:
2737 tmpdir, updated_fname = self._SetupImageInTmpdir()
2738 with test_util.capture_sys_output() as (stdout, stderr):
2739 self._DoBinman('ls', '-i', updated_fname)
2740 finally:
2741 shutil.rmtree(tmpdir)
Simon Glass61f564d2019-07-08 14:25:48 -06002742 lines = stdout.getvalue().splitlines()
2743 expected = [
2744'Name Image-pos Size Entry-type Offset Uncomp-size',
2745'----------------------------------------------------------------------',
2746'main-section 0 c00 section 0',
2747' u-boot 0 4 u-boot 0',
2748' section 100 %x section 100' % section_size,
2749' cbfs 100 400 cbfs 0',
2750' u-boot 138 4 u-boot 38',
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002751' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glass61f564d2019-07-08 14:25:48 -06002752' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002753' fdtmap %x 3bd fdtmap %x' %
Simon Glass61f564d2019-07-08 14:25:48 -06002754 (fdtmap_offset, fdtmap_offset),
2755' image-header bf8 8 image-header bf8',
2756 ]
2757 self.assertEqual(expected, lines)
2758
2759 def testListCmdFail(self):
2760 """Test failing to list an image"""
2761 self._DoReadFile('005_simple.dts')
Simon Glassf86a7362019-07-20 12:24:10 -06002762 try:
2763 tmpdir, updated_fname = self._SetupImageInTmpdir()
2764 with self.assertRaises(ValueError) as e:
2765 self._DoBinman('ls', '-i', updated_fname)
2766 finally:
2767 shutil.rmtree(tmpdir)
Simon Glass61f564d2019-07-08 14:25:48 -06002768 self.assertIn("Cannot find FDT map in image", str(e.exception))
2769
2770 def _RunListCmd(self, paths, expected):
2771 """List out entries and check the result
2772
2773 Args:
2774 paths: List of paths to pass to the list command
2775 expected: Expected list of filenames to be returned, in order
2776 """
2777 self._CheckLz4()
2778 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002779 image_fname = tools.get_output_filename('image.bin')
Simon Glass61f564d2019-07-08 14:25:48 -06002780 image = Image.FromFile(image_fname)
2781 lines = image.GetListEntries(paths)[1]
2782 files = [line[0].strip() for line in lines[1:]]
2783 self.assertEqual(expected, files)
2784
2785 def testListCmdSection(self):
2786 """Test listing the files in a section"""
2787 self._RunListCmd(['section'],
2788 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2789
2790 def testListCmdFile(self):
2791 """Test listing a particular file"""
2792 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2793
2794 def testListCmdWildcard(self):
2795 """Test listing a wildcarded file"""
2796 self._RunListCmd(['*boot*'],
2797 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2798
2799 def testListCmdWildcardMulti(self):
2800 """Test listing a wildcarded file"""
2801 self._RunListCmd(['*cb*', '*head*'],
2802 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2803
2804 def testListCmdEmpty(self):
2805 """Test listing a wildcarded file"""
2806 self._RunListCmd(['nothing'], [])
2807
2808 def testListCmdPath(self):
2809 """Test listing the files in a sub-entry of a section"""
2810 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2811
Simon Glassf667e452019-07-08 14:25:50 -06002812 def _RunExtractCmd(self, entry_name, decomp=True):
2813 """Extract an entry from an image
2814
2815 Args:
2816 entry_name: Entry name to extract
2817 decomp: True to decompress the data if compressed, False to leave
2818 it in its raw uncompressed format
2819
2820 Returns:
2821 data from entry
2822 """
2823 self._CheckLz4()
2824 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002825 image_fname = tools.get_output_filename('image.bin')
Simon Glassf667e452019-07-08 14:25:50 -06002826 return control.ReadEntry(image_fname, entry_name, decomp)
2827
2828 def testExtractSimple(self):
2829 """Test extracting a single file"""
2830 data = self._RunExtractCmd('u-boot')
2831 self.assertEqual(U_BOOT_DATA, data)
2832
Simon Glass71ce0ba2019-07-08 14:25:52 -06002833 def testExtractSection(self):
2834 """Test extracting the files in a section"""
2835 data = self._RunExtractCmd('section')
2836 cbfs_data = data[:0x400]
2837 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002838 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass71ce0ba2019-07-08 14:25:52 -06002839 dtb_data = data[0x400:]
2840 dtb = self._decompress(dtb_data)
2841 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2842
2843 def testExtractCompressed(self):
2844 """Test extracting compressed data"""
2845 data = self._RunExtractCmd('section/u-boot-dtb')
2846 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2847
2848 def testExtractRaw(self):
2849 """Test extracting compressed data without decompressing it"""
2850 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2851 dtb = self._decompress(data)
2852 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2853
2854 def testExtractCbfs(self):
2855 """Test extracting CBFS data"""
2856 data = self._RunExtractCmd('section/cbfs/u-boot')
2857 self.assertEqual(U_BOOT_DATA, data)
2858
2859 def testExtractCbfsCompressed(self):
2860 """Test extracting CBFS compressed data"""
2861 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2862 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2863
2864 def testExtractCbfsRaw(self):
2865 """Test extracting CBFS compressed data without decompressing it"""
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +02002866 bintool = self.comp_bintools['lzma_alone']
2867 self._CheckBintool(bintool)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002868 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +02002869 dtb = bintool.decompress(data)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002870 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2871
Simon Glassf667e452019-07-08 14:25:50 -06002872 def testExtractBadEntry(self):
2873 """Test extracting a bad section path"""
2874 with self.assertRaises(ValueError) as e:
2875 self._RunExtractCmd('section/does-not-exist')
2876 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2877 str(e.exception))
2878
2879 def testExtractMissingFile(self):
2880 """Test extracting file that does not exist"""
2881 with self.assertRaises(IOError) as e:
2882 control.ReadEntry('missing-file', 'name')
2883
2884 def testExtractBadFile(self):
2885 """Test extracting an invalid file"""
2886 fname = os.path.join(self._indir, 'badfile')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002887 tools.write_file(fname, b'')
Simon Glassf667e452019-07-08 14:25:50 -06002888 with self.assertRaises(ValueError) as e:
2889 control.ReadEntry(fname, 'name')
2890
Simon Glass71ce0ba2019-07-08 14:25:52 -06002891 def testExtractCmd(self):
2892 """Test extracting a file fron an image on the command line"""
2893 self._CheckLz4()
2894 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass71ce0ba2019-07-08 14:25:52 -06002895 fname = os.path.join(self._indir, 'output.extact')
Simon Glassf86a7362019-07-20 12:24:10 -06002896 try:
2897 tmpdir, updated_fname = self._SetupImageInTmpdir()
2898 with test_util.capture_sys_output() as (stdout, stderr):
2899 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2900 '-f', fname)
2901 finally:
2902 shutil.rmtree(tmpdir)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002903 data = tools.read_file(fname)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002904 self.assertEqual(U_BOOT_DATA, data)
2905
2906 def testExtractOneEntry(self):
2907 """Test extracting a single entry fron an image """
2908 self._CheckLz4()
2909 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002910 image_fname = tools.get_output_filename('image.bin')
Simon Glass71ce0ba2019-07-08 14:25:52 -06002911 fname = os.path.join(self._indir, 'output.extact')
2912 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
Simon Glassc1aa66e2022-01-29 14:14:04 -07002913 data = tools.read_file(fname)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002914 self.assertEqual(U_BOOT_DATA, data)
2915
2916 def _CheckExtractOutput(self, decomp):
2917 """Helper to test file output with and without decompression
2918
2919 Args:
2920 decomp: True to decompress entry data, False to output it raw
2921 """
2922 def _CheckPresent(entry_path, expect_data, expect_size=None):
2923 """Check and remove expected file
2924
2925 This checks the data/size of a file and removes the file both from
2926 the outfiles set and from the output directory. Once all files are
2927 processed, both the set and directory should be empty.
2928
2929 Args:
2930 entry_path: Entry path
2931 expect_data: Data to expect in file, or None to skip check
2932 expect_size: Size of data to expect in file, or None to skip
2933 """
2934 path = os.path.join(outdir, entry_path)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002935 data = tools.read_file(path)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002936 os.remove(path)
2937 if expect_data:
2938 self.assertEqual(expect_data, data)
2939 elif expect_size:
2940 self.assertEqual(expect_size, len(data))
2941 outfiles.remove(path)
2942
2943 def _CheckDirPresent(name):
2944 """Remove expected directory
2945
2946 This gives an error if the directory does not exist as expected
2947
2948 Args:
2949 name: Name of directory to remove
2950 """
2951 path = os.path.join(outdir, name)
2952 os.rmdir(path)
2953
2954 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002955 image_fname = tools.get_output_filename('image.bin')
Simon Glass71ce0ba2019-07-08 14:25:52 -06002956 outdir = os.path.join(self._indir, 'extract')
2957 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2958
2959 # Create a set of all file that were output (should be 9)
2960 outfiles = set()
2961 for root, dirs, files in os.walk(outdir):
2962 outfiles |= set([os.path.join(root, fname) for fname in files])
2963 self.assertEqual(9, len(outfiles))
2964 self.assertEqual(9, len(einfos))
2965
2966 image = control.images['image']
2967 entries = image.GetEntries()
2968
2969 # Check the 9 files in various ways
2970 section = entries['section']
2971 section_entries = section.GetEntries()
2972 cbfs_entries = section_entries['cbfs'].GetEntries()
2973 _CheckPresent('u-boot', U_BOOT_DATA)
2974 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
2975 dtb_len = EXTRACT_DTB_SIZE
2976 if not decomp:
2977 dtb_len = cbfs_entries['u-boot-dtb'].size
2978 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
2979 if not decomp:
2980 dtb_len = section_entries['u-boot-dtb'].size
2981 _CheckPresent('section/u-boot-dtb', None, dtb_len)
2982
2983 fdtmap = entries['fdtmap']
2984 _CheckPresent('fdtmap', fdtmap.data)
2985 hdr = entries['image-header']
2986 _CheckPresent('image-header', hdr.data)
2987
2988 _CheckPresent('section/root', section.data)
2989 cbfs = section_entries['cbfs']
2990 _CheckPresent('section/cbfs/root', cbfs.data)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002991 data = tools.read_file(image_fname)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002992 _CheckPresent('root', data)
2993
2994 # There should be no files left. Remove all the directories to check.
2995 # If there are any files/dirs remaining, one of these checks will fail.
2996 self.assertEqual(0, len(outfiles))
2997 _CheckDirPresent('section/cbfs')
2998 _CheckDirPresent('section')
2999 _CheckDirPresent('')
3000 self.assertFalse(os.path.exists(outdir))
3001
3002 def testExtractAllEntries(self):
3003 """Test extracting all entries"""
3004 self._CheckLz4()
3005 self._CheckExtractOutput(decomp=True)
3006
3007 def testExtractAllEntriesRaw(self):
3008 """Test extracting all entries without decompressing them"""
3009 self._CheckLz4()
3010 self._CheckExtractOutput(decomp=False)
3011
3012 def testExtractSelectedEntries(self):
3013 """Test extracting some entries"""
3014 self._CheckLz4()
3015 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003016 image_fname = tools.get_output_filename('image.bin')
Simon Glass71ce0ba2019-07-08 14:25:52 -06003017 outdir = os.path.join(self._indir, 'extract')
3018 einfos = control.ExtractEntries(image_fname, None, outdir,
3019 ['*cb*', '*head*'])
3020
3021 # File output is tested by testExtractAllEntries(), so just check that
3022 # the expected entries are selected
3023 names = [einfo.name for einfo in einfos]
3024 self.assertEqual(names,
3025 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
3026
3027 def testExtractNoEntryPaths(self):
3028 """Test extracting some entries"""
3029 self._CheckLz4()
3030 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003031 image_fname = tools.get_output_filename('image.bin')
Simon Glass71ce0ba2019-07-08 14:25:52 -06003032 with self.assertRaises(ValueError) as e:
3033 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassbb5edc12019-07-20 12:24:14 -06003034 self.assertIn('Must specify an entry path to write with -f',
Simon Glass71ce0ba2019-07-08 14:25:52 -06003035 str(e.exception))
3036
3037 def testExtractTooManyEntryPaths(self):
3038 """Test extracting some entries"""
3039 self._CheckLz4()
3040 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003041 image_fname = tools.get_output_filename('image.bin')
Simon Glass71ce0ba2019-07-08 14:25:52 -06003042 with self.assertRaises(ValueError) as e:
3043 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassbb5edc12019-07-20 12:24:14 -06003044 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass71ce0ba2019-07-08 14:25:52 -06003045 str(e.exception))
3046
Simon Glasse2705fa2019-07-08 14:25:53 -06003047 def testPackAlignSection(self):
3048 """Test that sections can have alignment"""
3049 self._DoReadFile('131_pack_align_section.dts')
3050
3051 self.assertIn('image', control.images)
3052 image = control.images['image']
3053 entries = image.GetEntries()
3054 self.assertEqual(3, len(entries))
3055
3056 # First u-boot
3057 self.assertIn('u-boot', entries)
3058 entry = entries['u-boot']
3059 self.assertEqual(0, entry.offset)
3060 self.assertEqual(0, entry.image_pos)
3061 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3062 self.assertEqual(len(U_BOOT_DATA), entry.size)
3063
3064 # Section0
3065 self.assertIn('section0', entries)
3066 section0 = entries['section0']
3067 self.assertEqual(0x10, section0.offset)
3068 self.assertEqual(0x10, section0.image_pos)
3069 self.assertEqual(len(U_BOOT_DATA), section0.size)
3070
3071 # Second u-boot
3072 section_entries = section0.GetEntries()
3073 self.assertIn('u-boot', section_entries)
3074 entry = section_entries['u-boot']
3075 self.assertEqual(0, entry.offset)
3076 self.assertEqual(0x10, entry.image_pos)
3077 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3078 self.assertEqual(len(U_BOOT_DATA), entry.size)
3079
3080 # Section1
3081 self.assertIn('section1', entries)
3082 section1 = entries['section1']
3083 self.assertEqual(0x14, section1.offset)
3084 self.assertEqual(0x14, section1.image_pos)
3085 self.assertEqual(0x20, section1.size)
3086
3087 # Second u-boot
3088 section_entries = section1.GetEntries()
3089 self.assertIn('u-boot', section_entries)
3090 entry = section_entries['u-boot']
3091 self.assertEqual(0, entry.offset)
3092 self.assertEqual(0x14, entry.image_pos)
3093 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3094 self.assertEqual(len(U_BOOT_DATA), entry.size)
3095
3096 # Section2
3097 self.assertIn('section2', section_entries)
3098 section2 = section_entries['section2']
3099 self.assertEqual(0x4, section2.offset)
3100 self.assertEqual(0x18, section2.image_pos)
3101 self.assertEqual(4, section2.size)
3102
3103 # Third u-boot
3104 section_entries = section2.GetEntries()
3105 self.assertIn('u-boot', section_entries)
3106 entry = section_entries['u-boot']
3107 self.assertEqual(0, entry.offset)
3108 self.assertEqual(0x18, entry.image_pos)
3109 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3110 self.assertEqual(len(U_BOOT_DATA), entry.size)
3111
Simon Glass51014aa2019-07-20 12:23:56 -06003112 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3113 dts='132_replace.dts'):
Simon Glass10f9d002019-07-20 12:23:50 -06003114 """Replace an entry in an image
3115
3116 This writes the entry data to update it, then opens the updated file and
3117 returns the value that it now finds there.
3118
3119 Args:
3120 entry_name: Entry name to replace
3121 data: Data to replace it with
3122 decomp: True to compress the data if needed, False if data is
3123 already compressed so should be used as is
Simon Glass51014aa2019-07-20 12:23:56 -06003124 allow_resize: True to allow entries to change size, False to raise
3125 an exception
Simon Glass10f9d002019-07-20 12:23:50 -06003126
3127 Returns:
3128 Tuple:
3129 data from entry
3130 data from fdtmap (excluding header)
Simon Glass51014aa2019-07-20 12:23:56 -06003131 Image object that was modified
Simon Glass10f9d002019-07-20 12:23:50 -06003132 """
Simon Glass51014aa2019-07-20 12:23:56 -06003133 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass10f9d002019-07-20 12:23:50 -06003134 update_dtb=True)[1]
3135
3136 self.assertIn('image', control.images)
3137 image = control.images['image']
3138 entries = image.GetEntries()
3139 orig_dtb_data = entries['u-boot-dtb'].data
3140 orig_fdtmap_data = entries['fdtmap'].data
3141
Simon Glassc1aa66e2022-01-29 14:14:04 -07003142 image_fname = tools.get_output_filename('image.bin')
3143 updated_fname = tools.get_output_filename('image-updated.bin')
3144 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glass51014aa2019-07-20 12:23:56 -06003145 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3146 allow_resize)
Simon Glass10f9d002019-07-20 12:23:50 -06003147 data = control.ReadEntry(updated_fname, entry_name, decomp)
3148
Simon Glass51014aa2019-07-20 12:23:56 -06003149 # The DT data should not change unless resized:
3150 if not allow_resize:
3151 new_dtb_data = entries['u-boot-dtb'].data
3152 self.assertEqual(new_dtb_data, orig_dtb_data)
3153 new_fdtmap_data = entries['fdtmap'].data
3154 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass10f9d002019-07-20 12:23:50 -06003155
Simon Glass51014aa2019-07-20 12:23:56 -06003156 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass10f9d002019-07-20 12:23:50 -06003157
3158 def testReplaceSimple(self):
3159 """Test replacing a single file"""
3160 expected = b'x' * len(U_BOOT_DATA)
Simon Glass51014aa2019-07-20 12:23:56 -06003161 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3162 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06003163 self.assertEqual(expected, data)
3164
3165 # Test that the state looks right. There should be an FDT for the fdtmap
3166 # that we jsut read back in, and it should match what we find in the
3167 # 'control' tables. Checking for an FDT that does not exist should
3168 # return None.
3169 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glass51014aa2019-07-20 12:23:56 -06003170 self.assertIsNotNone(path)
Simon Glass10f9d002019-07-20 12:23:50 -06003171 self.assertEqual(expected_fdtmap, fdtmap)
3172
3173 dtb = state.GetFdtForEtype('fdtmap')
3174 self.assertEqual(dtb.GetContents(), fdtmap)
3175
3176 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3177 self.assertIsNone(missing_path)
3178 self.assertIsNone(missing_fdtmap)
3179
3180 missing_dtb = state.GetFdtForEtype('missing')
3181 self.assertIsNone(missing_dtb)
3182
3183 self.assertEqual('/binman', state.fdt_path_prefix)
3184
3185 def testReplaceResizeFail(self):
3186 """Test replacing a file by something larger"""
3187 expected = U_BOOT_DATA + b'x'
3188 with self.assertRaises(ValueError) as e:
Simon Glass51014aa2019-07-20 12:23:56 -06003189 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3190 dts='139_replace_repack.dts')
Simon Glass10f9d002019-07-20 12:23:50 -06003191 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3192 str(e.exception))
3193
3194 def testReplaceMulti(self):
3195 """Test replacing entry data where multiple images are generated"""
3196 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3197 update_dtb=True)[0]
3198 expected = b'x' * len(U_BOOT_DATA)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003199 updated_fname = tools.get_output_filename('image-updated.bin')
3200 tools.write_file(updated_fname, data)
Simon Glass10f9d002019-07-20 12:23:50 -06003201 entry_name = 'u-boot'
Simon Glass51014aa2019-07-20 12:23:56 -06003202 control.WriteEntry(updated_fname, entry_name, expected,
3203 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06003204 data = control.ReadEntry(updated_fname, entry_name)
3205 self.assertEqual(expected, data)
3206
3207 # Check the state looks right.
3208 self.assertEqual('/binman/image', state.fdt_path_prefix)
3209
3210 # Now check we can write the first image
Simon Glassc1aa66e2022-01-29 14:14:04 -07003211 image_fname = tools.get_output_filename('first-image.bin')
3212 updated_fname = tools.get_output_filename('first-updated.bin')
3213 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glass10f9d002019-07-20 12:23:50 -06003214 entry_name = 'u-boot'
Simon Glass51014aa2019-07-20 12:23:56 -06003215 control.WriteEntry(updated_fname, entry_name, expected,
3216 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06003217 data = control.ReadEntry(updated_fname, entry_name)
3218 self.assertEqual(expected, data)
3219
3220 # Check the state looks right.
3221 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass8beb11e2019-07-08 14:25:47 -06003222
Simon Glass12bb1a92019-07-20 12:23:51 -06003223 def testUpdateFdtAllRepack(self):
3224 """Test that all device trees are updated with offset/size info"""
3225 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3226 SECTION_SIZE = 0x300
3227 DTB_SIZE = 602
3228 FDTMAP_SIZE = 608
3229 base_expected = {
3230 'offset': 0,
3231 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3232 'image-pos': 0,
3233 'section:offset': 0,
3234 'section:size': SECTION_SIZE,
3235 'section:image-pos': 0,
3236 'section/u-boot-dtb:offset': 4,
3237 'section/u-boot-dtb:size': 636,
3238 'section/u-boot-dtb:image-pos': 4,
3239 'u-boot-spl-dtb:offset': SECTION_SIZE,
3240 'u-boot-spl-dtb:size': DTB_SIZE,
3241 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3242 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3243 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3244 'u-boot-tpl-dtb:size': DTB_SIZE,
3245 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3246 'fdtmap:size': FDTMAP_SIZE,
3247 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3248 }
3249 main_expected = {
3250 'section:orig-size': SECTION_SIZE,
3251 'section/u-boot-dtb:orig-offset': 4,
3252 }
3253
3254 # We expect three device-tree files in the output, with the first one
3255 # within a fixed-size section.
3256 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3257 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3258 # main U-Boot tree. All three should have the same positions and offset
3259 # except that the main tree should include the main_expected properties
3260 start = 4
3261 for item in ['', 'spl', 'tpl', None]:
3262 if item is None:
3263 start += 16 # Move past fdtmap header
3264 dtb = fdt.Fdt.FromData(data[start:])
3265 dtb.Scan()
3266 props = self._GetPropTree(dtb,
3267 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3268 prefix='/' if item is None else '/binman/')
3269 expected = dict(base_expected)
3270 if item:
3271 expected[item] = 0
3272 else:
3273 # Main DTB and fdtdec should include the 'orig-' properties
3274 expected.update(main_expected)
3275 # Helpful for debugging:
3276 #for prop in sorted(props):
3277 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3278 self.assertEqual(expected, props)
3279 if item == '':
3280 start = SECTION_SIZE
3281 else:
3282 start += dtb._fdt_obj.totalsize()
3283
Simon Glasseba1f0c2019-07-20 12:23:55 -06003284 def testFdtmapHeaderMiddle(self):
3285 """Test an FDT map in the middle of an image when it should be at end"""
3286 with self.assertRaises(ValueError) as e:
3287 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3288 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3289 str(e.exception))
3290
3291 def testFdtmapHeaderStartBad(self):
3292 """Test an FDT map in middle of an image when it should be at start"""
3293 with self.assertRaises(ValueError) as e:
3294 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3295 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3296 str(e.exception))
3297
3298 def testFdtmapHeaderEndBad(self):
3299 """Test an FDT map at the start of an image when it should be at end"""
3300 with self.assertRaises(ValueError) as e:
3301 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3302 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3303 str(e.exception))
3304
3305 def testFdtmapHeaderNoSize(self):
3306 """Test an image header at the end of an image with undefined size"""
3307 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3308
Simon Glass51014aa2019-07-20 12:23:56 -06003309 def testReplaceResize(self):
3310 """Test replacing a single file in an entry with a larger file"""
3311 expected = U_BOOT_DATA + b'x'
3312 data, _, image = self._RunReplaceCmd('u-boot', expected,
3313 dts='139_replace_repack.dts')
3314 self.assertEqual(expected, data)
3315
3316 entries = image.GetEntries()
3317 dtb_data = entries['u-boot-dtb'].data
3318 dtb = fdt.Fdt.FromData(dtb_data)
3319 dtb.Scan()
3320
3321 # The u-boot section should now be larger in the dtb
3322 node = dtb.GetNode('/binman/u-boot')
3323 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3324
3325 # Same for the fdtmap
3326 fdata = entries['fdtmap'].data
3327 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3328 fdtb.Scan()
3329 fnode = fdtb.GetNode('/u-boot')
3330 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3331
3332 def testReplaceResizeNoRepack(self):
3333 """Test replacing an entry with a larger file when not allowed"""
3334 expected = U_BOOT_DATA + b'x'
3335 with self.assertRaises(ValueError) as e:
3336 self._RunReplaceCmd('u-boot', expected)
3337 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3338 str(e.exception))
3339
Simon Glass61ec04f2019-07-20 12:23:58 -06003340 def testEntryShrink(self):
3341 """Test contracting an entry after it is packed"""
3342 try:
3343 state.SetAllowEntryContraction(True)
3344 data = self._DoReadFileDtb('140_entry_shrink.dts',
3345 update_dtb=True)[0]
3346 finally:
3347 state.SetAllowEntryContraction(False)
3348 self.assertEqual(b'a', data[:1])
3349 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3350 self.assertEqual(b'a', data[-1:])
3351
3352 def testEntryShrinkFail(self):
3353 """Test not being allowed to contract an entry after it is packed"""
3354 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3355
3356 # In this case there is a spare byte at the end of the data. The size of
3357 # the contents is only 1 byte but we still have the size before it
3358 # shrunk.
3359 self.assertEqual(b'a\0', data[:2])
3360 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3361 self.assertEqual(b'a\0', data[-2:])
3362
Simon Glass27145fd2019-07-20 12:24:01 -06003363 def testDescriptorOffset(self):
3364 """Test that the Intel descriptor is always placed at at the start"""
3365 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3366 image = control.images['image']
3367 entries = image.GetEntries()
3368 desc = entries['intel-descriptor']
3369 self.assertEqual(0xff800000, desc.offset);
3370 self.assertEqual(0xff800000, desc.image_pos);
3371
Simon Glasseb0f4a42019-07-20 12:24:06 -06003372 def testReplaceCbfs(self):
3373 """Test replacing a single file in CBFS without changing the size"""
3374 self._CheckLz4()
3375 expected = b'x' * len(U_BOOT_DATA)
3376 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003377 updated_fname = tools.get_output_filename('image-updated.bin')
3378 tools.write_file(updated_fname, data)
Simon Glasseb0f4a42019-07-20 12:24:06 -06003379 entry_name = 'section/cbfs/u-boot'
3380 control.WriteEntry(updated_fname, entry_name, expected,
3381 allow_resize=True)
3382 data = control.ReadEntry(updated_fname, entry_name)
3383 self.assertEqual(expected, data)
3384
3385 def testReplaceResizeCbfs(self):
3386 """Test replacing a single file in CBFS with one of a different size"""
3387 self._CheckLz4()
3388 expected = U_BOOT_DATA + b'x'
3389 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003390 updated_fname = tools.get_output_filename('image-updated.bin')
3391 tools.write_file(updated_fname, data)
Simon Glasseb0f4a42019-07-20 12:24:06 -06003392 entry_name = 'section/cbfs/u-boot'
3393 control.WriteEntry(updated_fname, entry_name, expected,
3394 allow_resize=True)
3395 data = control.ReadEntry(updated_fname, entry_name)
3396 self.assertEqual(expected, data)
3397
Simon Glassa6cb9952019-07-20 12:24:15 -06003398 def _SetupForReplace(self):
3399 """Set up some files to use to replace entries
3400
3401 This generates an image, copies it to a new file, extracts all the files
3402 in it and updates some of them
3403
3404 Returns:
3405 List
3406 Image filename
3407 Output directory
3408 Expected values for updated entries, each a string
3409 """
3410 data = self._DoReadFileRealDtb('143_replace_all.dts')
3411
Simon Glassc1aa66e2022-01-29 14:14:04 -07003412 updated_fname = tools.get_output_filename('image-updated.bin')
3413 tools.write_file(updated_fname, data)
Simon Glassa6cb9952019-07-20 12:24:15 -06003414
3415 outdir = os.path.join(self._indir, 'extract')
3416 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3417
3418 expected1 = b'x' + U_BOOT_DATA + b'y'
3419 u_boot_fname1 = os.path.join(outdir, 'u-boot')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003420 tools.write_file(u_boot_fname1, expected1)
Simon Glassa6cb9952019-07-20 12:24:15 -06003421
3422 expected2 = b'a' + U_BOOT_DATA + b'b'
3423 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003424 tools.write_file(u_boot_fname2, expected2)
Simon Glassa6cb9952019-07-20 12:24:15 -06003425
3426 expected_text = b'not the same text'
3427 text_fname = os.path.join(outdir, 'text')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003428 tools.write_file(text_fname, expected_text)
Simon Glassa6cb9952019-07-20 12:24:15 -06003429
3430 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3431 dtb = fdt.FdtScan(dtb_fname)
3432 node = dtb.GetNode('/binman/text')
3433 node.AddString('my-property', 'the value')
3434 dtb.Sync(auto_resize=True)
3435 dtb.Flush()
3436
3437 return updated_fname, outdir, expected1, expected2, expected_text
3438
3439 def _CheckReplaceMultiple(self, entry_paths):
3440 """Handle replacing the contents of multiple entries
3441
3442 Args:
3443 entry_paths: List of entry paths to replace
3444
3445 Returns:
3446 List
3447 Dict of entries in the image:
3448 key: Entry name
3449 Value: Entry object
3450 Expected values for updated entries, each a string
3451 """
3452 updated_fname, outdir, expected1, expected2, expected_text = (
3453 self._SetupForReplace())
3454 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3455
3456 image = Image.FromFile(updated_fname)
3457 image.LoadData()
3458 return image.GetEntries(), expected1, expected2, expected_text
3459
3460 def testReplaceAll(self):
3461 """Test replacing the contents of all entries"""
3462 entries, expected1, expected2, expected_text = (
3463 self._CheckReplaceMultiple([]))
3464 data = entries['u-boot'].data
3465 self.assertEqual(expected1, data)
3466
3467 data = entries['u-boot2'].data
3468 self.assertEqual(expected2, data)
3469
3470 data = entries['text'].data
3471 self.assertEqual(expected_text, data)
3472
3473 # Check that the device tree is updated
3474 data = entries['u-boot-dtb'].data
3475 dtb = fdt.Fdt.FromData(data)
3476 dtb.Scan()
3477 node = dtb.GetNode('/binman/text')
3478 self.assertEqual('the value', node.props['my-property'].value)
3479
3480 def testReplaceSome(self):
3481 """Test replacing the contents of a few entries"""
3482 entries, expected1, expected2, expected_text = (
3483 self._CheckReplaceMultiple(['u-boot2', 'text']))
3484
3485 # This one should not change
3486 data = entries['u-boot'].data
3487 self.assertEqual(U_BOOT_DATA, data)
3488
3489 data = entries['u-boot2'].data
3490 self.assertEqual(expected2, data)
3491
3492 data = entries['text'].data
3493 self.assertEqual(expected_text, data)
3494
3495 def testReplaceCmd(self):
3496 """Test replacing a file fron an image on the command line"""
3497 self._DoReadFileRealDtb('143_replace_all.dts')
3498
3499 try:
3500 tmpdir, updated_fname = self._SetupImageInTmpdir()
3501
3502 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3503 expected = b'x' * len(U_BOOT_DATA)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003504 tools.write_file(fname, expected)
Simon Glassa6cb9952019-07-20 12:24:15 -06003505
3506 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003507 data = tools.read_file(updated_fname)
Simon Glassa6cb9952019-07-20 12:24:15 -06003508 self.assertEqual(expected, data[:len(expected)])
3509 map_fname = os.path.join(tmpdir, 'image-updated.map')
3510 self.assertFalse(os.path.exists(map_fname))
3511 finally:
3512 shutil.rmtree(tmpdir)
3513
3514 def testReplaceCmdSome(self):
3515 """Test replacing some files fron an image on the command line"""
3516 updated_fname, outdir, expected1, expected2, expected_text = (
3517 self._SetupForReplace())
3518
3519 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3520 'u-boot2', 'text')
3521
Simon Glassc1aa66e2022-01-29 14:14:04 -07003522 tools.prepare_output_dir(None)
Simon Glassa6cb9952019-07-20 12:24:15 -06003523 image = Image.FromFile(updated_fname)
3524 image.LoadData()
3525 entries = image.GetEntries()
3526
3527 # This one should not change
3528 data = entries['u-boot'].data
3529 self.assertEqual(U_BOOT_DATA, data)
3530
3531 data = entries['u-boot2'].data
3532 self.assertEqual(expected2, data)
3533
3534 data = entries['text'].data
3535 self.assertEqual(expected_text, data)
3536
3537 def testReplaceMissing(self):
3538 """Test replacing entries where the file is missing"""
3539 updated_fname, outdir, expected1, expected2, expected_text = (
3540 self._SetupForReplace())
3541
3542 # Remove one of the files, to generate a warning
3543 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3544 os.remove(u_boot_fname1)
3545
3546 with test_util.capture_sys_output() as (stdout, stderr):
3547 control.ReplaceEntries(updated_fname, None, outdir, [])
3548 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass38fdb4c2020-07-09 18:39:39 -06003549 stderr.getvalue())
Simon Glassa6cb9952019-07-20 12:24:15 -06003550
3551 def testReplaceCmdMap(self):
3552 """Test replacing a file fron an image on the command line"""
3553 self._DoReadFileRealDtb('143_replace_all.dts')
3554
3555 try:
3556 tmpdir, updated_fname = self._SetupImageInTmpdir()
3557
3558 fname = os.path.join(self._indir, 'update-u-boot.bin')
3559 expected = b'x' * len(U_BOOT_DATA)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003560 tools.write_file(fname, expected)
Simon Glassa6cb9952019-07-20 12:24:15 -06003561
3562 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3563 '-f', fname, '-m')
3564 map_fname = os.path.join(tmpdir, 'image-updated.map')
3565 self.assertTrue(os.path.exists(map_fname))
3566 finally:
3567 shutil.rmtree(tmpdir)
3568
3569 def testReplaceNoEntryPaths(self):
3570 """Test replacing an entry without an entry path"""
3571 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003572 image_fname = tools.get_output_filename('image.bin')
Simon Glassa6cb9952019-07-20 12:24:15 -06003573 with self.assertRaises(ValueError) as e:
3574 control.ReplaceEntries(image_fname, 'fname', None, [])
3575 self.assertIn('Must specify an entry path to read with -f',
3576 str(e.exception))
3577
3578 def testReplaceTooManyEntryPaths(self):
3579 """Test extracting some entries"""
3580 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003581 image_fname = tools.get_output_filename('image.bin')
Simon Glassa6cb9952019-07-20 12:24:15 -06003582 with self.assertRaises(ValueError) as e:
3583 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3584 self.assertIn('Must specify exactly one entry path to write with -f',
3585 str(e.exception))
3586
Simon Glass2250ee62019-08-24 07:22:48 -06003587 def testPackReset16(self):
3588 """Test that an image with an x86 reset16 region can be created"""
3589 data = self._DoReadFile('144_x86_reset16.dts')
3590 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3591
3592 def testPackReset16Spl(self):
3593 """Test that an image with an x86 reset16-spl region can be created"""
3594 data = self._DoReadFile('145_x86_reset16_spl.dts')
3595 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3596
3597 def testPackReset16Tpl(self):
3598 """Test that an image with an x86 reset16-tpl region can be created"""
3599 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3600 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3601
Simon Glass5af12072019-08-24 07:22:50 -06003602 def testPackIntelFit(self):
3603 """Test that an image with an Intel FIT and pointer can be created"""
3604 data = self._DoReadFile('147_intel_fit.dts')
3605 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3606 fit = data[16:32];
3607 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3608 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3609
3610 image = control.images['image']
3611 entries = image.GetEntries()
3612 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3613 self.assertEqual(expected_ptr, ptr)
3614
3615 def testPackIntelFitMissing(self):
3616 """Test detection of a FIT pointer with not FIT region"""
3617 with self.assertRaises(ValueError) as e:
3618 self._DoReadFile('148_intel_fit_missing.dts')
3619 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3620 str(e.exception))
3621
Simon Glass7c150132019-11-06 17:22:44 -07003622 def _CheckSymbolsTplSection(self, dts, expected_vals):
3623 data = self._DoReadFile(dts)
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003624 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE, *expected_vals)
Simon Glass2090f1e2019-08-24 07:23:00 -06003625 upto1 = 4 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003626 expected1 = tools.get_bytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass2090f1e2019-08-24 07:23:00 -06003627 self.assertEqual(expected1, data[:upto1])
3628
3629 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003630 expected2 = tools.get_bytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass2090f1e2019-08-24 07:23:00 -06003631 self.assertEqual(expected2, data[upto1:upto2])
3632
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003633 upto3 = 0x3c + len(U_BOOT_DATA)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003634 expected3 = tools.get_bytes(0xff, 1) + U_BOOT_DATA
Simon Glass2090f1e2019-08-24 07:23:00 -06003635 self.assertEqual(expected3, data[upto2:upto3])
3636
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003637 expected4 = sym_values + U_BOOT_TPL_DATA[24:]
Simon Glass7c150132019-11-06 17:22:44 -07003638 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3639
3640 def testSymbolsTplSection(self):
3641 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3642 self._SetupSplElf('u_boot_binman_syms')
3643 self._SetupTplElf('u_boot_binman_syms')
3644 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003645 [0x04, 0x20, 0x10 + 0x3c, 0x04])
Simon Glass7c150132019-11-06 17:22:44 -07003646
3647 def testSymbolsTplSectionX86(self):
3648 """Test binman can assign symbols in a section with end-at-4gb"""
3649 self._SetupSplElf('u_boot_binman_syms_x86')
3650 self._SetupTplElf('u_boot_binman_syms_x86')
3651 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003652 [0xffffff04, 0xffffff20, 0xffffff3c,
Simon Glass7c150132019-11-06 17:22:44 -07003653 0x04])
Simon Glass2090f1e2019-08-24 07:23:00 -06003654
Simon Glassbf4d0e22019-08-24 07:23:03 -06003655 def testPackX86RomIfwiSectiom(self):
3656 """Test that a section can be placed in an IFWI region"""
3657 self._SetupIfwi('fitimage.bin')
3658 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3659 self._CheckIfwi(data)
3660
Simon Glassea0fff92019-08-24 07:23:07 -06003661 def testPackFspM(self):
3662 """Test that an image with a FSP memory-init binary can be created"""
3663 data = self._DoReadFile('152_intel_fsp_m.dts')
3664 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3665
Simon Glassbc6a88f2019-10-20 21:31:35 -06003666 def testPackFspS(self):
3667 """Test that an image with a FSP silicon-init binary can be created"""
3668 data = self._DoReadFile('153_intel_fsp_s.dts')
3669 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassea0fff92019-08-24 07:23:07 -06003670
Simon Glass998d1482019-10-20 21:31:36 -06003671 def testPackFspT(self):
3672 """Test that an image with a FSP temp-ram-init binary can be created"""
3673 data = self._DoReadFile('154_intel_fsp_t.dts')
3674 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3675
Simon Glass0dc706f2020-07-09 18:39:31 -06003676 def testMkimage(self):
3677 """Test using mkimage to build an image"""
3678 data = self._DoReadFile('156_mkimage.dts')
3679
3680 # Just check that the data appears in the file somewhere
3681 self.assertIn(U_BOOT_SPL_DATA, data)
3682
Simon Glass4f9ee832022-01-09 20:14:09 -07003683 def testMkimageMissing(self):
3684 """Test that binman still produces an image if mkimage is missing"""
3685 with test_util.capture_sys_output() as (_, stderr):
3686 self._DoTestFile('156_mkimage.dts',
3687 force_missing_bintools='mkimage')
3688 err = stderr.getvalue()
3689 self.assertRegex(err,
3690 "Image 'main-section'.*missing bintools.*: mkimage")
3691
Simon Glassce867ad2020-07-09 18:39:36 -06003692 def testExtblob(self):
3693 """Test an image with an external blob"""
3694 data = self._DoReadFile('157_blob_ext.dts')
3695 self.assertEqual(REFCODE_DATA, data)
3696
3697 def testExtblobMissing(self):
3698 """Test an image with a missing external blob"""
3699 with self.assertRaises(ValueError) as e:
3700 self._DoReadFile('158_blob_ext_missing.dts')
3701 self.assertIn("Filename 'missing-file' not found in input path",
3702 str(e.exception))
3703
Simon Glass4f9f1052020-07-09 18:39:38 -06003704 def testExtblobMissingOk(self):
3705 """Test an image with an missing external blob that is allowed"""
Simon Glassb1cca952020-07-09 18:39:40 -06003706 with test_util.capture_sys_output() as (stdout, stderr):
3707 self._DoTestFile('158_blob_ext_missing.dts', allow_missing=True)
3708 err = stderr.getvalue()
3709 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
3710
3711 def testExtblobMissingOkSect(self):
3712 """Test an image with an missing external blob that is allowed"""
3713 with test_util.capture_sys_output() as (stdout, stderr):
3714 self._DoTestFile('159_blob_ext_missing_sect.dts',
3715 allow_missing=True)
3716 err = stderr.getvalue()
3717 self.assertRegex(err, "Image 'main-section'.*missing.*: "
3718 "blob-ext blob-ext2")
Simon Glass4f9f1052020-07-09 18:39:38 -06003719
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003720 def testPackX86RomMeMissingDesc(self):
3721 """Test that an missing Intel descriptor entry is allowed"""
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003722 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass52b10dd2020-07-25 15:11:19 -06003723 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003724 err = stderr.getvalue()
3725 self.assertRegex(err,
3726 "Image 'main-section'.*missing.*: intel-descriptor")
3727
3728 def testPackX86RomMissingIfwi(self):
3729 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3730 self._SetupIfwi('fitimage.bin')
3731 pathname = os.path.join(self._indir, 'fitimage.bin')
3732 os.remove(pathname)
3733 with test_util.capture_sys_output() as (stdout, stderr):
3734 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3735 err = stderr.getvalue()
3736 self.assertRegex(err, "Image 'main-section'.*missing.*: intel-ifwi")
3737
Simon Glass8d2ef3e2022-02-11 13:23:21 -07003738 def testPackOverlapZero(self):
Simon Glassb3295fd2020-07-09 18:39:42 -06003739 """Test that zero-size overlapping regions are ignored"""
3740 self._DoTestFile('160_pack_overlap_zero.dts')
3741
Alper Nebi Yasak21353312022-02-08 01:08:04 +03003742 def _CheckSimpleFitData(self, fit_data, kernel_data, fdt1_data):
Simon Glassfdc34362020-07-09 18:39:45 -06003743 # The data should be inside the FIT
3744 dtb = fdt.Fdt.FromData(fit_data)
3745 dtb.Scan()
3746 fnode = dtb.GetNode('/images/kernel')
3747 self.assertIn('data', fnode.props)
3748
3749 fname = os.path.join(self._indir, 'fit_data.fit')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003750 tools.write_file(fname, fit_data)
3751 out = tools.run('dumpimage', '-l', fname)
Simon Glassfdc34362020-07-09 18:39:45 -06003752
3753 # Check a few features to make sure the plumbing works. We don't need
3754 # to test the operation of mkimage or dumpimage here. First convert the
3755 # output into a dict where the keys are the fields printed by dumpimage
3756 # and the values are a list of values for each field
3757 lines = out.splitlines()
3758
3759 # Converts "Compression: gzip compressed" into two groups:
3760 # 'Compression' and 'gzip compressed'
3761 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3762 vals = collections.defaultdict(list)
3763 for line in lines:
3764 mat = re_line.match(line)
3765 vals[mat.group(1)].append(mat.group(2))
3766
3767 self.assertEquals('FIT description: test-desc', lines[0])
3768 self.assertIn('Created:', lines[1])
3769 self.assertIn('Image 0 (kernel)', vals)
3770 self.assertIn('Hash value', vals)
3771 data_sizes = vals.get('Data Size')
3772 self.assertIsNotNone(data_sizes)
3773 self.assertEqual(2, len(data_sizes))
3774 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
Alper Nebi Yasak21353312022-02-08 01:08:04 +03003775 self.assertEqual(len(kernel_data), int(data_sizes[0].split()[0]))
3776 self.assertEqual(len(fdt1_data), int(data_sizes[1].split()[0]))
3777
Alper Nebi Yasake7368782022-03-27 18:31:47 +03003778 # Check if entry listing correctly omits /images/
3779 image = control.images['image']
3780 fit_entry = image.GetEntries()['fit']
3781 subentries = list(fit_entry.GetEntries().keys())
3782 expected = ['kernel', 'fdt-1']
3783 self.assertEqual(expected, subentries)
3784
Alper Nebi Yasak21353312022-02-08 01:08:04 +03003785 def testSimpleFit(self):
3786 """Test an image with a FIT inside"""
3787 data = self._DoReadFile('161_fit.dts')
3788 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3789 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3790 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3791
3792 self._CheckSimpleFitData(fit_data, U_BOOT_DATA, U_BOOT_SPL_DTB_DATA)
3793
3794 def testSimpleFitExpandsSubentries(self):
3795 """Test that FIT images expand their subentries"""
3796 data = self._DoReadFileDtb('161_fit.dts', use_expanded=True)[0]
3797 self.assertEqual(U_BOOT_EXP_DATA, data[:len(U_BOOT_EXP_DATA)])
3798 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3799 fit_data = data[len(U_BOOT_EXP_DATA):-len(U_BOOT_NODTB_DATA)]
3800
3801 self._CheckSimpleFitData(fit_data, U_BOOT_EXP_DATA, U_BOOT_SPL_DTB_DATA)
Simon Glassfdc34362020-07-09 18:39:45 -06003802
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003803 def testSimpleFitImagePos(self):
3804 """Test that we have correct image-pos for FIT subentries"""
3805 data, _, _, out_dtb_fname = self._DoReadFileDtb('161_fit.dts',
3806 update_dtb=True)
3807 dtb = fdt.Fdt(out_dtb_fname)
3808 dtb.Scan()
3809 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3810
Simon Glass38397d02022-03-05 20:19:01 -07003811 self.maxDiff = None
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003812 self.assertEqual({
3813 'image-pos': 0,
3814 'offset': 0,
3815 'size': 1890,
3816
3817 'u-boot:image-pos': 0,
3818 'u-boot:offset': 0,
3819 'u-boot:size': 4,
3820
3821 'fit:image-pos': 4,
3822 'fit:offset': 4,
3823 'fit:size': 1840,
3824
Simon Glass38397d02022-03-05 20:19:01 -07003825 'fit/images/kernel:image-pos': 304,
3826 'fit/images/kernel:offset': 300,
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003827 'fit/images/kernel:size': 4,
3828
Simon Glass38397d02022-03-05 20:19:01 -07003829 'fit/images/kernel/u-boot:image-pos': 304,
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003830 'fit/images/kernel/u-boot:offset': 0,
3831 'fit/images/kernel/u-boot:size': 4,
3832
Simon Glass38397d02022-03-05 20:19:01 -07003833 'fit/images/fdt-1:image-pos': 552,
3834 'fit/images/fdt-1:offset': 548,
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003835 'fit/images/fdt-1:size': 6,
3836
Simon Glass38397d02022-03-05 20:19:01 -07003837 'fit/images/fdt-1/u-boot-spl-dtb:image-pos': 552,
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003838 'fit/images/fdt-1/u-boot-spl-dtb:offset': 0,
3839 'fit/images/fdt-1/u-boot-spl-dtb:size': 6,
3840
3841 'u-boot-nodtb:image-pos': 1844,
3842 'u-boot-nodtb:offset': 1844,
3843 'u-boot-nodtb:size': 46,
3844 }, props)
3845
3846 # Actually check the data is where we think it is
3847 for node, expected in [
3848 ("u-boot", U_BOOT_DATA),
3849 ("fit/images/kernel", U_BOOT_DATA),
3850 ("fit/images/kernel/u-boot", U_BOOT_DATA),
3851 ("fit/images/fdt-1", U_BOOT_SPL_DTB_DATA),
3852 ("fit/images/fdt-1/u-boot-spl-dtb", U_BOOT_SPL_DTB_DATA),
3853 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
3854 ]:
3855 image_pos = props[f"{node}:image-pos"]
3856 size = props[f"{node}:size"]
3857 self.assertEqual(len(expected), size)
3858 self.assertEqual(expected, data[image_pos:image_pos+size])
3859
Simon Glassfdc34362020-07-09 18:39:45 -06003860 def testFitExternal(self):
Simon Glasse9d336d2020-09-01 05:13:55 -06003861 """Test an image with an FIT with external images"""
Simon Glassfdc34362020-07-09 18:39:45 -06003862 data = self._DoReadFile('162_fit_external.dts')
3863 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3864
Simon Glass8bc78b72022-01-09 20:13:39 -07003865 # Size of the external-data region as set up by mkimage
3866 external_data_size = len(U_BOOT_DATA) + 2
3867 expected_size = (len(U_BOOT_DATA) + 0x400 +
Simon Glassc1aa66e2022-01-29 14:14:04 -07003868 tools.align(external_data_size, 4) +
Simon Glass8bc78b72022-01-09 20:13:39 -07003869 len(U_BOOT_NODTB_DATA))
3870
Simon Glassfdc34362020-07-09 18:39:45 -06003871 # The data should be outside the FIT
3872 dtb = fdt.Fdt.FromData(fit_data)
3873 dtb.Scan()
3874 fnode = dtb.GetNode('/images/kernel')
3875 self.assertNotIn('data', fnode.props)
Simon Glass8bc78b72022-01-09 20:13:39 -07003876 self.assertEqual(len(U_BOOT_DATA),
3877 fdt_util.fdt32_to_cpu(fnode.props['data-size'].value))
3878 fit_pos = 0x400;
3879 self.assertEqual(
3880 fit_pos,
3881 fdt_util.fdt32_to_cpu(fnode.props['data-position'].value))
3882
3883 self.assertEquals(expected_size, len(data))
3884 actual_pos = len(U_BOOT_DATA) + fit_pos
3885 self.assertEqual(U_BOOT_DATA + b'aa',
3886 data[actual_pos:actual_pos + external_data_size])
Simon Glass12bb1a92019-07-20 12:23:51 -06003887
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003888 def testFitExternalImagePos(self):
3889 """Test that we have correct image-pos for external FIT subentries"""
3890 data, _, _, out_dtb_fname = self._DoReadFileDtb('162_fit_external.dts',
3891 update_dtb=True)
3892 dtb = fdt.Fdt(out_dtb_fname)
3893 dtb.Scan()
3894 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3895
3896 self.assertEqual({
3897 'image-pos': 0,
3898 'offset': 0,
3899 'size': 1082,
3900
3901 'u-boot:image-pos': 0,
3902 'u-boot:offset': 0,
3903 'u-boot:size': 4,
3904
3905 'fit:size': 1032,
3906 'fit:offset': 4,
3907 'fit:image-pos': 4,
3908
3909 'fit/images/kernel:size': 4,
3910 'fit/images/kernel:offset': 1024,
3911 'fit/images/kernel:image-pos': 1028,
3912
3913 'fit/images/kernel/u-boot:size': 4,
3914 'fit/images/kernel/u-boot:offset': 0,
3915 'fit/images/kernel/u-boot:image-pos': 1028,
3916
3917 'fit/images/fdt-1:size': 2,
3918 'fit/images/fdt-1:offset': 1028,
3919 'fit/images/fdt-1:image-pos': 1032,
3920
3921 'fit/images/fdt-1/_testing:size': 2,
3922 'fit/images/fdt-1/_testing:offset': 0,
3923 'fit/images/fdt-1/_testing:image-pos': 1032,
3924
3925 'u-boot-nodtb:image-pos': 1036,
3926 'u-boot-nodtb:offset': 1036,
3927 'u-boot-nodtb:size': 46,
3928 }, props)
3929
3930 # Actually check the data is where we think it is
3931 for node, expected in [
3932 ("u-boot", U_BOOT_DATA),
3933 ("fit/images/kernel", U_BOOT_DATA),
3934 ("fit/images/kernel/u-boot", U_BOOT_DATA),
3935 ("fit/images/fdt-1", b'aa'),
3936 ("fit/images/fdt-1/_testing", b'aa'),
3937 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
3938 ]:
3939 image_pos = props[f"{node}:image-pos"]
3940 size = props[f"{node}:size"]
3941 self.assertEqual(len(expected), size)
3942 self.assertEqual(expected, data[image_pos:image_pos+size])
3943
Simon Glass4f9ee832022-01-09 20:14:09 -07003944 def testFitMissing(self):
3945 """Test that binman still produces a FIT image if mkimage is missing"""
3946 with test_util.capture_sys_output() as (_, stderr):
3947 self._DoTestFile('162_fit_external.dts',
3948 force_missing_bintools='mkimage')
3949 err = stderr.getvalue()
3950 self.assertRegex(err,
3951 "Image 'main-section'.*missing bintools.*: mkimage")
3952
Alper Nebi Yasak8001d0b2020-08-31 12:58:18 +03003953 def testSectionIgnoreHashSignature(self):
3954 """Test that sections ignore hash, signature nodes for its data"""
3955 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
3956 expected = (U_BOOT_DATA + U_BOOT_DATA)
3957 self.assertEqual(expected, data)
3958
Alper Nebi Yasak3fdeb142020-08-31 12:58:19 +03003959 def testPadInSections(self):
3960 """Test pad-before, pad-after for entries in sections"""
Simon Glassf90d9062020-10-26 17:40:09 -06003961 data, _, _, out_dtb_fname = self._DoReadFileDtb(
3962 '166_pad_in_sections.dts', update_dtb=True)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003963 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
3964 U_BOOT_DATA + tools.get_bytes(ord('!'), 6) +
Alper Nebi Yasak3fdeb142020-08-31 12:58:19 +03003965 U_BOOT_DATA)
3966 self.assertEqual(expected, data)
3967
Simon Glassf90d9062020-10-26 17:40:09 -06003968 dtb = fdt.Fdt(out_dtb_fname)
3969 dtb.Scan()
3970 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
3971 expected = {
3972 'image-pos': 0,
3973 'offset': 0,
3974 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
3975
3976 'section:image-pos': 0,
3977 'section:offset': 0,
3978 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
3979
3980 'section/before:image-pos': 0,
3981 'section/before:offset': 0,
3982 'section/before:size': len(U_BOOT_DATA),
3983
3984 'section/u-boot:image-pos': 4,
3985 'section/u-boot:offset': 4,
3986 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
3987
3988 'section/after:image-pos': 26,
3989 'section/after:offset': 26,
3990 'section/after:size': len(U_BOOT_DATA),
3991 }
3992 self.assertEqual(expected, props)
3993
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03003994 def testFitImageSubentryAlignment(self):
3995 """Test relative alignability of FIT image subentries"""
Alper Nebi Yasakf3078d42022-02-08 01:08:07 +03003996 self._SetupSplElf()
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03003997 entry_args = {
3998 'test-id': TEXT_DATA,
3999 }
4000 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
4001 entry_args=entry_args)
4002 dtb = fdt.Fdt.FromData(data)
4003 dtb.Scan()
4004
4005 node = dtb.GetNode('/images/kernel')
4006 data = dtb.GetProps(node)["data"].bytes
4007 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
Simon Glassc1aa66e2022-01-29 14:14:04 -07004008 expected = (tools.get_bytes(0, 0x20) + U_BOOT_SPL_DATA +
4009 tools.get_bytes(0, align_pad) + U_BOOT_DATA)
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03004010 self.assertEqual(expected, data)
4011
4012 node = dtb.GetNode('/images/fdt-1')
4013 data = dtb.GetProps(node)["data"].bytes
Simon Glassc1aa66e2022-01-29 14:14:04 -07004014 expected = (U_BOOT_SPL_DTB_DATA + tools.get_bytes(0, 20) +
4015 tools.to_bytes(TEXT_DATA) + tools.get_bytes(0, 30) +
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03004016 U_BOOT_DTB_DATA)
4017 self.assertEqual(expected, data)
4018
4019 def testFitExtblobMissingOk(self):
4020 """Test a FIT with a missing external blob that is allowed"""
4021 with test_util.capture_sys_output() as (stdout, stderr):
4022 self._DoTestFile('168_fit_missing_blob.dts',
4023 allow_missing=True)
4024 err = stderr.getvalue()
Simon Glassb2381432020-09-06 10:39:09 -06004025 self.assertRegex(err, "Image 'main-section'.*missing.*: atf-bl31")
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03004026
Simon Glass3decfa32020-09-01 05:13:54 -06004027 def testBlobNamedByArgMissing(self):
4028 """Test handling of a missing entry arg"""
4029 with self.assertRaises(ValueError) as e:
4030 self._DoReadFile('068_blob_named_by_arg.dts')
4031 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
4032 str(e.exception))
4033
Simon Glassdc2f81a2020-09-01 05:13:58 -06004034 def testPackBl31(self):
4035 """Test that an image with an ATF BL31 binary can be created"""
4036 data = self._DoReadFile('169_atf_bl31.dts')
4037 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
4038
Samuel Holland18bd4552020-10-21 21:12:15 -05004039 def testPackScp(self):
4040 """Test that an image with an SCP binary can be created"""
4041 data = self._DoReadFile('172_scp.dts')
4042 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
4043
Simon Glass6cf99532020-09-01 05:13:59 -06004044 def testFitFdt(self):
4045 """Test an image with an FIT with multiple FDT images"""
4046 def _CheckFdt(seq, expected_data):
4047 """Check the FDT nodes
4048
4049 Args:
4050 seq: Sequence number to check (0 or 1)
4051 expected_data: Expected contents of 'data' property
4052 """
4053 name = 'fdt-%d' % seq
4054 fnode = dtb.GetNode('/images/%s' % name)
4055 self.assertIsNotNone(fnode)
4056 self.assertEqual({'description','type', 'compression', 'data'},
4057 set(fnode.props.keys()))
4058 self.assertEqual(expected_data, fnode.props['data'].bytes)
4059 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
4060 fnode.props['description'].value)
Jan Kiszkab2106612022-02-28 17:06:20 +01004061 self.assertEqual(fnode.subnodes[0].name, 'hash')
Simon Glass6cf99532020-09-01 05:13:59 -06004062
4063 def _CheckConfig(seq, expected_data):
4064 """Check the configuration nodes
4065
4066 Args:
4067 seq: Sequence number to check (0 or 1)
4068 expected_data: Expected contents of 'data' property
4069 """
4070 cnode = dtb.GetNode('/configurations')
4071 self.assertIn('default', cnode.props)
Simon Glassc0f1ebe2020-09-06 10:39:08 -06004072 self.assertEqual('config-2', cnode.props['default'].value)
Simon Glass6cf99532020-09-01 05:13:59 -06004073
4074 name = 'config-%d' % seq
4075 fnode = dtb.GetNode('/configurations/%s' % name)
4076 self.assertIsNotNone(fnode)
4077 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
4078 set(fnode.props.keys()))
4079 self.assertEqual('conf-test-fdt%d.dtb' % seq,
4080 fnode.props['description'].value)
4081 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
4082
4083 entry_args = {
4084 'of-list': 'test-fdt1 test-fdt2',
Simon Glassc0f1ebe2020-09-06 10:39:08 -06004085 'default-dt': 'test-fdt2',
Simon Glass6cf99532020-09-01 05:13:59 -06004086 }
4087 data = self._DoReadFileDtb(
Bin Mengaa75ce92021-05-10 20:23:32 +08004088 '170_fit_fdt.dts',
Simon Glass6cf99532020-09-01 05:13:59 -06004089 entry_args=entry_args,
4090 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4091 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4092 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4093
4094 dtb = fdt.Fdt.FromData(fit_data)
4095 dtb.Scan()
4096 fnode = dtb.GetNode('/images/kernel')
4097 self.assertIn('data', fnode.props)
4098
4099 # Check all the properties in fdt-1 and fdt-2
4100 _CheckFdt(1, TEST_FDT1_DATA)
4101 _CheckFdt(2, TEST_FDT2_DATA)
4102
4103 # Check configurations
4104 _CheckConfig(1, TEST_FDT1_DATA)
4105 _CheckConfig(2, TEST_FDT2_DATA)
4106
4107 def testFitFdtMissingList(self):
4108 """Test handling of a missing 'of-list' entry arg"""
4109 with self.assertRaises(ValueError) as e:
Bin Mengaa75ce92021-05-10 20:23:32 +08004110 self._DoReadFile('170_fit_fdt.dts')
Simon Glass6cf99532020-09-01 05:13:59 -06004111 self.assertIn("Generator node requires 'of-list' entry argument",
4112 str(e.exception))
4113
4114 def testFitFdtEmptyList(self):
4115 """Test handling of an empty 'of-list' entry arg"""
4116 entry_args = {
4117 'of-list': '',
4118 }
4119 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
4120
4121 def testFitFdtMissingProp(self):
4122 """Test handling of a missing 'fit,fdt-list' property"""
4123 with self.assertRaises(ValueError) as e:
4124 self._DoReadFile('171_fit_fdt_missing_prop.dts')
4125 self.assertIn("Generator node requires 'fit,fdt-list' property",
4126 str(e.exception))
Simon Glassdc2f81a2020-09-01 05:13:58 -06004127
Simon Glassc0f1ebe2020-09-06 10:39:08 -06004128 def testFitFdtMissing(self):
4129 """Test handling of a missing 'default-dt' entry arg"""
4130 entry_args = {
4131 'of-list': 'test-fdt1 test-fdt2',
4132 }
4133 with self.assertRaises(ValueError) as e:
4134 self._DoReadFileDtb(
Bin Mengaa75ce92021-05-10 20:23:32 +08004135 '170_fit_fdt.dts',
Simon Glassc0f1ebe2020-09-06 10:39:08 -06004136 entry_args=entry_args,
4137 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4138 self.assertIn("Generated 'default' node requires default-dt entry argument",
4139 str(e.exception))
4140
4141 def testFitFdtNotInList(self):
4142 """Test handling of a default-dt that is not in the of-list"""
4143 entry_args = {
4144 'of-list': 'test-fdt1 test-fdt2',
4145 'default-dt': 'test-fdt3',
4146 }
4147 with self.assertRaises(ValueError) as e:
4148 self._DoReadFileDtb(
Bin Mengaa75ce92021-05-10 20:23:32 +08004149 '170_fit_fdt.dts',
Simon Glassc0f1ebe2020-09-06 10:39:08 -06004150 entry_args=entry_args,
4151 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4152 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
4153 str(e.exception))
4154
Simon Glassb2381432020-09-06 10:39:09 -06004155 def testFitExtblobMissingHelp(self):
4156 """Test display of help messages when an external blob is missing"""
4157 control.missing_blob_help = control._ReadMissingBlobHelp()
4158 control.missing_blob_help['wibble'] = 'Wibble test'
4159 control.missing_blob_help['another'] = 'Another test'
4160 with test_util.capture_sys_output() as (stdout, stderr):
4161 self._DoTestFile('168_fit_missing_blob.dts',
4162 allow_missing=True)
4163 err = stderr.getvalue()
4164
4165 # We can get the tag from the name, the type or the missing-msg
4166 # property. Check all three.
4167 self.assertIn('You may need to build ARM Trusted', err)
4168 self.assertIn('Wibble test', err)
4169 self.assertIn('Another test', err)
4170
Simon Glass204aa782020-09-06 10:35:32 -06004171 def testMissingBlob(self):
4172 """Test handling of a blob containing a missing file"""
4173 with self.assertRaises(ValueError) as e:
4174 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
4175 self.assertIn("Filename 'missing' not found in input path",
4176 str(e.exception))
4177
Simon Glassfb91d562020-09-06 10:35:33 -06004178 def testEnvironment(self):
4179 """Test adding a U-Boot environment"""
4180 data = self._DoReadFile('174_env.dts')
4181 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
4182 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4183 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4184 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
4185 env)
4186
4187 def testEnvironmentNoSize(self):
4188 """Test that a missing 'size' property is detected"""
4189 with self.assertRaises(ValueError) as e:
Simon Glassa4dfe3e2020-10-26 17:40:00 -06004190 self._DoTestFile('175_env_no_size.dts')
Simon Glassfb91d562020-09-06 10:35:33 -06004191 self.assertIn("'u-boot-env' entry must have a size property",
4192 str(e.exception))
4193
4194 def testEnvironmentTooSmall(self):
4195 """Test handling of an environment that does not fit"""
4196 with self.assertRaises(ValueError) as e:
Simon Glassa4dfe3e2020-10-26 17:40:00 -06004197 self._DoTestFile('176_env_too_small.dts')
Simon Glassfb91d562020-09-06 10:35:33 -06004198
4199 # checksum, start byte, environment with \0 terminator, final \0
4200 need = 4 + 1 + len(ENV_DATA) + 1 + 1
4201 short = need - 0x8
4202 self.assertIn("too small to hold data (need %#x more bytes)" % short,
4203 str(e.exception))
4204
Simon Glassf2c0dd82020-10-26 17:40:01 -06004205 def testSkipAtStart(self):
4206 """Test handling of skip-at-start section"""
4207 data = self._DoReadFile('177_skip_at_start.dts')
4208 self.assertEqual(U_BOOT_DATA, data)
4209
4210 image = control.images['image']
4211 entries = image.GetEntries()
4212 section = entries['section']
4213 self.assertEqual(0, section.offset)
4214 self.assertEqual(len(U_BOOT_DATA), section.size)
4215 self.assertEqual(U_BOOT_DATA, section.GetData())
4216
4217 entry = section.GetEntries()['u-boot']
4218 self.assertEqual(16, entry.offset)
4219 self.assertEqual(len(U_BOOT_DATA), entry.size)
4220 self.assertEqual(U_BOOT_DATA, entry.data)
4221
4222 def testSkipAtStartPad(self):
4223 """Test handling of skip-at-start section with padded entry"""
4224 data = self._DoReadFile('178_skip_at_start_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004225 before = tools.get_bytes(0, 8)
4226 after = tools.get_bytes(0, 4)
Simon Glassf2c0dd82020-10-26 17:40:01 -06004227 all = before + U_BOOT_DATA + after
4228 self.assertEqual(all, data)
4229
4230 image = control.images['image']
4231 entries = image.GetEntries()
4232 section = entries['section']
4233 self.assertEqual(0, section.offset)
4234 self.assertEqual(len(all), section.size)
4235 self.assertEqual(all, section.GetData())
4236
4237 entry = section.GetEntries()['u-boot']
4238 self.assertEqual(16, entry.offset)
4239 self.assertEqual(len(all), entry.size)
4240 self.assertEqual(U_BOOT_DATA, entry.data)
4241
4242 def testSkipAtStartSectionPad(self):
4243 """Test handling of skip-at-start section with padding"""
4244 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004245 before = tools.get_bytes(0, 8)
4246 after = tools.get_bytes(0, 4)
Simon Glassf2c0dd82020-10-26 17:40:01 -06004247 all = before + U_BOOT_DATA + after
Simon Glassd1d3ad72020-10-26 17:40:13 -06004248 self.assertEqual(all, data)
Simon Glassf2c0dd82020-10-26 17:40:01 -06004249
4250 image = control.images['image']
4251 entries = image.GetEntries()
4252 section = entries['section']
4253 self.assertEqual(0, section.offset)
4254 self.assertEqual(len(all), section.size)
Simon Glass63e7ba62020-10-26 17:40:16 -06004255 self.assertEqual(U_BOOT_DATA, section.data)
Simon Glassd1d3ad72020-10-26 17:40:13 -06004256 self.assertEqual(all, section.GetPaddedData())
Simon Glassf2c0dd82020-10-26 17:40:01 -06004257
4258 entry = section.GetEntries()['u-boot']
4259 self.assertEqual(16, entry.offset)
4260 self.assertEqual(len(U_BOOT_DATA), entry.size)
4261 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassfb91d562020-09-06 10:35:33 -06004262
Simon Glass7d398bb2020-10-26 17:40:14 -06004263 def testSectionPad(self):
4264 """Testing padding with sections"""
4265 data = self._DoReadFile('180_section_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004266 expected = (tools.get_bytes(ord('&'), 3) +
4267 tools.get_bytes(ord('!'), 5) +
Simon Glass7d398bb2020-10-26 17:40:14 -06004268 U_BOOT_DATA +
Simon Glassc1aa66e2022-01-29 14:14:04 -07004269 tools.get_bytes(ord('!'), 1) +
4270 tools.get_bytes(ord('&'), 2))
Simon Glass7d398bb2020-10-26 17:40:14 -06004271 self.assertEqual(expected, data)
4272
4273 def testSectionAlign(self):
4274 """Testing alignment with sections"""
4275 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4276 expected = (b'\0' + # fill section
Simon Glassc1aa66e2022-01-29 14:14:04 -07004277 tools.get_bytes(ord('&'), 1) + # padding to section align
Simon Glass7d398bb2020-10-26 17:40:14 -06004278 b'\0' + # fill section
Simon Glassc1aa66e2022-01-29 14:14:04 -07004279 tools.get_bytes(ord('!'), 3) + # padding to u-boot align
Simon Glass7d398bb2020-10-26 17:40:14 -06004280 U_BOOT_DATA +
Simon Glassc1aa66e2022-01-29 14:14:04 -07004281 tools.get_bytes(ord('!'), 4) + # padding to u-boot size
4282 tools.get_bytes(ord('!'), 4)) # padding to section size
Simon Glass7d398bb2020-10-26 17:40:14 -06004283 self.assertEqual(expected, data)
4284
Simon Glass8f5ef892020-10-26 17:40:25 -06004285 def testCompressImage(self):
4286 """Test compression of the entire image"""
4287 self._CheckLz4()
4288 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4289 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4290 dtb = fdt.Fdt(out_dtb_fname)
4291 dtb.Scan()
4292 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4293 'uncomp-size'])
4294 orig = self._decompress(data)
4295 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4296
4297 # Do a sanity check on various fields
4298 image = control.images['image']
4299 entries = image.GetEntries()
4300 self.assertEqual(2, len(entries))
4301
4302 entry = entries['blob']
4303 self.assertEqual(COMPRESS_DATA, entry.data)
4304 self.assertEqual(len(COMPRESS_DATA), entry.size)
4305
4306 entry = entries['u-boot']
4307 self.assertEqual(U_BOOT_DATA, entry.data)
4308 self.assertEqual(len(U_BOOT_DATA), entry.size)
4309
4310 self.assertEqual(len(data), image.size)
4311 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4312 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4313 orig = self._decompress(image.data)
4314 self.assertEqual(orig, image.uncomp_data)
4315
4316 expected = {
4317 'blob:offset': 0,
4318 'blob:size': len(COMPRESS_DATA),
4319 'u-boot:offset': len(COMPRESS_DATA),
4320 'u-boot:size': len(U_BOOT_DATA),
4321 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4322 'offset': 0,
4323 'image-pos': 0,
4324 'size': len(data),
4325 }
4326 self.assertEqual(expected, props)
4327
4328 def testCompressImageLess(self):
4329 """Test compression where compression reduces the image size"""
4330 self._CheckLz4()
4331 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4332 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4333 dtb = fdt.Fdt(out_dtb_fname)
4334 dtb.Scan()
4335 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4336 'uncomp-size'])
4337 orig = self._decompress(data)
4338
4339 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
4340
4341 # Do a sanity check on various fields
4342 image = control.images['image']
4343 entries = image.GetEntries()
4344 self.assertEqual(2, len(entries))
4345
4346 entry = entries['blob']
4347 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4348 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4349
4350 entry = entries['u-boot']
4351 self.assertEqual(U_BOOT_DATA, entry.data)
4352 self.assertEqual(len(U_BOOT_DATA), entry.size)
4353
4354 self.assertEqual(len(data), image.size)
4355 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4356 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4357 image.uncomp_size)
4358 orig = self._decompress(image.data)
4359 self.assertEqual(orig, image.uncomp_data)
4360
4361 expected = {
4362 'blob:offset': 0,
4363 'blob:size': len(COMPRESS_DATA_BIG),
4364 'u-boot:offset': len(COMPRESS_DATA_BIG),
4365 'u-boot:size': len(U_BOOT_DATA),
4366 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4367 'offset': 0,
4368 'image-pos': 0,
4369 'size': len(data),
4370 }
4371 self.assertEqual(expected, props)
4372
4373 def testCompressSectionSize(self):
4374 """Test compression of a section with a fixed size"""
4375 self._CheckLz4()
4376 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4377 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4378 dtb = fdt.Fdt(out_dtb_fname)
4379 dtb.Scan()
4380 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4381 'uncomp-size'])
4382 orig = self._decompress(data)
4383 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4384 expected = {
4385 'section/blob:offset': 0,
4386 'section/blob:size': len(COMPRESS_DATA),
4387 'section/u-boot:offset': len(COMPRESS_DATA),
4388 'section/u-boot:size': len(U_BOOT_DATA),
4389 'section:offset': 0,
4390 'section:image-pos': 0,
4391 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4392 'section:size': 0x30,
4393 'offset': 0,
4394 'image-pos': 0,
4395 'size': 0x30,
4396 }
4397 self.assertEqual(expected, props)
4398
4399 def testCompressSection(self):
4400 """Test compression of a section with no fixed size"""
4401 self._CheckLz4()
4402 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4403 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4404 dtb = fdt.Fdt(out_dtb_fname)
4405 dtb.Scan()
4406 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4407 'uncomp-size'])
4408 orig = self._decompress(data)
4409 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4410 expected = {
4411 'section/blob:offset': 0,
4412 'section/blob:size': len(COMPRESS_DATA),
4413 'section/u-boot:offset': len(COMPRESS_DATA),
4414 'section/u-boot:size': len(U_BOOT_DATA),
4415 'section:offset': 0,
4416 'section:image-pos': 0,
4417 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4418 'section:size': len(data),
4419 'offset': 0,
4420 'image-pos': 0,
4421 'size': len(data),
4422 }
4423 self.assertEqual(expected, props)
4424
Stefan Herbrechtsmeierc3665a82022-08-19 16:25:31 +02004425 def testLz4Missing(self):
4426 """Test that binman still produces an image if lz4 is missing"""
4427 with test_util.capture_sys_output() as (_, stderr):
4428 self._DoTestFile('185_compress_section.dts',
4429 force_missing_bintools='lz4')
4430 err = stderr.getvalue()
4431 self.assertRegex(err,
4432 "Image 'main-section'.*missing bintools.*: lz4")
4433
Simon Glass8f5ef892020-10-26 17:40:25 -06004434 def testCompressExtra(self):
4435 """Test compression of a section with no fixed size"""
4436 self._CheckLz4()
4437 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4438 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4439 dtb = fdt.Fdt(out_dtb_fname)
4440 dtb.Scan()
4441 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4442 'uncomp-size'])
4443
4444 base = data[len(U_BOOT_DATA):]
4445 self.assertEquals(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
4446 rest = base[len(U_BOOT_DATA):]
4447
4448 # Check compressed data
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +02004449 bintool = self.comp_bintools['lz4']
4450 expect1 = bintool.compress(COMPRESS_DATA + U_BOOT_DATA)
Stefan Herbrechtsmeierfa24f552022-08-19 16:25:23 +02004451 data1 = rest[:len(expect1)]
4452 section1 = self._decompress(data1)
4453 self.assertEquals(expect1, data1)
Simon Glass8f5ef892020-10-26 17:40:25 -06004454 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, section1)
4455 rest1 = rest[len(expect1):]
4456
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +02004457 expect2 = bintool.compress(COMPRESS_DATA + COMPRESS_DATA)
Stefan Herbrechtsmeierfa24f552022-08-19 16:25:23 +02004458 data2 = rest1[:len(expect2)]
4459 section2 = self._decompress(data2)
4460 self.assertEquals(expect2, data2)
Simon Glass8f5ef892020-10-26 17:40:25 -06004461 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA, section2)
4462 rest2 = rest1[len(expect2):]
4463
4464 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4465 len(expect2) + len(U_BOOT_DATA))
4466 #self.assertEquals(expect_size, len(data))
4467
4468 #self.assertEquals(U_BOOT_DATA, rest2)
4469
4470 self.maxDiff = None
4471 expected = {
4472 'u-boot:offset': 0,
4473 'u-boot:image-pos': 0,
4474 'u-boot:size': len(U_BOOT_DATA),
4475
4476 'base:offset': len(U_BOOT_DATA),
4477 'base:image-pos': len(U_BOOT_DATA),
4478 'base:size': len(data) - len(U_BOOT_DATA),
4479 'base/u-boot:offset': 0,
4480 'base/u-boot:image-pos': len(U_BOOT_DATA),
4481 'base/u-boot:size': len(U_BOOT_DATA),
4482 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4483 len(expect2),
4484 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4485 len(expect2),
4486 'base/u-boot2:size': len(U_BOOT_DATA),
4487
4488 'base/section:offset': len(U_BOOT_DATA),
4489 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4490 'base/section:size': len(expect1),
4491 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4492 'base/section/blob:offset': 0,
4493 'base/section/blob:size': len(COMPRESS_DATA),
4494 'base/section/u-boot:offset': len(COMPRESS_DATA),
4495 'base/section/u-boot:size': len(U_BOOT_DATA),
4496
4497 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4498 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4499 'base/section2:size': len(expect2),
4500 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4501 'base/section2/blob:offset': 0,
4502 'base/section2/blob:size': len(COMPRESS_DATA),
4503 'base/section2/blob2:offset': len(COMPRESS_DATA),
4504 'base/section2/blob2:size': len(COMPRESS_DATA),
4505
4506 'offset': 0,
4507 'image-pos': 0,
4508 'size': len(data),
4509 }
4510 self.assertEqual(expected, props)
4511
Simon Glass870a9ea2021-01-06 21:35:15 -07004512 def testSymbolsSubsection(self):
4513 """Test binman can assign symbols from a subsection"""
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03004514 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glass870a9ea2021-01-06 21:35:15 -07004515
Simon Glass939d1062021-01-06 21:35:16 -07004516 def testReadImageEntryArg(self):
4517 """Test reading an image that would need an entry arg to generate"""
4518 entry_args = {
4519 'cros-ec-rw-path': 'ecrw.bin',
4520 }
4521 data = self.data = self._DoReadFileDtb(
4522 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4523 entry_args=entry_args)
4524
Simon Glassc1aa66e2022-01-29 14:14:04 -07004525 image_fname = tools.get_output_filename('image.bin')
Simon Glass939d1062021-01-06 21:35:16 -07004526 orig_image = control.images['image']
4527
4528 # This should not generate an error about the missing 'cros-ec-rw-path'
4529 # since we are reading the image from a file. Compare with
4530 # testEntryArgsRequired()
4531 image = Image.FromFile(image_fname)
4532 self.assertEqual(orig_image.GetEntries().keys(),
4533 image.GetEntries().keys())
4534
Simon Glass6eb99322021-01-06 21:35:18 -07004535 def testFilesAlign(self):
4536 """Test alignment with files"""
4537 data = self._DoReadFile('190_files_align.dts')
4538
4539 # The first string is 15 bytes so will align to 16
4540 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4541 self.assertEqual(expect, data)
4542
Simon Glass5c6ba712021-01-06 21:35:19 -07004543 def testReadImageSkip(self):
4544 """Test reading an image and accessing its FDT map"""
4545 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004546 image_fname = tools.get_output_filename('image.bin')
Simon Glass5c6ba712021-01-06 21:35:19 -07004547 orig_image = control.images['image']
4548 image = Image.FromFile(image_fname)
4549 self.assertEqual(orig_image.GetEntries().keys(),
4550 image.GetEntries().keys())
4551
4552 orig_entry = orig_image.GetEntries()['fdtmap']
4553 entry = image.GetEntries()['fdtmap']
4554 self.assertEqual(orig_entry.offset, entry.offset)
4555 self.assertEqual(orig_entry.size, entry.size)
4556 self.assertEqual(16, entry.image_pos)
4557
4558 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4559
4560 self.assertEquals(U_BOOT_DATA, u_boot.ReadData())
4561
Simon Glass77a64e02021-03-18 20:24:57 +13004562 def testTplNoDtb(self):
4563 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
Simon Glass0fe44dc2021-04-25 08:39:32 +12004564 self._SetupTplElf()
Simon Glass77a64e02021-03-18 20:24:57 +13004565 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4566 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4567 data[:len(U_BOOT_TPL_NODTB_DATA)])
4568
Simon Glassd26efc82021-03-18 20:24:58 +13004569 def testTplBssPad(self):
4570 """Test that we can pad TPL's BSS with zeros"""
4571 # ELF file with a '__bss_size' symbol
4572 self._SetupTplElf()
4573 data = self._DoReadFile('193_tpl_bss_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004574 self.assertEqual(U_BOOT_TPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glassd26efc82021-03-18 20:24:58 +13004575 data)
4576
4577 def testTplBssPadMissing(self):
4578 """Test that a missing symbol is detected"""
4579 self._SetupTplElf('u_boot_ucode_ptr')
4580 with self.assertRaises(ValueError) as e:
4581 self._DoReadFile('193_tpl_bss_pad.dts')
4582 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4583 str(e.exception))
4584
Simon Glass06684922021-03-18 20:25:07 +13004585 def checkDtbSizes(self, data, pad_len, start):
4586 """Check the size arguments in a dtb embedded in an image
4587
4588 Args:
4589 data: The image data
4590 pad_len: Length of the pad section in the image, in bytes
4591 start: Start offset of the devicetree to examine, within the image
4592
4593 Returns:
4594 Size of the devicetree in bytes
4595 """
4596 dtb_data = data[start:]
4597 dtb = fdt.Fdt.FromData(dtb_data)
4598 fdt_size = dtb.GetFdtObj().totalsize()
4599 dtb.Scan()
4600 props = self._GetPropTree(dtb, 'size')
4601 self.assertEqual({
4602 'size': len(data),
4603 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4604 'u-boot-spl/u-boot-spl-dtb:size': 801,
4605 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4606 'u-boot-spl:size': 860,
4607 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4608 'u-boot/u-boot-dtb:size': 781,
4609 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4610 'u-boot:size': 827,
4611 }, props)
4612 return fdt_size
4613
4614 def testExpanded(self):
4615 """Test that an expanded entry type is selected when needed"""
4616 self._SetupSplElf()
4617 self._SetupTplElf()
4618
4619 # SPL has a devicetree, TPL does not
4620 entry_args = {
4621 'spl-dtb': '1',
4622 'spl-bss-pad': 'y',
4623 'tpl-dtb': '',
4624 }
4625 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4626 entry_args=entry_args)
4627 image = control.images['image']
4628 entries = image.GetEntries()
4629 self.assertEqual(3, len(entries))
4630
4631 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4632 self.assertIn('u-boot', entries)
4633 entry = entries['u-boot']
4634 self.assertEqual('u-boot-expanded', entry.etype)
4635 subent = entry.GetEntries()
4636 self.assertEqual(2, len(subent))
4637 self.assertIn('u-boot-nodtb', subent)
4638 self.assertIn('u-boot-dtb', subent)
4639
4640 # Second, u-boot-spl, which should be expanded into three parts
4641 self.assertIn('u-boot-spl', entries)
4642 entry = entries['u-boot-spl']
4643 self.assertEqual('u-boot-spl-expanded', entry.etype)
4644 subent = entry.GetEntries()
4645 self.assertEqual(3, len(subent))
4646 self.assertIn('u-boot-spl-nodtb', subent)
4647 self.assertIn('u-boot-spl-bss-pad', subent)
4648 self.assertIn('u-boot-spl-dtb', subent)
4649
4650 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4651 # devicetree
4652 self.assertIn('u-boot-tpl', entries)
4653 entry = entries['u-boot-tpl']
4654 self.assertEqual('u-boot-tpl', entry.etype)
4655 self.assertEqual(None, entry.GetEntries())
4656
4657 def testExpandedTpl(self):
4658 """Test that an expanded entry type is selected for TPL when needed"""
4659 self._SetupTplElf()
4660
4661 entry_args = {
4662 'tpl-bss-pad': 'y',
4663 'tpl-dtb': 'y',
4664 }
4665 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4666 entry_args=entry_args)
4667 image = control.images['image']
4668 entries = image.GetEntries()
4669 self.assertEqual(1, len(entries))
4670
4671 # We only have u-boot-tpl, which be expanded
4672 self.assertIn('u-boot-tpl', entries)
4673 entry = entries['u-boot-tpl']
4674 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4675 subent = entry.GetEntries()
4676 self.assertEqual(3, len(subent))
4677 self.assertIn('u-boot-tpl-nodtb', subent)
4678 self.assertIn('u-boot-tpl-bss-pad', subent)
4679 self.assertIn('u-boot-tpl-dtb', subent)
4680
4681 def testExpandedNoPad(self):
4682 """Test an expanded entry without BSS pad enabled"""
4683 self._SetupSplElf()
4684 self._SetupTplElf()
4685
4686 # SPL has a devicetree, TPL does not
4687 entry_args = {
4688 'spl-dtb': 'something',
4689 'spl-bss-pad': 'n',
4690 'tpl-dtb': '',
4691 }
4692 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4693 entry_args=entry_args)
4694 image = control.images['image']
4695 entries = image.GetEntries()
4696
4697 # Just check u-boot-spl, which should be expanded into two parts
4698 self.assertIn('u-boot-spl', entries)
4699 entry = entries['u-boot-spl']
4700 self.assertEqual('u-boot-spl-expanded', entry.etype)
4701 subent = entry.GetEntries()
4702 self.assertEqual(2, len(subent))
4703 self.assertIn('u-boot-spl-nodtb', subent)
4704 self.assertIn('u-boot-spl-dtb', subent)
4705
4706 def testExpandedTplNoPad(self):
4707 """Test that an expanded entry type with padding disabled in TPL"""
4708 self._SetupTplElf()
4709
4710 entry_args = {
4711 'tpl-bss-pad': '',
4712 'tpl-dtb': 'y',
4713 }
4714 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4715 entry_args=entry_args)
4716 image = control.images['image']
4717 entries = image.GetEntries()
4718 self.assertEqual(1, len(entries))
4719
4720 # We only have u-boot-tpl, which be expanded
4721 self.assertIn('u-boot-tpl', entries)
4722 entry = entries['u-boot-tpl']
4723 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4724 subent = entry.GetEntries()
4725 self.assertEqual(2, len(subent))
4726 self.assertIn('u-boot-tpl-nodtb', subent)
4727 self.assertIn('u-boot-tpl-dtb', subent)
4728
4729 def testFdtInclude(self):
4730 """Test that an Fdt is update within all binaries"""
4731 self._SetupSplElf()
4732 self._SetupTplElf()
4733
4734 # SPL has a devicetree, TPL does not
4735 self.maxDiff = None
4736 entry_args = {
4737 'spl-dtb': '1',
4738 'spl-bss-pad': 'y',
4739 'tpl-dtb': '',
4740 }
4741 # Build the image. It includes two separate devicetree binaries, each
4742 # with their own contents, but all contain the binman definition.
4743 data = self._DoReadFileDtb(
4744 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4745 update_dtb=True, entry_args=entry_args)[0]
4746 pad_len = 10
4747
4748 # Check the U-Boot dtb
4749 start = len(U_BOOT_NODTB_DATA)
4750 fdt_size = self.checkDtbSizes(data, pad_len, start)
4751
4752 # Now check SPL
4753 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4754 fdt_size = self.checkDtbSizes(data, pad_len, start)
4755
4756 # TPL has no devicetree
4757 start += fdt_size + len(U_BOOT_TPL_DATA)
4758 self.assertEqual(len(data), start)
Simon Glass7d398bb2020-10-26 17:40:14 -06004759
Simon Glass3d433382021-03-21 18:24:30 +13004760 def testSymbolsExpanded(self):
4761 """Test binman can assign symbols in expanded entries"""
4762 entry_args = {
4763 'spl-dtb': '1',
4764 }
4765 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4766 U_BOOT_SPL_DTB_DATA, 0x38,
4767 entry_args=entry_args, use_expanded=True)
4768
Simon Glass189f2912021-03-21 18:24:31 +13004769 def testCollection(self):
4770 """Test a collection"""
4771 data = self._DoReadFile('198_collection.dts')
4772 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
Simon Glassc1aa66e2022-01-29 14:14:04 -07004773 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
4774 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
Simon Glass189f2912021-03-21 18:24:31 +13004775 data)
4776
Simon Glass631f7522021-03-21 18:24:32 +13004777 def testCollectionSection(self):
4778 """Test a collection where a section must be built first"""
4779 # Sections never have their contents when GetData() is called, but when
Simon Glassd34bcdd2021-11-23 11:03:47 -07004780 # BuildSectionData() is called with required=True, a section will force
Simon Glass631f7522021-03-21 18:24:32 +13004781 # building the contents, producing an error is anything is still
4782 # missing.
4783 data = self._DoReadFile('199_collection_section.dts')
4784 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
Simon Glassc1aa66e2022-01-29 14:14:04 -07004785 self.assertEqual(section + U_BOOT_DATA + tools.get_bytes(0xff, 2) +
4786 section + tools.get_bytes(0xfe, 3) + U_BOOT_DATA,
Simon Glass631f7522021-03-21 18:24:32 +13004787 data)
4788
Simon Glass5ff9fed2021-03-21 18:24:33 +13004789 def testAlignDefault(self):
4790 """Test that default alignment works on sections"""
4791 data = self._DoReadFile('200_align_default.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004792 expected = (U_BOOT_DATA + tools.get_bytes(0, 8 - len(U_BOOT_DATA)) +
Simon Glass5ff9fed2021-03-21 18:24:33 +13004793 U_BOOT_DATA)
4794 # Special alignment for section
Simon Glassc1aa66e2022-01-29 14:14:04 -07004795 expected += tools.get_bytes(0, 32 - len(expected))
Simon Glass5ff9fed2021-03-21 18:24:33 +13004796 # No alignment within the nested section
4797 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
4798 # Now the final piece, which should be default-aligned
Simon Glassc1aa66e2022-01-29 14:14:04 -07004799 expected += tools.get_bytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
Simon Glass5ff9fed2021-03-21 18:24:33 +13004800 self.assertEqual(expected, data)
Simon Glass631f7522021-03-21 18:24:32 +13004801
Bin Meng4c4d6072021-05-10 20:23:33 +08004802 def testPackOpenSBI(self):
4803 """Test that an image with an OpenSBI binary can be created"""
4804 data = self._DoReadFile('201_opensbi.dts')
4805 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
4806
Simon Glassc69d19c2021-07-06 10:36:37 -06004807 def testSectionsSingleThread(self):
4808 """Test sections without multithreading"""
4809 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
Simon Glassc1aa66e2022-01-29 14:14:04 -07004810 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4811 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
4812 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glassc69d19c2021-07-06 10:36:37 -06004813 self.assertEqual(expected, data)
4814
4815 def testThreadTimeout(self):
4816 """Test handling a thread that takes too long"""
4817 with self.assertRaises(ValueError) as e:
4818 self._DoTestFile('202_section_timeout.dts',
4819 test_section_timeout=True)
Simon Glassb2dfe832021-10-18 12:13:15 -06004820 self.assertIn("Timed out obtaining contents", str(e.exception))
Simon Glassc69d19c2021-07-06 10:36:37 -06004821
Simon Glass03ebc202021-07-06 10:36:41 -06004822 def testTiming(self):
4823 """Test output of timing information"""
4824 data = self._DoReadFile('055_sections.dts')
4825 with test_util.capture_sys_output() as (stdout, stderr):
4826 state.TimingShow()
4827 self.assertIn('read:', stdout.getvalue())
4828 self.assertIn('compress:', stdout.getvalue())
4829
Simon Glass0427bed2021-11-03 21:09:18 -06004830 def testUpdateFdtInElf(self):
4831 """Test that we can update the devicetree in an ELF file"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02004832 if not elf.ELF_TOOLS:
4833 self.skipTest('Python elftools not available')
Simon Glass0427bed2021-11-03 21:09:18 -06004834 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4835 outfile = os.path.join(self._indir, 'u-boot.out')
4836 begin_sym = 'dtb_embed_begin'
4837 end_sym = 'dtb_embed_end'
4838 retcode = self._DoTestFile(
4839 '060_fdt_update.dts', update_dtb=True,
4840 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4841 self.assertEqual(0, retcode)
4842
4843 # Check that the output file does in fact contact a dtb with the binman
4844 # definition in the correct place
4845 syms = elf.GetSymbolFileOffset(infile,
4846 ['dtb_embed_begin', 'dtb_embed_end'])
Simon Glassc1aa66e2022-01-29 14:14:04 -07004847 data = tools.read_file(outfile)
Simon Glass0427bed2021-11-03 21:09:18 -06004848 dtb_data = data[syms['dtb_embed_begin'].offset:
4849 syms['dtb_embed_end'].offset]
4850
4851 dtb = fdt.Fdt.FromData(dtb_data)
4852 dtb.Scan()
4853 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4854 self.assertEqual({
4855 'image-pos': 0,
4856 'offset': 0,
4857 '_testing:offset': 32,
4858 '_testing:size': 2,
4859 '_testing:image-pos': 32,
4860 'section@0/u-boot:offset': 0,
4861 'section@0/u-boot:size': len(U_BOOT_DATA),
4862 'section@0/u-boot:image-pos': 0,
4863 'section@0:offset': 0,
4864 'section@0:size': 16,
4865 'section@0:image-pos': 0,
4866
4867 'section@1/u-boot:offset': 0,
4868 'section@1/u-boot:size': len(U_BOOT_DATA),
4869 'section@1/u-boot:image-pos': 16,
4870 'section@1:offset': 16,
4871 'section@1:size': 16,
4872 'section@1:image-pos': 16,
4873 'size': 40
4874 }, props)
4875
4876 def testUpdateFdtInElfInvalid(self):
4877 """Test that invalid args are detected with --update-fdt-in-elf"""
4878 with self.assertRaises(ValueError) as e:
4879 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
4880 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
4881 str(e.exception))
4882
4883 def testUpdateFdtInElfNoSyms(self):
4884 """Test that missing symbols are detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02004885 if not elf.ELF_TOOLS:
4886 self.skipTest('Python elftools not available')
Simon Glass0427bed2021-11-03 21:09:18 -06004887 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4888 outfile = ''
4889 begin_sym = 'wrong_begin'
4890 end_sym = 'wrong_end'
4891 with self.assertRaises(ValueError) as e:
4892 self._DoTestFile(
4893 '060_fdt_update.dts',
4894 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4895 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
4896 str(e.exception))
4897
4898 def testUpdateFdtInElfTooSmall(self):
4899 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02004900 if not elf.ELF_TOOLS:
4901 self.skipTest('Python elftools not available')
Simon Glass0427bed2021-11-03 21:09:18 -06004902 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
4903 outfile = os.path.join(self._indir, 'u-boot.out')
4904 begin_sym = 'dtb_embed_begin'
4905 end_sym = 'dtb_embed_end'
4906 with self.assertRaises(ValueError) as e:
4907 self._DoTestFile(
4908 '060_fdt_update.dts', update_dtb=True,
4909 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4910 self.assertRegex(
4911 str(e.exception),
4912 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
4913
Simon Glassc475dec2021-11-23 11:03:42 -07004914 def testVersion(self):
4915 """Test we can get the binman version"""
4916 version = '(unreleased)'
4917 self.assertEqual(version, state.GetVersion(self._indir))
4918
4919 with self.assertRaises(SystemExit):
4920 with test_util.capture_sys_output() as (_, stderr):
4921 self._DoBinman('-V')
4922 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
4923
4924 # Try running the tool too, just to be safe
4925 result = self._RunBinman('-V')
4926 self.assertEqual('Binman %s\n' % version, result.stderr)
4927
4928 # Set up a version file to make sure that works
4929 version = 'v2025.01-rc2'
Simon Glassc1aa66e2022-01-29 14:14:04 -07004930 tools.write_file(os.path.join(self._indir, 'version'), version,
Simon Glassc475dec2021-11-23 11:03:42 -07004931 binary=False)
4932 self.assertEqual(version, state.GetVersion(self._indir))
4933
Simon Glass943bf782021-11-23 21:09:50 -07004934 def testAltFormat(self):
4935 """Test that alternative formats can be used to extract"""
4936 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
4937
4938 try:
4939 tmpdir, updated_fname = self._SetupImageInTmpdir()
4940 with test_util.capture_sys_output() as (stdout, _):
4941 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
4942 self.assertEqual(
4943 '''Flag (-F) Entry type Description
4944fdt fdtmap Extract the devicetree blob from the fdtmap
4945''',
4946 stdout.getvalue())
4947
4948 dtb = os.path.join(tmpdir, 'fdt.dtb')
4949 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
4950 dtb, 'fdtmap')
4951
4952 # Check that we can read it and it can be scanning, meaning it does
4953 # not have a 16-byte fdtmap header
Simon Glassc1aa66e2022-01-29 14:14:04 -07004954 data = tools.read_file(dtb)
Simon Glass943bf782021-11-23 21:09:50 -07004955 dtb = fdt.Fdt.FromData(data)
4956 dtb.Scan()
4957
4958 # Now check u-boot which has no alt_format
4959 fname = os.path.join(tmpdir, 'fdt.dtb')
4960 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
4961 '-f', fname, 'u-boot')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004962 data = tools.read_file(fname)
Simon Glass943bf782021-11-23 21:09:50 -07004963 self.assertEqual(U_BOOT_DATA, data)
4964
4965 finally:
4966 shutil.rmtree(tmpdir)
4967
Simon Glasscc2c5002021-11-23 21:09:52 -07004968 def testExtblobList(self):
4969 """Test an image with an external blob list"""
4970 data = self._DoReadFile('215_blob_ext_list.dts')
4971 self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
4972
4973 def testExtblobListMissing(self):
4974 """Test an image with a missing external blob"""
4975 with self.assertRaises(ValueError) as e:
4976 self._DoReadFile('216_blob_ext_list_missing.dts')
4977 self.assertIn("Filename 'missing-file' not found in input path",
4978 str(e.exception))
4979
4980 def testExtblobListMissingOk(self):
4981 """Test an image with an missing external blob that is allowed"""
4982 with test_util.capture_sys_output() as (stdout, stderr):
4983 self._DoTestFile('216_blob_ext_list_missing.dts',
4984 allow_missing=True)
4985 err = stderr.getvalue()
4986 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
4987
Simon Glass75989722021-11-23 21:08:59 -07004988 def testFip(self):
4989 """Basic test of generation of an ARM Firmware Image Package (FIP)"""
4990 data = self._DoReadFile('203_fip.dts')
4991 hdr, fents = fip_util.decode_fip(data)
4992 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
4993 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
4994 self.assertEqual(0x123, hdr.flags)
4995
4996 self.assertEqual(2, len(fents))
4997
4998 fent = fents[0]
4999 self.assertEqual(
5000 bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
5001 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
5002 self.assertEqual('soc-fw', fent.fip_type)
5003 self.assertEqual(0x88, fent.offset)
5004 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5005 self.assertEqual(0x123456789abcdef, fent.flags)
5006 self.assertEqual(ATF_BL31_DATA, fent.data)
5007 self.assertEqual(True, fent.valid)
5008
5009 fent = fents[1]
5010 self.assertEqual(
5011 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
5012 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
5013 self.assertEqual('scp-fwu-cfg', fent.fip_type)
5014 self.assertEqual(0x8c, fent.offset)
5015 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5016 self.assertEqual(0, fent.flags)
5017 self.assertEqual(ATF_BL2U_DATA, fent.data)
5018 self.assertEqual(True, fent.valid)
5019
5020 def testFipOther(self):
5021 """Basic FIP with something that isn't a external blob"""
5022 data = self._DoReadFile('204_fip_other.dts')
5023 hdr, fents = fip_util.decode_fip(data)
5024
5025 self.assertEqual(2, len(fents))
5026 fent = fents[1]
5027 self.assertEqual('rot-cert', fent.fip_type)
5028 self.assertEqual(b'aa', fent.data)
5029
Simon Glass75989722021-11-23 21:08:59 -07005030 def testFipNoType(self):
5031 """FIP with an entry of an unknown type"""
5032 with self.assertRaises(ValueError) as e:
5033 self._DoReadFile('205_fip_no_type.dts')
5034 self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
5035 str(e.exception))
5036
5037 def testFipUuid(self):
5038 """Basic FIP with a manual uuid"""
5039 data = self._DoReadFile('206_fip_uuid.dts')
5040 hdr, fents = fip_util.decode_fip(data)
5041
5042 self.assertEqual(2, len(fents))
5043 fent = fents[1]
5044 self.assertEqual(None, fent.fip_type)
5045 self.assertEqual(
5046 bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
5047 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
5048 fent.uuid)
5049 self.assertEqual(U_BOOT_DATA, fent.data)
5050
5051 def testFipLs(self):
5052 """Test listing a FIP"""
5053 data = self._DoReadFileRealDtb('207_fip_ls.dts')
5054 hdr, fents = fip_util.decode_fip(data)
5055
5056 try:
5057 tmpdir, updated_fname = self._SetupImageInTmpdir()
5058 with test_util.capture_sys_output() as (stdout, stderr):
5059 self._DoBinman('ls', '-i', updated_fname)
5060 finally:
5061 shutil.rmtree(tmpdir)
5062 lines = stdout.getvalue().splitlines()
5063 expected = [
5064'Name Image-pos Size Entry-type Offset Uncomp-size',
5065'----------------------------------------------------------------',
5066'main-section 0 2d3 section 0',
5067' atf-fip 0 90 atf-fip 0',
5068' soc-fw 88 4 blob-ext 88',
5069' u-boot 8c 4 u-boot 8c',
5070' fdtmap 90 243 fdtmap 90',
5071]
5072 self.assertEqual(expected, lines)
5073
5074 image = control.images['image']
5075 entries = image.GetEntries()
5076 fdtmap = entries['fdtmap']
5077
5078 fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
5079 magic = fdtmap_data[:8]
5080 self.assertEqual(b'_FDTMAP_', magic)
Simon Glassc1aa66e2022-01-29 14:14:04 -07005081 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass75989722021-11-23 21:08:59 -07005082
5083 fdt_data = fdtmap_data[16:]
5084 dtb = fdt.Fdt.FromData(fdt_data)
5085 dtb.Scan()
5086 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
5087 self.assertEqual({
5088 'atf-fip/soc-fw:image-pos': 136,
5089 'atf-fip/soc-fw:offset': 136,
5090 'atf-fip/soc-fw:size': 4,
5091 'atf-fip/u-boot:image-pos': 140,
5092 'atf-fip/u-boot:offset': 140,
5093 'atf-fip/u-boot:size': 4,
5094 'atf-fip:image-pos': 0,
5095 'atf-fip:offset': 0,
5096 'atf-fip:size': 144,
5097 'image-pos': 0,
5098 'offset': 0,
5099 'fdtmap:image-pos': fdtmap.image_pos,
5100 'fdtmap:offset': fdtmap.offset,
5101 'fdtmap:size': len(fdtmap_data),
5102 'size': len(data),
5103 }, props)
5104
5105 def testFipExtractOneEntry(self):
5106 """Test extracting a single entry fron an FIP"""
5107 self._DoReadFileRealDtb('207_fip_ls.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07005108 image_fname = tools.get_output_filename('image.bin')
Simon Glass75989722021-11-23 21:08:59 -07005109 fname = os.path.join(self._indir, 'output.extact')
5110 control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
Simon Glassc1aa66e2022-01-29 14:14:04 -07005111 data = tools.read_file(fname)
Simon Glass75989722021-11-23 21:08:59 -07005112 self.assertEqual(U_BOOT_DATA, data)
5113
5114 def testFipReplace(self):
5115 """Test replacing a single file in a FIP"""
Simon Glassc1aa66e2022-01-29 14:14:04 -07005116 expected = U_BOOT_DATA + tools.get_bytes(0x78, 50)
Simon Glass75989722021-11-23 21:08:59 -07005117 data = self._DoReadFileRealDtb('208_fip_replace.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07005118 updated_fname = tools.get_output_filename('image-updated.bin')
5119 tools.write_file(updated_fname, data)
Simon Glass75989722021-11-23 21:08:59 -07005120 entry_name = 'atf-fip/u-boot'
5121 control.WriteEntry(updated_fname, entry_name, expected,
5122 allow_resize=True)
5123 actual = control.ReadEntry(updated_fname, entry_name)
5124 self.assertEqual(expected, actual)
5125
Simon Glassc1aa66e2022-01-29 14:14:04 -07005126 new_data = tools.read_file(updated_fname)
Simon Glass75989722021-11-23 21:08:59 -07005127 hdr, fents = fip_util.decode_fip(new_data)
5128
5129 self.assertEqual(2, len(fents))
5130
5131 # Check that the FIP entry is updated
5132 fent = fents[1]
5133 self.assertEqual(0x8c, fent.offset)
5134 self.assertEqual(len(expected), fent.size)
5135 self.assertEqual(0, fent.flags)
5136 self.assertEqual(expected, fent.data)
5137 self.assertEqual(True, fent.valid)
5138
5139 def testFipMissing(self):
5140 with test_util.capture_sys_output() as (stdout, stderr):
5141 self._DoTestFile('209_fip_missing.dts', allow_missing=True)
5142 err = stderr.getvalue()
5143 self.assertRegex(err, "Image 'main-section'.*missing.*: rmm-fw")
5144
5145 def testFipSize(self):
5146 """Test a FIP with a size property"""
5147 data = self._DoReadFile('210_fip_size.dts')
5148 self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
5149 hdr, fents = fip_util.decode_fip(data)
5150 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5151 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5152
5153 self.assertEqual(1, len(fents))
5154
5155 fent = fents[0]
5156 self.assertEqual('soc-fw', fent.fip_type)
5157 self.assertEqual(0x60, fent.offset)
5158 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5159 self.assertEqual(ATF_BL31_DATA, fent.data)
5160 self.assertEqual(True, fent.valid)
5161
5162 rest = data[0x60 + len(ATF_BL31_DATA):0x100]
Simon Glassc1aa66e2022-01-29 14:14:04 -07005163 self.assertEqual(tools.get_bytes(0xff, len(rest)), rest)
Simon Glass75989722021-11-23 21:08:59 -07005164
5165 def testFipBadAlign(self):
5166 """Test that an invalid alignment value in a FIP is detected"""
5167 with self.assertRaises(ValueError) as e:
5168 self._DoTestFile('211_fip_bad_align.dts')
5169 self.assertIn(
5170 "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
5171 str(e.exception))
5172
5173 def testFipCollection(self):
5174 """Test using a FIP in a collection"""
5175 data = self._DoReadFile('212_fip_collection.dts')
5176 entry1 = control.images['image'].GetEntries()['collection']
5177 data1 = data[:entry1.size]
5178 hdr1, fents2 = fip_util.decode_fip(data1)
5179
5180 entry2 = control.images['image'].GetEntries()['atf-fip']
5181 data2 = data[entry2.offset:entry2.offset + entry2.size]
5182 hdr1, fents2 = fip_util.decode_fip(data2)
5183
5184 # The 'collection' entry should have U-Boot included at the end
5185 self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
5186 self.assertEqual(data1, data2 + U_BOOT_DATA)
5187 self.assertEqual(U_BOOT_DATA, data1[-4:])
5188
5189 # There should be a U-Boot after the final FIP
5190 self.assertEqual(U_BOOT_DATA, data[-4:])
Simon Glassc69d19c2021-07-06 10:36:37 -06005191
Simon Glass32d4f102022-01-12 13:10:35 -07005192 def testFakeBlob(self):
5193 """Test handling of faking an external blob"""
5194 with test_util.capture_sys_output() as (stdout, stderr):
5195 self._DoTestFile('217_fake_blob.dts', allow_missing=True,
5196 allow_fake_blobs=True)
5197 err = stderr.getvalue()
5198 self.assertRegex(
5199 err,
5200 "Image '.*' has faked external blobs and is non-functional: .*")
Simon Glass32d4f102022-01-12 13:10:35 -07005201
Simon Glassf4590e02022-01-09 20:13:46 -07005202 def testExtblobListFaked(self):
5203 """Test an extblob with missing external blob that are faked"""
5204 with test_util.capture_sys_output() as (stdout, stderr):
5205 self._DoTestFile('216_blob_ext_list_missing.dts',
5206 allow_fake_blobs=True)
5207 err = stderr.getvalue()
5208 self.assertRegex(err, "Image 'main-section'.*faked.*: blob-ext-list")
5209
Simon Glass56ee85e2022-01-09 20:13:57 -07005210 def testListBintools(self):
5211 args = ['tool', '--list']
5212 with test_util.capture_sys_output() as (stdout, _):
5213 self._DoBinman(*args)
5214 out = stdout.getvalue().splitlines()
5215 self.assertTrue(len(out) >= 2)
5216
5217 def testFetchBintools(self):
5218 def fail_download(url):
Simon Glassc1aa66e2022-01-29 14:14:04 -07005219 """Take the tools.download() function by raising an exception"""
Simon Glass56ee85e2022-01-09 20:13:57 -07005220 raise urllib.error.URLError('my error')
5221
5222 args = ['tool']
5223 with self.assertRaises(ValueError) as e:
5224 self._DoBinman(*args)
5225 self.assertIn("Invalid arguments to 'tool' subcommand",
5226 str(e.exception))
5227
5228 args = ['tool', '--fetch']
5229 with self.assertRaises(ValueError) as e:
5230 self._DoBinman(*args)
5231 self.assertIn('Please specify bintools to fetch', str(e.exception))
5232
5233 args = ['tool', '--fetch', '_testing']
Simon Glassc1aa66e2022-01-29 14:14:04 -07005234 with unittest.mock.patch.object(tools, 'download',
Simon Glass56ee85e2022-01-09 20:13:57 -07005235 side_effect=fail_download):
5236 with test_util.capture_sys_output() as (stdout, _):
5237 self._DoBinman(*args)
5238 self.assertIn('failed to fetch with all methods', stdout.getvalue())
5239
Simon Glassbc570642022-01-09 20:14:11 -07005240 def testBintoolDocs(self):
5241 """Test for creation of bintool documentation"""
5242 with test_util.capture_sys_output() as (stdout, stderr):
5243 control.write_bintool_docs(control.bintool.Bintool.get_tool_list())
5244 self.assertTrue(len(stdout.getvalue()) > 0)
5245
5246 def testBintoolDocsMissing(self):
5247 """Test handling of missing bintool documentation"""
5248 with self.assertRaises(ValueError) as e:
5249 with test_util.capture_sys_output() as (stdout, stderr):
5250 control.write_bintool_docs(
5251 control.bintool.Bintool.get_tool_list(), 'mkimage')
5252 self.assertIn('Documentation is missing for modules: mkimage',
5253 str(e.exception))
5254
Jan Kiszkafcc87ef2022-01-28 20:37:53 +01005255 def testListWithGenNode(self):
5256 """Check handling of an FDT map when the section cannot be found"""
5257 entry_args = {
5258 'of-list': 'test-fdt1 test-fdt2',
5259 }
5260 data = self._DoReadFileDtb(
5261 '219_fit_gennode.dts',
5262 entry_args=entry_args,
5263 use_real_dtb=True,
5264 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])
5265
5266 try:
5267 tmpdir, updated_fname = self._SetupImageInTmpdir()
5268 with test_util.capture_sys_output() as (stdout, stderr):
5269 self._RunBinman('ls', '-i', updated_fname)
5270 finally:
5271 shutil.rmtree(tmpdir)
5272
Alper Nebi Yasaked293c32022-02-08 01:08:05 +03005273 def testFitSubentryUsesBintool(self):
5274 """Test that binman FIT subentries can use bintools"""
5275 command.test_result = self._HandleGbbCommand
5276 entry_args = {
5277 'keydir': 'devkeys',
5278 'bmpblk': 'bmpblk.bin',
5279 }
5280 data, _, _, _ = self._DoReadFileDtb('220_fit_subentry_bintool.dts',
5281 entry_args=entry_args)
5282
Alper Nebi Yasakf3078d42022-02-08 01:08:07 +03005283 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
5284 tools.get_bytes(0, 0x2180 - 16))
Alper Nebi Yasaked293c32022-02-08 01:08:05 +03005285 self.assertIn(expected, data)
5286
5287 def testFitSubentryMissingBintool(self):
5288 """Test that binman reports missing bintools for FIT subentries"""
5289 entry_args = {
5290 'keydir': 'devkeys',
5291 }
5292 with test_util.capture_sys_output() as (_, stderr):
5293 self._DoTestFile('220_fit_subentry_bintool.dts',
5294 force_missing_bintools='futility', entry_args=entry_args)
5295 err = stderr.getvalue()
5296 self.assertRegex(err,
5297 "Image 'main-section'.*missing bintools.*: futility")
Simon Glass32d4f102022-01-12 13:10:35 -07005298
Alper Nebi Yasakee813c82022-02-09 22:02:35 +03005299 def testFitSubentryHashSubnode(self):
5300 """Test an image with a FIT inside"""
5301 data, _, _, out_dtb_name = self._DoReadFileDtb(
5302 '221_fit_subentry_hash.dts', use_real_dtb=True, update_dtb=True)
5303
5304 mkimage_dtb = fdt.Fdt.FromData(data)
5305 mkimage_dtb.Scan()
5306 binman_dtb = fdt.Fdt(out_dtb_name)
5307 binman_dtb.Scan()
5308
5309 # Check that binman didn't add hash values
5310 fnode = binman_dtb.GetNode('/binman/fit/images/kernel/hash')
5311 self.assertNotIn('value', fnode.props)
5312
5313 fnode = binman_dtb.GetNode('/binman/fit/images/fdt-1/hash')
5314 self.assertNotIn('value', fnode.props)
5315
5316 # Check that mkimage added hash values
5317 fnode = mkimage_dtb.GetNode('/images/kernel/hash')
5318 self.assertIn('value', fnode.props)
5319
5320 fnode = mkimage_dtb.GetNode('/images/fdt-1/hash')
5321 self.assertIn('value', fnode.props)
5322
Roger Quadros47f420a2022-02-19 20:50:04 +02005323 def testPackTeeOs(self):
5324 """Test that an image with an TEE binary can be created"""
5325 data = self._DoReadFile('222_tee_os.dts')
5326 self.assertEqual(TEE_OS_DATA, data[:len(TEE_OS_DATA)])
5327
Simon Glass6a0b5f82022-02-08 11:50:03 -07005328 def testFitFdtOper(self):
5329 """Check handling of a specified FIT operation"""
5330 entry_args = {
5331 'of-list': 'test-fdt1 test-fdt2',
5332 'default-dt': 'test-fdt2',
5333 }
5334 self._DoReadFileDtb(
5335 '223_fit_fdt_oper.dts',
5336 entry_args=entry_args,
5337 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
5338
5339 def testFitFdtBadOper(self):
5340 """Check handling of an FDT map when the section cannot be found"""
5341 with self.assertRaises(ValueError) as exc:
5342 self._DoReadFileDtb('224_fit_bad_oper.dts')
Simon Glassce4e4022022-03-05 20:19:09 -07005343 self.assertIn("Node '/binman/fit': subnode 'images/@fdt-SEQ': Unknown operation 'unknown'",
Simon Glass6a0b5f82022-02-08 11:50:03 -07005344 str(exc.exception))
5345
Simon Glass80a66ae2022-03-05 20:18:59 -07005346 def test_uses_expand_size(self):
5347 """Test that the 'expand-size' property cannot be used anymore"""
5348 with self.assertRaises(ValueError) as e:
5349 data = self._DoReadFile('225_expand_size_bad.dts')
5350 self.assertIn(
5351 "Node '/binman/u-boot': Please use 'extend-size' instead of 'expand-size'",
5352 str(e.exception))
5353
Simon Glass72e423c2022-03-05 20:19:05 -07005354 def testMkimageMissingBlob(self):
5355 """Test using mkimage to build an image"""
5356 with test_util.capture_sys_output() as (stdout, stderr):
5357 self._DoTestFile('229_mkimage_missing.dts', allow_missing=True,
5358 allow_fake_blobs=True)
5359 err = stderr.getvalue()
5360 self.assertRegex(
5361 err,
5362 "Image '.*' has faked external blobs and is non-functional: .*")
5363
Simon Glass40c8bdd2022-03-05 20:19:12 -07005364 def testFitSplitElf(self):
5365 """Test an image with an FIT with an split-elf operation"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02005366 if not elf.ELF_TOOLS:
5367 self.skipTest('Python elftools not available')
Simon Glass40c8bdd2022-03-05 20:19:12 -07005368 entry_args = {
5369 'of-list': 'test-fdt1 test-fdt2',
5370 'default-dt': 'test-fdt2',
5371 'atf-bl31-path': 'bl31.elf',
5372 'tee-os-path': 'tee.elf',
5373 }
5374 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5375 data = self._DoReadFileDtb(
5376 '226_fit_split_elf.dts',
5377 entry_args=entry_args,
5378 extra_indirs=[test_subdir])[0]
5379
5380 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
5381 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
5382
5383 base_keys = {'description', 'type', 'arch', 'os', 'compression',
5384 'data', 'load'}
5385 dtb = fdt.Fdt.FromData(fit_data)
5386 dtb.Scan()
5387
5388 elf_data = tools.read_file(os.path.join(self._indir, 'bl31.elf'))
5389 segments, entry = elf.read_loadable_segments(elf_data)
5390
5391 # We assume there are two segments
5392 self.assertEquals(2, len(segments))
5393
5394 atf1 = dtb.GetNode('/images/atf-1')
5395 _, start, data = segments[0]
5396 self.assertEqual(base_keys | {'entry'}, atf1.props.keys())
5397 self.assertEqual(entry,
5398 fdt_util.fdt32_to_cpu(atf1.props['entry'].value))
5399 self.assertEqual(start,
5400 fdt_util.fdt32_to_cpu(atf1.props['load'].value))
5401 self.assertEqual(data, atf1.props['data'].bytes)
5402
5403 atf2 = dtb.GetNode('/images/atf-2')
5404 self.assertEqual(base_keys, atf2.props.keys())
5405 _, start, data = segments[1]
5406 self.assertEqual(start,
5407 fdt_util.fdt32_to_cpu(atf2.props['load'].value))
5408 self.assertEqual(data, atf2.props['data'].bytes)
5409
5410 conf = dtb.GetNode('/configurations')
5411 self.assertEqual({'default'}, conf.props.keys())
5412
5413 for subnode in conf.subnodes:
5414 self.assertEqual({'description', 'fdt', 'loadables'},
5415 subnode.props.keys())
5416 self.assertEqual(
5417 ['atf-1', 'atf-2', 'tee-1', 'tee-2'],
5418 fdt_util.GetStringList(subnode, 'loadables'))
5419
5420 def _check_bad_fit(self, dts):
5421 """Check a bad FIT
5422
5423 This runs with the given dts and returns the assertion raised
5424
5425 Args:
5426 dts (str): dts filename to use
5427
5428 Returns:
5429 str: Assertion string raised
5430 """
5431 entry_args = {
5432 'of-list': 'test-fdt1 test-fdt2',
5433 'default-dt': 'test-fdt2',
5434 'atf-bl31-path': 'bl31.elf',
5435 'tee-os-path': 'tee.elf',
5436 }
5437 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5438 with self.assertRaises(ValueError) as exc:
5439 self._DoReadFileDtb(dts, entry_args=entry_args,
5440 extra_indirs=[test_subdir])[0]
5441 return str(exc.exception)
5442
5443 def testFitSplitElfBadElf(self):
5444 """Test a FIT split-elf operation with an invalid ELF file"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02005445 if not elf.ELF_TOOLS:
5446 self.skipTest('Python elftools not available')
Simon Glass40c8bdd2022-03-05 20:19:12 -07005447 TestFunctional._MakeInputFile('bad.elf', tools.get_bytes(100, 100))
5448 entry_args = {
5449 'of-list': 'test-fdt1 test-fdt2',
5450 'default-dt': 'test-fdt2',
5451 'atf-bl31-path': 'bad.elf',
5452 'tee-os-path': 'tee.elf',
5453 }
5454 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5455 with self.assertRaises(ValueError) as exc:
5456 self._DoReadFileDtb(
5457 '226_fit_split_elf.dts',
5458 entry_args=entry_args,
5459 extra_indirs=[test_subdir])[0]
5460 self.assertIn(
5461 "Node '/binman/fit': subnode 'images/@atf-SEQ': Failed to read ELF file: Magic number does not match",
5462 str(exc.exception))
5463
5464 def testFitSplitElfBadDirective(self):
5465 """Test a FIT split-elf invalid fit,xxx directive in an image node"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02005466 if not elf.ELF_TOOLS:
5467 self.skipTest('Python elftools not available')
Simon Glass40c8bdd2022-03-05 20:19:12 -07005468 err = self._check_bad_fit('227_fit_bad_dir.dts')
5469 self.assertIn(
5470 "Node '/binman/fit': subnode 'images/@atf-SEQ': Unknown directive 'fit,something'",
5471 err)
5472
5473 def testFitSplitElfBadDirectiveConfig(self):
5474 """Test a FIT split-elf with invalid fit,xxx directive in config"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02005475 if not elf.ELF_TOOLS:
5476 self.skipTest('Python elftools not available')
Simon Glass40c8bdd2022-03-05 20:19:12 -07005477 err = self._check_bad_fit('228_fit_bad_dir_config.dts')
5478 self.assertEqual(
5479 "Node '/binman/fit': subnode 'configurations/@config-SEQ': Unknown directive 'fit,config'",
5480 err)
5481
5482 def checkFitSplitElf(self, **kwargs):
Simon Glass7960a0a2022-08-07 09:46:46 -06005483 """Test an split-elf FIT with a missing ELF file
5484
5485 Args:
5486 kwargs (dict of str): Arguments to pass to _DoTestFile()
5487
5488 Returns:
5489 tuple:
5490 str: stdout result
5491 str: stderr result
5492 """
Simon Glass40c8bdd2022-03-05 20:19:12 -07005493 entry_args = {
5494 'of-list': 'test-fdt1 test-fdt2',
5495 'default-dt': 'test-fdt2',
5496 'atf-bl31-path': 'bl31.elf',
5497 'tee-os-path': 'missing.elf',
5498 }
5499 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5500 with test_util.capture_sys_output() as (stdout, stderr):
5501 self._DoTestFile(
5502 '226_fit_split_elf.dts', entry_args=entry_args,
Simon Glass7960a0a2022-08-07 09:46:46 -06005503 extra_indirs=[test_subdir], verbosity=3, **kwargs)
5504 out = stdout.getvalue()
5505 err = stderr.getvalue()
5506 return out, err
Simon Glass40c8bdd2022-03-05 20:19:12 -07005507
5508 def testFitSplitElfMissing(self):
5509 """Test an split-elf FIT with a missing ELF file"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02005510 if not elf.ELF_TOOLS:
5511 self.skipTest('Python elftools not available')
Simon Glass7960a0a2022-08-07 09:46:46 -06005512 out, err = self.checkFitSplitElf(allow_missing=True)
Simon Glass40c8bdd2022-03-05 20:19:12 -07005513 self.assertRegex(
5514 err,
5515 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7960a0a2022-08-07 09:46:46 -06005516 self.assertNotRegex(out, '.*Faked blob.*')
5517 fname = tools.get_output_filename('binman-fake/missing.elf')
5518 self.assertFalse(os.path.exists(fname))
Simon Glass40c8bdd2022-03-05 20:19:12 -07005519
5520 def testFitSplitElfFaked(self):
5521 """Test an split-elf FIT with faked ELF file"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02005522 if not elf.ELF_TOOLS:
5523 self.skipTest('Python elftools not available')
Simon Glass7960a0a2022-08-07 09:46:46 -06005524 out, err = self.checkFitSplitElf(allow_missing=True, allow_fake_blobs=True)
Simon Glass40c8bdd2022-03-05 20:19:12 -07005525 self.assertRegex(
5526 err,
5527 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7960a0a2022-08-07 09:46:46 -06005528 self.assertRegex(
5529 out,
5530 "Entry '/binman/fit/images/@tee-SEQ/tee-os': Faked blob '.*binman-fake/missing.elf")
5531 fname = tools.get_output_filename('binman-fake/missing.elf')
5532 self.assertTrue(os.path.exists(fname))
Simon Glass40c8bdd2022-03-05 20:19:12 -07005533
Philippe Reynesb1c50932022-03-28 22:57:04 +02005534 def testPreLoad(self):
5535 """Test an image with a pre-load header"""
5536 entry_args = {
5537 'pre-load-key-path': '.',
5538 }
5539 data, _, _, _ = self._DoReadFileDtb('225_pre_load.dts',
5540 entry_args=entry_args)
5541 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5542 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5543 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5544 data = self._DoReadFile('225_pre_load.dts')
5545 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5546 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5547 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5548
5549 def testPreLoadPkcs(self):
5550 """Test an image with a pre-load header with padding pkcs"""
5551 data = self._DoReadFile('226_pre_load_pkcs.dts')
5552 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5553 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5554 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5555
5556 def testPreLoadPss(self):
5557 """Test an image with a pre-load header with padding pss"""
5558 data = self._DoReadFile('227_pre_load_pss.dts')
5559 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5560 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5561 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5562
5563 def testPreLoadInvalidPadding(self):
5564 """Test an image with a pre-load header with an invalid padding"""
5565 with self.assertRaises(ValueError) as e:
5566 data = self._DoReadFile('228_pre_load_invalid_padding.dts')
5567
5568 def testPreLoadInvalidSha(self):
5569 """Test an image with a pre-load header with an invalid hash"""
5570 with self.assertRaises(ValueError) as e:
5571 data = self._DoReadFile('229_pre_load_invalid_sha.dts')
5572
5573 def testPreLoadInvalidAlgo(self):
5574 """Test an image with a pre-load header with an invalid algo"""
5575 with self.assertRaises(ValueError) as e:
5576 data = self._DoReadFile('230_pre_load_invalid_algo.dts')
5577
5578 def testPreLoadInvalidKey(self):
5579 """Test an image with a pre-load header with an invalid key"""
5580 with self.assertRaises(ValueError) as e:
5581 data = self._DoReadFile('231_pre_load_invalid_key.dts')
Roger Quadros47f420a2022-02-19 20:50:04 +02005582
Alper Nebi Yasak67bf2c82022-03-27 18:31:44 +03005583 def _CheckSafeUniqueNames(self, *images):
5584 """Check all entries of given images for unsafe unique names"""
5585 for image in images:
5586 entries = {}
5587 image._CollectEntries(entries, {}, image)
5588 for entry in entries.values():
5589 uniq = entry.GetUniqueName()
5590
5591 # Used as part of a filename, so must not be absolute paths.
5592 self.assertFalse(os.path.isabs(uniq))
5593
5594 def testSafeUniqueNames(self):
5595 """Test entry unique names are safe in single image configuration"""
5596 data = self._DoReadFileRealDtb('230_unique_names.dts')
5597
5598 orig_image = control.images['image']
5599 image_fname = tools.get_output_filename('image.bin')
5600 image = Image.FromFile(image_fname)
5601
5602 self._CheckSafeUniqueNames(orig_image, image)
5603
5604 def testSafeUniqueNamesMulti(self):
5605 """Test entry unique names are safe with multiple images"""
5606 data = self._DoReadFileRealDtb('231_unique_names_multi.dts')
5607
5608 orig_image = control.images['image']
5609 image_fname = tools.get_output_filename('image.bin')
5610 image = Image.FromFile(image_fname)
5611
5612 self._CheckSafeUniqueNames(orig_image, image)
5613
Alper Nebi Yasak8ee4ec92022-03-27 18:31:45 +03005614 def testReplaceCmdWithBintool(self):
5615 """Test replacing an entry that needs a bintool to pack"""
5616 data = self._DoReadFileRealDtb('232_replace_with_bintool.dts')
5617 expected = U_BOOT_DATA + b'aa'
5618 self.assertEqual(expected, data[:len(expected)])
5619
5620 try:
5621 tmpdir, updated_fname = self._SetupImageInTmpdir()
5622 fname = os.path.join(tmpdir, 'update-testing.bin')
5623 tools.write_file(fname, b'zz')
5624 self._DoBinman('replace', '-i', updated_fname,
5625 '_testing', '-f', fname)
5626
5627 data = tools.read_file(updated_fname)
5628 expected = U_BOOT_DATA + b'zz'
5629 self.assertEqual(expected, data[:len(expected)])
5630 finally:
5631 shutil.rmtree(tmpdir)
5632
5633 def testReplaceCmdOtherWithBintool(self):
5634 """Test replacing an entry when another needs a bintool to pack"""
5635 data = self._DoReadFileRealDtb('232_replace_with_bintool.dts')
5636 expected = U_BOOT_DATA + b'aa'
5637 self.assertEqual(expected, data[:len(expected)])
5638
5639 try:
5640 tmpdir, updated_fname = self._SetupImageInTmpdir()
5641 fname = os.path.join(tmpdir, 'update-u-boot.bin')
5642 tools.write_file(fname, b'x' * len(U_BOOT_DATA))
5643 self._DoBinman('replace', '-i', updated_fname,
5644 'u-boot', '-f', fname)
5645
5646 data = tools.read_file(updated_fname)
5647 expected = b'x' * len(U_BOOT_DATA) + b'aa'
5648 self.assertEqual(expected, data[:len(expected)])
5649 finally:
5650 shutil.rmtree(tmpdir)
5651
Alper Nebi Yasake2ce4fb2022-03-27 18:31:46 +03005652 def testReplaceResizeNoRepackSameSize(self):
5653 """Test replacing entries with same-size data without repacking"""
5654 expected = b'x' * len(U_BOOT_DATA)
5655 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected)
5656 self.assertEqual(expected, data)
5657
5658 path, fdtmap = state.GetFdtContents('fdtmap')
5659 self.assertIsNotNone(path)
5660 self.assertEqual(expected_fdtmap, fdtmap)
5661
5662 def testReplaceResizeNoRepackSmallerSize(self):
5663 """Test replacing entries with smaller-size data without repacking"""
5664 new_data = b'x'
5665 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', new_data)
5666 expected = new_data.ljust(len(U_BOOT_DATA), b'\0')
5667 self.assertEqual(expected, data)
5668
5669 path, fdtmap = state.GetFdtContents('fdtmap')
5670 self.assertIsNotNone(path)
5671 self.assertEqual(expected_fdtmap, fdtmap)
5672
Alper Nebi Yasak74d3b232022-03-27 18:31:48 +03005673 def testExtractFit(self):
5674 """Test extracting a FIT section"""
5675 self._DoReadFileRealDtb('233_fit_extract_replace.dts')
5676 image_fname = tools.get_output_filename('image.bin')
5677
5678 fit_data = control.ReadEntry(image_fname, 'fit')
5679 fit = fdt.Fdt.FromData(fit_data)
5680 fit.Scan()
5681
5682 # Check subentry data inside the extracted fit
5683 for node_path, expected in [
5684 ('/images/kernel', U_BOOT_DATA),
5685 ('/images/fdt-1', U_BOOT_NODTB_DATA),
5686 ('/images/scr-1', COMPRESS_DATA),
5687 ]:
5688 node = fit.GetNode(node_path)
5689 data = fit.GetProps(node)['data'].bytes
5690 self.assertEqual(expected, data)
5691
5692 def testExtractFitSubentries(self):
5693 """Test extracting FIT section subentries"""
5694 self._DoReadFileRealDtb('233_fit_extract_replace.dts')
5695 image_fname = tools.get_output_filename('image.bin')
5696
5697 for entry_path, expected in [
5698 ('fit/kernel', U_BOOT_DATA),
5699 ('fit/kernel/u-boot', U_BOOT_DATA),
5700 ('fit/fdt-1', U_BOOT_NODTB_DATA),
5701 ('fit/fdt-1/u-boot-nodtb', U_BOOT_NODTB_DATA),
5702 ('fit/scr-1', COMPRESS_DATA),
5703 ('fit/scr-1/blob', COMPRESS_DATA),
5704 ]:
5705 data = control.ReadEntry(image_fname, entry_path)
5706 self.assertEqual(expected, data)
5707
Alper Nebi Yasak99283e52022-03-27 18:31:49 +03005708 def testReplaceFitSubentryLeafSameSize(self):
5709 """Test replacing a FIT leaf subentry with same-size data"""
5710 new_data = b'x' * len(U_BOOT_DATA)
5711 data, expected_fdtmap, _ = self._RunReplaceCmd(
5712 'fit/kernel/u-boot', new_data,
5713 dts='233_fit_extract_replace.dts')
5714 self.assertEqual(new_data, data)
5715
5716 path, fdtmap = state.GetFdtContents('fdtmap')
5717 self.assertIsNotNone(path)
5718 self.assertEqual(expected_fdtmap, fdtmap)
5719
5720 def testReplaceFitSubentryLeafBiggerSize(self):
5721 """Test replacing a FIT leaf subentry with bigger-size data"""
5722 new_data = b'ub' * len(U_BOOT_NODTB_DATA)
5723 data, expected_fdtmap, _ = self._RunReplaceCmd(
5724 'fit/fdt-1/u-boot-nodtb', new_data,
5725 dts='233_fit_extract_replace.dts')
5726 self.assertEqual(new_data, data)
5727
5728 # Will be repacked, so fdtmap must change
5729 path, fdtmap = state.GetFdtContents('fdtmap')
5730 self.assertIsNotNone(path)
5731 self.assertNotEqual(expected_fdtmap, fdtmap)
5732
5733 def testReplaceFitSubentryLeafSmallerSize(self):
5734 """Test replacing a FIT leaf subentry with smaller-size data"""
5735 new_data = b'x'
5736 expected = new_data.ljust(len(U_BOOT_NODTB_DATA), b'\0')
5737 data, expected_fdtmap, _ = self._RunReplaceCmd(
5738 'fit/fdt-1/u-boot-nodtb', new_data,
5739 dts='233_fit_extract_replace.dts')
5740 self.assertEqual(expected, data)
5741
5742 path, fdtmap = state.GetFdtContents('fdtmap')
5743 self.assertIsNotNone(path)
5744 self.assertEqual(expected_fdtmap, fdtmap)
5745
Alper Nebi Yasak82337bb2022-03-27 18:31:50 +03005746 def testReplaceSectionSimple(self):
5747 """Test replacing a simple section with arbitrary data"""
5748 new_data = b'w' * len(COMPRESS_DATA + U_BOOT_DATA)
Simon Glass73593e42022-08-13 11:40:46 -06005749 with self.assertRaises(ValueError) as exc:
5750 self._RunReplaceCmd('section', new_data,
5751 dts='234_replace_section_simple.dts')
5752 self.assertIn(
5753 "Node '/section': Replacing sections is not implemented yet",
5754 str(exc.exception))
Alper Nebi Yasak82337bb2022-03-27 18:31:50 +03005755
Simon Glassdfe1db42022-08-13 11:40:48 -06005756 def testMkimageImagename(self):
5757 """Test using mkimage with -n holding the data too"""
5758 data = self._DoReadFile('235_mkimage_name.dts')
5759
5760 # Check that the data appears in the file somewhere
5761 self.assertIn(U_BOOT_SPL_DATA, data)
5762
5763 # Get struct image_header -> ih_name
5764 name = data[0x20:0x40]
5765
5766 # Build the filename that we expect to be placed in there, by virtue of
5767 # the -n paraameter
5768 expect = os.path.join(tools.get_output_dir(), 'mkimage.mkimage')
5769
5770 # Check that the image name is set to the temporary filename used
5771 self.assertEqual(expect.encode('utf-8')[:0x20], name)
5772
Simon Glass9db9e932022-08-13 11:40:49 -06005773 def testMkimageImage(self):
5774 """Test using mkimage with -n holding the data too"""
5775 data = self._DoReadFile('236_mkimage_image.dts')
5776
5777 # Check that the data appears in the file somewhere
5778 self.assertIn(U_BOOT_SPL_DATA, data)
5779
5780 # Get struct image_header -> ih_name
5781 name = data[0x20:0x40]
5782
5783 # Build the filename that we expect to be placed in there, by virtue of
5784 # the -n paraameter
5785 expect = os.path.join(tools.get_output_dir(), 'mkimage-n.mkimage')
5786
5787 # Check that the image name is set to the temporary filename used
5788 self.assertEqual(expect.encode('utf-8')[:0x20], name)
5789
5790 # Check the corect data is in the imagename file
5791 self.assertEqual(U_BOOT_DATA, tools.read_file(expect))
5792
5793 def testMkimageImageNoContent(self):
5794 """Test using mkimage with -n and no data"""
5795 with self.assertRaises(ValueError) as exc:
5796 self._DoReadFile('237_mkimage_image_no_content.dts')
5797 self.assertIn('Could not complete processing of contents',
5798 str(exc.exception))
5799
5800 def testMkimageImageBad(self):
5801 """Test using mkimage with imagename node and data-to-imagename"""
5802 with self.assertRaises(ValueError) as exc:
5803 self._DoReadFile('238_mkimage_image_bad.dts')
5804 self.assertIn('Cannot use both imagename node and data-to-imagename',
5805 str(exc.exception))
5806
Simon Glassd626e822022-08-13 11:40:50 -06005807 def testCollectionOther(self):
5808 """Test a collection where the data comes from another section"""
5809 data = self._DoReadFile('239_collection_other.dts')
5810 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
5811 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
5812 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
5813 data)
5814
5815 def testMkimageCollection(self):
5816 """Test using a collection referring to an entry in a mkimage entry"""
5817 data = self._DoReadFile('240_mkimage_coll.dts')
5818 expect = U_BOOT_SPL_DATA + U_BOOT_DATA
5819 self.assertEqual(expect, data[:len(expect)])
5820
Stefan Herbrechtsmeier6aa80002022-08-19 16:25:25 +02005821 def testCompressDtbPrependInvalid(self):
5822 """Test that invalid header is detected"""
5823 with self.assertRaises(ValueError) as e:
5824 self._DoReadFileDtb('235_compress_dtb_prepend_invalid.dts')
5825 self.assertIn("Node '/binman/u-boot-dtb': Invalid prepend in "
5826 "'u-boot-dtb': 'invalid'", str(e.exception))
5827
5828 def testCompressDtbPrependLength(self):
5829 """Test that compress with length header works as expected"""
5830 data = self._DoReadFileRealDtb('236_compress_dtb_prepend_length.dts')
5831 image = control.images['image']
5832 entries = image.GetEntries()
5833 self.assertIn('u-boot-dtb', entries)
5834 u_boot_dtb = entries['u-boot-dtb']
5835 self.assertIn('fdtmap', entries)
5836 fdtmap = entries['fdtmap']
5837
5838 image_fname = tools.get_output_filename('image.bin')
5839 orig = control.ReadEntry(image_fname, 'u-boot-dtb')
5840 dtb = fdt.Fdt.FromData(orig)
5841 dtb.Scan()
5842 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
5843 expected = {
5844 'u-boot:size': len(U_BOOT_DATA),
5845 'u-boot-dtb:uncomp-size': len(orig),
5846 'u-boot-dtb:size': u_boot_dtb.size,
5847 'fdtmap:size': fdtmap.size,
5848 'size': len(data),
5849 }
5850 self.assertEqual(expected, props)
5851
5852 # Check implementation
5853 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
5854 rest = data[len(U_BOOT_DATA):]
5855 comp_data_len = struct.unpack('<I', rest[:4])[0]
5856 comp_data = rest[4:4 + comp_data_len]
5857 orig2 = self._decompress(comp_data)
5858 self.assertEqual(orig, orig2)
5859
Stefan Herbrechtsmeierec7d27d2022-08-19 16:25:30 +02005860 def testInvalidCompress(self):
5861 """Test that invalid compress algorithm is detected"""
5862 with self.assertRaises(ValueError) as e:
5863 self._DoTestFile('237_compress_dtb_invalid.dts')
5864 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
5865
Alper Nebi Yasak8ee4ec92022-03-27 18:31:45 +03005866
Simon Glass9fc60b42017-11-12 21:52:22 -07005867if __name__ == "__main__":
5868 unittest.main()