blob: 934c8dd26f61236ad3ce3a2f16813fe4d22935a1 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001# SPDX-License-Identifier: GPL-2.0+
Simon Glass57454f42016-11-25 20:15:52 -07002# Copyright (c) 2016 Google, Inc
3# Written by Simon Glass <sjg@chromium.org>
4#
Simon Glass57454f42016-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 Glass45d556d2020-07-09 18:39:45 -06009import collections
Simon Glassc585dd42020-04-17 18:09:03 -060010import gzip
Simon Glassae7cf032018-09-14 04:57:31 -060011import hashlib
Simon Glass57454f42016-11-25 20:15:52 -070012from optparse import OptionParser
13import os
Simon Glass45d556d2020-07-09 18:39:45 -060014import re
Simon Glass57454f42016-11-25 20:15:52 -070015import shutil
16import struct
17import sys
18import tempfile
19import unittest
Simon Glass162017b2022-01-09 20:13:57 -070020import unittest.mock
21import urllib.error
Simon Glass57454f42016-11-25 20:15:52 -070022
Simon Glass4eae9252022-01-09 20:13:50 -070023from binman import bintool
Simon Glassc585dd42020-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 Glass3efb2972021-11-23 21:08:59 -070029from binman import fip_util
Simon Glassc585dd42020-04-17 18:09:03 -060030from binman import fmap_util
Simon Glassc585dd42020-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 Glass90cd6f02020-08-05 13:27:47 -060036from binman.image import Image
Simon Glass131444f2023-02-23 18:18:04 -070037from u_boot_pylib import command
38from u_boot_pylib import test_util
39from u_boot_pylib import tools
40from u_boot_pylib import tout
Simon Glass57454f42016-11-25 20:15:52 -070041
42# Contents of test files, corresponding to different entry types
Simon Glass303f62f2019-05-17 22:00:46 -060043U_BOOT_DATA = b'1234'
44U_BOOT_IMG_DATA = b'img'
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +030045U_BOOT_SPL_DATA = b'56780123456789abcdefghijklm'
46U_BOOT_TPL_DATA = b'tpl9876543210fedcbazywvuts'
Simon Glass56d05412022-02-28 07:16:54 -070047U_BOOT_VPL_DATA = b'vpl76543210fedcbazywxyz_'
Simon Glass303f62f2019-05-17 22:00:46 -060048BLOB_DATA = b'89'
49ME_DATA = b'0abcd'
50VGA_DATA = b'vga'
51U_BOOT_DTB_DATA = b'udtb'
52U_BOOT_SPL_DTB_DATA = b'spldtb'
53U_BOOT_TPL_DTB_DATA = b'tpldtb'
Simon Glass56d05412022-02-28 07:16:54 -070054U_BOOT_VPL_DTB_DATA = b'vpldtb'
Simon Glass303f62f2019-05-17 22:00:46 -060055X86_START16_DATA = b'start16'
56X86_START16_SPL_DATA = b'start16spl'
57X86_START16_TPL_DATA = b'start16tpl'
Simon Glass0b074d62019-08-24 07:22:48 -060058X86_RESET16_DATA = b'reset16'
59X86_RESET16_SPL_DATA = b'reset16spl'
60X86_RESET16_TPL_DATA = b'reset16tpl'
Simon Glass303f62f2019-05-17 22:00:46 -060061PPC_MPC85XX_BR_DATA = b'ppcmpc85xxbr'
62U_BOOT_NODTB_DATA = b'nodtb with microcode pointer somewhere in here'
63U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here'
64U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here'
Simon Glass56d05412022-02-28 07:16:54 -070065U_BOOT_VPL_NODTB_DATA = b'vplnodtb'
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +030066U_BOOT_EXP_DATA = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
67U_BOOT_SPL_EXP_DATA = U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA
68U_BOOT_TPL_EXP_DATA = U_BOOT_TPL_NODTB_DATA + U_BOOT_TPL_DTB_DATA
Simon Glass303f62f2019-05-17 22:00:46 -060069FSP_DATA = b'fsp'
70CMC_DATA = b'cmc'
71VBT_DATA = b'vbt'
72MRC_DATA = b'mrc'
Simon Glass2ca52032018-07-17 13:25:33 -060073TEXT_DATA = 'text'
74TEXT_DATA2 = 'text2'
75TEXT_DATA3 = 'text3'
Simon Glass303f62f2019-05-17 22:00:46 -060076CROS_EC_RW_DATA = b'ecrw'
77GBB_DATA = b'gbbd'
78BMPBLK_DATA = b'bmp'
79VBLOCK_DATA = b'vblk'
80FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
81 b"sorry you're alive\n")
Simon Glassccec0262019-07-08 13:18:42 -060082COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
Simon Glassd92c8362020-10-26 17:40:25 -060083COMPRESS_DATA_BIG = COMPRESS_DATA * 2
Simon Glass303f62f2019-05-17 22:00:46 -060084REFCODE_DATA = b'refcode'
Simon Glassba7985d2019-08-24 07:23:07 -060085FSP_M_DATA = b'fsp_m'
Simon Glass4d9086d2019-10-20 21:31:35 -060086FSP_S_DATA = b'fsp_s'
Simon Glass9ea87b22019-10-20 21:31:36 -060087FSP_T_DATA = b'fsp_t'
Simon Glass559c4de2020-09-01 05:13:58 -060088ATF_BL31_DATA = b'bl31'
Roger Quadros5cdcea02022-02-19 20:50:04 +020089TEE_OS_DATA = b'this is some tee OS data'
Simon Glass3efb2972021-11-23 21:08:59 -070090ATF_BL2U_DATA = b'bl2u'
Bin Mengc0b15742021-05-10 20:23:33 +080091OPENSBI_DATA = b'opensbi'
Samuel Holland9d8cc632020-10-21 21:12:15 -050092SCP_DATA = b'scp'
Simon Glassa435cd12020-09-01 05:13:59 -060093TEST_FDT1_DATA = b'fdt1'
94TEST_FDT2_DATA = b'test-fdt2'
Simon Glassa0729502020-09-06 10:35:33 -060095ENV_DATA = b'var1=1\nvar2="2"'
Philippe Reynesebe96cb2022-03-28 22:57:04 +020096PRE_LOAD_MAGIC = b'UBSH'
97PRE_LOAD_VERSION = 0x11223344.to_bytes(4, 'big')
98PRE_LOAD_HDR_SIZE = 0x00001000.to_bytes(4, 'big')
Simon Glassa435cd12020-09-01 05:13:59 -060099
100# Subdirectory of the input dir to use to put test FDTs
101TEST_FDT_SUBDIR = 'fdts'
Simon Glassdb168d42018-07-17 13:25:39 -0600102
Simon Glass2c6adba2019-07-20 12:23:47 -0600103# The expected size for the device tree in some tests
Simon Glass4c613bf2019-07-08 14:25:50 -0600104EXTRACT_DTB_SIZE = 0x3c9
105
Simon Glass2c6adba2019-07-20 12:23:47 -0600106# Properties expected to be in the device tree when update_dtb is used
107BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
108
Simon Glassfb30e292019-07-20 12:23:51 -0600109# Extra properties expected to be in the device tree when allow-repack is used
110REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
111
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200112# Supported compression bintools
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +0200113COMP_BINTOOLS = ['bzip2', 'gzip', 'lz4', 'lzma_alone', 'lzop', 'xz', 'zstd']
Simon Glass57454f42016-11-25 20:15:52 -0700114
Simon Glassad5cfe12023-01-07 14:07:14 -0700115TEE_ADDR = 0x5678
116
Simon Glass57454f42016-11-25 20:15:52 -0700117class TestFunctional(unittest.TestCase):
118 """Functional tests for binman
119
120 Most of these use a sample .dts file to build an image and then check
121 that it looks correct. The sample files are in the test/ subdirectory
122 and are numbered.
123
124 For each entry type a very small test file is created using fixed
125 string contents. This makes it easy to test that things look right, and
126 debug problems.
127
128 In some cases a 'real' file must be used - these are also supplied in
129 the test/ diurectory.
130 """
131 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600132 def setUpClass(cls):
Simon Glassb3393262017-11-12 21:52:20 -0700133 global entry
Simon Glassc585dd42020-04-17 18:09:03 -0600134 from binman import entry
Simon Glassb3393262017-11-12 21:52:20 -0700135
Simon Glass57454f42016-11-25 20:15:52 -0700136 # Handle the case where argv[0] is 'python'
Simon Glass862f8e22019-08-24 07:22:43 -0600137 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
138 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
Simon Glass57454f42016-11-25 20:15:52 -0700139
140 # Create a temporary directory for input files
Simon Glass862f8e22019-08-24 07:22:43 -0600141 cls._indir = tempfile.mkdtemp(prefix='binmant.')
Simon Glass57454f42016-11-25 20:15:52 -0700142
143 # Create some test files
144 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
145 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
146 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glass8425a1f2018-07-17 13:25:48 -0600147 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass56d05412022-02-28 07:16:54 -0700148 TestFunctional._MakeInputFile('vpl/u-boot-vpl.bin', U_BOOT_VPL_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700149 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glass72232452016-11-25 20:15:53 -0700150 TestFunctional._MakeInputFile('me.bin', ME_DATA)
151 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glass862f8e22019-08-24 07:22:43 -0600152 cls._ResetDtbs()
Simon Glass0b074d62019-08-24 07:22:48 -0600153
Jagdish Gediya311d4842018-09-03 21:35:08 +0530154 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glass0b074d62019-08-24 07:22:48 -0600155
Simon Glassabab18c2019-08-24 07:22:49 -0600156 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
157 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
Simon Glasse83679d2017-11-12 21:52:26 -0700158 X86_START16_SPL_DATA)
Simon Glassabab18c2019-08-24 07:22:49 -0600159 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
Simon Glassed40e962018-09-14 04:57:10 -0600160 X86_START16_TPL_DATA)
Simon Glass0b074d62019-08-24 07:22:48 -0600161
162 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
163 X86_RESET16_DATA)
164 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
165 X86_RESET16_SPL_DATA)
166 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
167 X86_RESET16_TPL_DATA)
168
Simon Glass57454f42016-11-25 20:15:52 -0700169 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass3d274232017-11-12 21:52:27 -0700170 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
171 U_BOOT_SPL_NODTB_DATA)
Simon Glass3fb4f422018-09-14 04:57:32 -0600172 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
173 U_BOOT_TPL_NODTB_DATA)
Simon Glass56d05412022-02-28 07:16:54 -0700174 TestFunctional._MakeInputFile('vpl/u-boot-vpl-nodtb.bin',
175 U_BOOT_VPL_NODTB_DATA)
Simon Glassb4176d42016-11-25 20:15:56 -0700176 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
177 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Mengd7bcdf52017-08-15 22:41:54 -0700178 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassa409c932017-11-12 21:52:28 -0700179 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassdb168d42018-07-17 13:25:39 -0600180 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600181 TestFunctional._MakeInputDir('devkeys')
182 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass41902e42018-10-01 12:22:31 -0600183 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glassba7985d2019-08-24 07:23:07 -0600184 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
Simon Glass4d9086d2019-10-20 21:31:35 -0600185 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
Simon Glass9ea87b22019-10-20 21:31:36 -0600186 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700187
Simon Glassf6290892019-08-24 07:22:53 -0600188 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
189 elf_test.BuildElfTestFiles(cls._elf_testdir)
190
Simon Glass72232452016-11-25 20:15:53 -0700191 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glass4affd4b2019-08-24 07:22:54 -0600192 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -0700193 tools.read_file(cls.ElfTestFile('u_boot_ucode_ptr')))
Simon Glass72232452016-11-25 20:15:53 -0700194
195 # Intel flash descriptor file
Simon Glasse88cef92020-07-09 18:39:41 -0600196 cls._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -0700197
Simon Glass862f8e22019-08-24 07:22:43 -0600198 shutil.copytree(cls.TestFile('files'),
199 os.path.join(cls._indir, 'files'))
Simon Glassac6328c2018-09-14 04:57:28 -0600200
Simon Glass7ba33592018-09-14 04:57:26 -0600201 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
Simon Glassd92c8362020-10-26 17:40:25 -0600202 TestFunctional._MakeInputFile('compress_big', COMPRESS_DATA_BIG)
Simon Glass559c4de2020-09-01 05:13:58 -0600203 TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
Roger Quadros5cdcea02022-02-19 20:50:04 +0200204 TestFunctional._MakeInputFile('tee-pager.bin', TEE_OS_DATA)
Simon Glass3efb2972021-11-23 21:08:59 -0700205 TestFunctional._MakeInputFile('bl2u.bin', ATF_BL2U_DATA)
Bin Mengc0b15742021-05-10 20:23:33 +0800206 TestFunctional._MakeInputFile('fw_dynamic.bin', OPENSBI_DATA)
Samuel Holland9d8cc632020-10-21 21:12:15 -0500207 TestFunctional._MakeInputFile('scp.bin', SCP_DATA)
Simon Glass7ba33592018-09-14 04:57:26 -0600208
Simon Glassa435cd12020-09-01 05:13:59 -0600209 # Add a few .dtb files for testing
210 TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR,
211 TEST_FDT1_DATA)
212 TestFunctional._MakeInputFile('%s/test-fdt2.dtb' % TEST_FDT_SUBDIR,
213 TEST_FDT2_DATA)
214
Simon Glassa0729502020-09-06 10:35:33 -0600215 TestFunctional._MakeInputFile('env.txt', ENV_DATA)
216
Simon Glass5f423422022-03-05 20:19:12 -0700217 # ELF file with two sections in different parts of memory, used for both
218 # ATF and OP_TEE
219 TestFunctional._MakeInputFile('bl31.elf',
220 tools.read_file(cls.ElfTestFile('elf_sections')))
221 TestFunctional._MakeInputFile('tee.elf',
222 tools.read_file(cls.ElfTestFile('elf_sections')))
223
Simon Glassad5cfe12023-01-07 14:07:14 -0700224 # Newer OP_TEE file in v1 binary format
225 cls.make_tee_bin('tee.bin')
226
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200227 cls.comp_bintools = {}
228 for name in COMP_BINTOOLS:
229 cls.comp_bintools[name] = bintool.Bintool.create(name)
Simon Glass1de34482019-07-08 13:18:53 -0600230
Simon Glass57454f42016-11-25 20:15:52 -0700231 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600232 def tearDownClass(cls):
Simon Glass57454f42016-11-25 20:15:52 -0700233 """Remove the temporary input directory and its contents"""
Simon Glass862f8e22019-08-24 07:22:43 -0600234 if cls.preserve_indir:
235 print('Preserving input dir: %s' % cls._indir)
Simon Glass1c420c92019-07-08 13:18:49 -0600236 else:
Simon Glass862f8e22019-08-24 07:22:43 -0600237 if cls._indir:
238 shutil.rmtree(cls._indir)
239 cls._indir = None
Simon Glass57454f42016-11-25 20:15:52 -0700240
Simon Glass1c420c92019-07-08 13:18:49 -0600241 @classmethod
Simon Glasscebfab22019-07-08 13:18:50 -0600242 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
Simon Glassf46732a2019-07-08 14:25:29 -0600243 toolpath=None, verbosity=None):
Simon Glass1c420c92019-07-08 13:18:49 -0600244 """Accept arguments controlling test execution
245
246 Args:
247 preserve_indir: Preserve the shared input directory used by all
248 tests in this class.
249 preserve_outdir: Preserve the output directories used by tests. Each
250 test has its own, so this is normally only useful when running a
251 single test.
Simon Glasscebfab22019-07-08 13:18:50 -0600252 toolpath: ist of paths to use for tools
Simon Glass1c420c92019-07-08 13:18:49 -0600253 """
254 cls.preserve_indir = preserve_indir
255 cls.preserve_outdirs = preserve_outdirs
Simon Glasscebfab22019-07-08 13:18:50 -0600256 cls.toolpath = toolpath
Simon Glassf46732a2019-07-08 14:25:29 -0600257 cls.verbosity = verbosity
Simon Glass1c420c92019-07-08 13:18:49 -0600258
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200259 def _CheckBintool(self, bintool):
260 if not bintool.is_present():
261 self.skipTest('%s not available' % bintool.name)
262
Simon Glass1de34482019-07-08 13:18:53 -0600263 def _CheckLz4(self):
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200264 bintool = self.comp_bintools['lz4']
265 self._CheckBintool(bintool)
Simon Glass1de34482019-07-08 13:18:53 -0600266
Simon Glassee9d10d2019-07-20 12:24:09 -0600267 def _CleanupOutputDir(self):
268 """Remove the temporary output directory"""
269 if self.preserve_outdirs:
270 print('Preserving output dir: %s' % tools.outdir)
271 else:
Simon Glass80025522022-01-29 14:14:04 -0700272 tools._finalise_for_test()
Simon Glassee9d10d2019-07-20 12:24:09 -0600273
Simon Glass57454f42016-11-25 20:15:52 -0700274 def setUp(self):
275 # Enable this to turn on debugging output
Simon Glass011f1b32022-01-29 14:14:15 -0700276 # tout.init(tout.DEBUG)
Simon Glass57454f42016-11-25 20:15:52 -0700277 command.test_result = None
278
279 def tearDown(self):
280 """Remove the temporary output directory"""
Simon Glassee9d10d2019-07-20 12:24:09 -0600281 self._CleanupOutputDir()
Simon Glass57454f42016-11-25 20:15:52 -0700282
Simon Glassb3d6fc72019-07-20 12:24:10 -0600283 def _SetupImageInTmpdir(self):
284 """Set up the output image in a new temporary directory
285
286 This is used when an image has been generated in the output directory,
287 but we want to run binman again. This will create a new output
288 directory and fail to delete the original one.
289
290 This creates a new temporary directory, copies the image to it (with a
291 new name) and removes the old output directory.
292
293 Returns:
294 Tuple:
295 Temporary directory to use
296 New image filename
297 """
Simon Glass80025522022-01-29 14:14:04 -0700298 image_fname = tools.get_output_filename('image.bin')
Simon Glassb3d6fc72019-07-20 12:24:10 -0600299 tmpdir = tempfile.mkdtemp(prefix='binman.')
300 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
Simon Glass80025522022-01-29 14:14:04 -0700301 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassb3d6fc72019-07-20 12:24:10 -0600302 self._CleanupOutputDir()
303 return tmpdir, updated_fname
304
Simon Glass8425a1f2018-07-17 13:25:48 -0600305 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600306 def _ResetDtbs(cls):
Simon Glass8425a1f2018-07-17 13:25:48 -0600307 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
308 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
309 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
Simon Glass56d05412022-02-28 07:16:54 -0700310 TestFunctional._MakeInputFile('vpl/u-boot-vpl.dtb', U_BOOT_VPL_DTB_DATA)
Simon Glass8425a1f2018-07-17 13:25:48 -0600311
Simon Glass57454f42016-11-25 20:15:52 -0700312 def _RunBinman(self, *args, **kwargs):
313 """Run binman using the command line
314
315 Args:
316 Arguments to pass, as a list of strings
317 kwargs: Arguments to pass to Command.RunPipe()
318 """
Simon Glass840be732022-01-29 14:14:05 -0700319 result = command.run_pipe([[self._binman_pathname] + list(args)],
Simon Glass57454f42016-11-25 20:15:52 -0700320 capture=True, capture_stderr=True, raise_on_error=False)
321 if result.return_code and kwargs.get('raise_on_error', True):
322 raise Exception("Error running '%s': %s" % (' '.join(args),
323 result.stdout + result.stderr))
324 return result
325
Simon Glassf46732a2019-07-08 14:25:29 -0600326 def _DoBinman(self, *argv):
Simon Glass57454f42016-11-25 20:15:52 -0700327 """Run binman using directly (in the same process)
328
329 Args:
330 Arguments to pass, as a list of strings
331 Returns:
332 Return value (0 for success)
333 """
Simon Glassf46732a2019-07-08 14:25:29 -0600334 argv = list(argv)
335 args = cmdline.ParseArgs(argv)
336 args.pager = 'binman-invalid-pager'
337 args.build_dir = self._indir
Simon Glass57454f42016-11-25 20:15:52 -0700338
339 # For testing, you can force an increase in verbosity here
Simon Glassf46732a2019-07-08 14:25:29 -0600340 # args.verbosity = tout.DEBUG
341 return control.Binman(args)
Simon Glass57454f42016-11-25 20:15:52 -0700342
Simon Glass91710b32018-07-17 13:25:32 -0600343 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glassb4595d82019-04-25 21:58:34 -0600344 entry_args=None, images=None, use_real_dtb=False,
Simon Glassed930672021-03-18 20:25:05 +1300345 use_expanded=False, verbosity=None, allow_missing=False,
Heiko Thiery6d451362022-01-06 11:49:41 +0100346 allow_fake_blobs=False, extra_indirs=None, threads=None,
Simon Glass66152ce2022-01-09 20:14:09 -0700347 test_section_timeout=False, update_fdt_in_elf=None,
Simon Glass6bce5dc2022-11-09 19:14:42 -0700348 force_missing_bintools='', ignore_missing=False):
Simon Glass57454f42016-11-25 20:15:52 -0700349 """Run binman with a given test file
350
351 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600352 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600353 debug: True to enable debugging output
Simon Glass30732662018-06-01 09:38:20 -0600354 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600355 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600356 tree before packing it into the image
Simon Glass3b376c32018-09-14 04:57:12 -0600357 entry_args: Dict of entry args to supply to binman
358 key: arg name
359 value: value of that arg
360 images: List of image names to build
Simon Glass31ee50f2020-09-01 05:13:55 -0600361 use_real_dtb: True to use the test file as the contents of
362 the u-boot-dtb entry. Normally this is not needed and the
363 test contents (the U_BOOT_DTB_DATA string) can be used.
364 But in some test we need the real contents.
Simon Glassed930672021-03-18 20:25:05 +1300365 use_expanded: True to use expanded entries where available, e.g.
366 'u-boot-expanded' instead of 'u-boot'
Simon Glass31ee50f2020-09-01 05:13:55 -0600367 verbosity: Verbosity level to use (0-3, None=don't set it)
368 allow_missing: Set the '--allow-missing' flag so that missing
369 external binaries just produce a warning instead of an error
Heiko Thiery6d451362022-01-06 11:49:41 +0100370 allow_fake_blobs: Set the '--fake-ext-blobs' flag
Simon Glassa435cd12020-09-01 05:13:59 -0600371 extra_indirs: Extra input directories to add using -I
Simon Glass76f496d2021-07-06 10:36:37 -0600372 threads: Number of threads to use (None for default, 0 for
373 single-threaded)
Simon Glass9a798402021-11-03 21:09:17 -0600374 test_section_timeout: True to force the first time to timeout, as
375 used in testThreadTimeout()
Simon Glassadfb8492021-11-03 21:09:18 -0600376 update_fdt_in_elf: Value to pass with --update-fdt-in-elf=xxx
Simon Glass66152ce2022-01-09 20:14:09 -0700377 force_missing_tools (str): comma-separated list of bintools to
378 regard as missing
Simon Glass9a798402021-11-03 21:09:17 -0600379
380 Returns:
381 int return code, 0 on success
Simon Glass57454f42016-11-25 20:15:52 -0700382 """
Simon Glassf46732a2019-07-08 14:25:29 -0600383 args = []
Simon Glass075a45c2017-11-13 18:55:00 -0700384 if debug:
385 args.append('-D')
Simon Glassf46732a2019-07-08 14:25:29 -0600386 if verbosity is not None:
387 args.append('-v%d' % verbosity)
388 elif self.verbosity:
389 args.append('-v%d' % self.verbosity)
390 if self.toolpath:
391 for path in self.toolpath:
392 args += ['--toolpath', path]
Simon Glass76f496d2021-07-06 10:36:37 -0600393 if threads is not None:
394 args.append('-T%d' % threads)
395 if test_section_timeout:
396 args.append('--test-section-timeout')
Simon Glassf46732a2019-07-08 14:25:29 -0600397 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass30732662018-06-01 09:38:20 -0600398 if map:
399 args.append('-m')
Simon Glassa87014e2018-07-06 10:27:42 -0600400 if update_dtb:
Simon Glass38a411c2019-07-08 13:18:47 -0600401 args.append('-u')
Simon Glass31402012018-09-14 04:57:23 -0600402 if not use_real_dtb:
403 args.append('--fake-dtb')
Simon Glassed930672021-03-18 20:25:05 +1300404 if not use_expanded:
405 args.append('--no-expanded')
Simon Glass91710b32018-07-17 13:25:32 -0600406 if entry_args:
Simon Glass5f3645b2019-05-14 15:53:41 -0600407 for arg, value in entry_args.items():
Simon Glass91710b32018-07-17 13:25:32 -0600408 args.append('-a%s=%s' % (arg, value))
Simon Glass5d94cc62020-07-09 18:39:38 -0600409 if allow_missing:
410 args.append('-M')
Simon Glass6bce5dc2022-11-09 19:14:42 -0700411 if ignore_missing:
412 args.append('-W')
Heiko Thiery6d451362022-01-06 11:49:41 +0100413 if allow_fake_blobs:
414 args.append('--fake-ext-blobs')
Simon Glass66152ce2022-01-09 20:14:09 -0700415 if force_missing_bintools:
416 args += ['--force-missing-bintools', force_missing_bintools]
Simon Glassadfb8492021-11-03 21:09:18 -0600417 if update_fdt_in_elf:
418 args += ['--update-fdt-in-elf', update_fdt_in_elf]
Simon Glass3b376c32018-09-14 04:57:12 -0600419 if images:
420 for image in images:
421 args += ['-i', image]
Simon Glassa435cd12020-09-01 05:13:59 -0600422 if extra_indirs:
423 for indir in extra_indirs:
424 args += ['-I', indir]
Simon Glass075a45c2017-11-13 18:55:00 -0700425 return self._DoBinman(*args)
Simon Glass57454f42016-11-25 20:15:52 -0700426
427 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glass72232452016-11-25 20:15:53 -0700428 """Set up a new test device-tree file
429
430 The given file is compiled and set up as the device tree to be used
431 for ths test.
432
433 Args:
434 fname: Filename of .dts file to read
Simon Glass1e324002018-06-01 09:38:19 -0600435 outfile: Output filename for compiled device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700436
437 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600438 Contents of device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700439 """
Simon Glassb8d2daa2019-07-20 12:23:49 -0600440 tmpdir = tempfile.mkdtemp(prefix='binmant.')
441 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
Simon Glass33486662019-05-14 15:53:42 -0600442 with open(dtb, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700443 data = fd.read()
444 TestFunctional._MakeInputFile(outfile, data)
Simon Glassb8d2daa2019-07-20 12:23:49 -0600445 shutil.rmtree(tmpdir)
Simon Glass752e7552018-10-01 21:12:41 -0600446 return data
Simon Glass57454f42016-11-25 20:15:52 -0700447
Simon Glass56d05412022-02-28 07:16:54 -0700448 def _GetDtbContentsForSpls(self, dtb_data, name):
449 """Create a version of the main DTB for SPL / TPL / VPL
Simon Glasse219aa42018-09-14 04:57:24 -0600450
451 For testing we don't actually have different versions of the DTB. With
452 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
453 we don't normally have any unwanted nodes.
454
455 We still want the DTBs for SPL and TPL to be different though, since
456 otherwise it is confusing to know which one we are looking at. So add
457 an 'spl' or 'tpl' property to the top-level node.
Simon Glass31ee50f2020-09-01 05:13:55 -0600458
459 Args:
460 dtb_data: dtb data to modify (this should be a value devicetree)
461 name: Name of a new property to add
462
463 Returns:
464 New dtb data with the property added
Simon Glasse219aa42018-09-14 04:57:24 -0600465 """
466 dtb = fdt.Fdt.FromData(dtb_data)
467 dtb.Scan()
468 dtb.GetNode('/binman').AddZeroProp(name)
469 dtb.Sync(auto_resize=True)
470 dtb.Pack()
471 return dtb.GetContents()
472
Simon Glassed930672021-03-18 20:25:05 +1300473 def _DoReadFileDtb(self, fname, use_real_dtb=False, use_expanded=False,
474 map=False, update_dtb=False, entry_args=None,
Simon Glass76f496d2021-07-06 10:36:37 -0600475 reset_dtbs=True, extra_indirs=None, threads=None):
Simon Glass57454f42016-11-25 20:15:52 -0700476 """Run binman and return the resulting image
477
478 This runs binman with a given test file and then reads the resulting
479 output file. It is a shortcut function since most tests need to do
480 these steps.
481
482 Raises an assertion failure if binman returns a non-zero exit code.
483
484 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600485 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass57454f42016-11-25 20:15:52 -0700486 use_real_dtb: True to use the test file as the contents of
487 the u-boot-dtb entry. Normally this is not needed and the
488 test contents (the U_BOOT_DTB_DATA string) can be used.
489 But in some test we need the real contents.
Simon Glassed930672021-03-18 20:25:05 +1300490 use_expanded: True to use expanded entries where available, e.g.
491 'u-boot-expanded' instead of 'u-boot'
Simon Glass30732662018-06-01 09:38:20 -0600492 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600493 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600494 tree before packing it into the image
Simon Glass31ee50f2020-09-01 05:13:55 -0600495 entry_args: Dict of entry args to supply to binman
496 key: arg name
497 value: value of that arg
498 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
499 function. If reset_dtbs is True, then the original test dtb
500 is written back before this function finishes
Simon Glassa435cd12020-09-01 05:13:59 -0600501 extra_indirs: Extra input directories to add using -I
Simon Glass76f496d2021-07-06 10:36:37 -0600502 threads: Number of threads to use (None for default, 0 for
503 single-threaded)
Simon Glass72232452016-11-25 20:15:53 -0700504
505 Returns:
506 Tuple:
507 Resulting image contents
508 Device tree contents
Simon Glass30732662018-06-01 09:38:20 -0600509 Map data showing contents of image (or None if none)
Simon Glassdef77b52018-07-17 13:25:27 -0600510 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass57454f42016-11-25 20:15:52 -0700511 """
Simon Glass72232452016-11-25 20:15:53 -0700512 dtb_data = None
Simon Glass57454f42016-11-25 20:15:52 -0700513 # Use the compiled test file as the u-boot-dtb input
514 if use_real_dtb:
Simon Glass72232452016-11-25 20:15:53 -0700515 dtb_data = self._SetupDtb(fname)
Simon Glasse219aa42018-09-14 04:57:24 -0600516
517 # For testing purposes, make a copy of the DT for SPL and TPL. Add
518 # a node indicating which it is, so aid verification.
Simon Glass56d05412022-02-28 07:16:54 -0700519 for name in ['spl', 'tpl', 'vpl']:
Simon Glasse219aa42018-09-14 04:57:24 -0600520 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
521 outfile = os.path.join(self._indir, dtb_fname)
522 TestFunctional._MakeInputFile(dtb_fname,
Simon Glass56d05412022-02-28 07:16:54 -0700523 self._GetDtbContentsForSpls(dtb_data, name))
Simon Glass57454f42016-11-25 20:15:52 -0700524
525 try:
Simon Glass91710b32018-07-17 13:25:32 -0600526 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glassa435cd12020-09-01 05:13:59 -0600527 entry_args=entry_args, use_real_dtb=use_real_dtb,
Simon Glass76f496d2021-07-06 10:36:37 -0600528 use_expanded=use_expanded, extra_indirs=extra_indirs,
529 threads=threads)
Simon Glass57454f42016-11-25 20:15:52 -0700530 self.assertEqual(0, retcode)
Simon Glass80025522022-01-29 14:14:04 -0700531 out_dtb_fname = tools.get_output_filename('u-boot.dtb.out')
Simon Glass57454f42016-11-25 20:15:52 -0700532
533 # Find the (only) image, read it and return its contents
534 image = control.images['image']
Simon Glass80025522022-01-29 14:14:04 -0700535 image_fname = tools.get_output_filename('image.bin')
Simon Glassa87014e2018-07-06 10:27:42 -0600536 self.assertTrue(os.path.exists(image_fname))
Simon Glass30732662018-06-01 09:38:20 -0600537 if map:
Simon Glass80025522022-01-29 14:14:04 -0700538 map_fname = tools.get_output_filename('image.map')
Simon Glass30732662018-06-01 09:38:20 -0600539 with open(map_fname) as fd:
540 map_data = fd.read()
541 else:
542 map_data = None
Simon Glass33486662019-05-14 15:53:42 -0600543 with open(image_fname, 'rb') as fd:
Simon Glassa87014e2018-07-06 10:27:42 -0600544 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass57454f42016-11-25 20:15:52 -0700545 finally:
546 # Put the test file back
Simon Glasse219aa42018-09-14 04:57:24 -0600547 if reset_dtbs and use_real_dtb:
Simon Glass8425a1f2018-07-17 13:25:48 -0600548 self._ResetDtbs()
Simon Glass57454f42016-11-25 20:15:52 -0700549
Simon Glass5b4bce32019-07-08 14:25:26 -0600550 def _DoReadFileRealDtb(self, fname):
551 """Run binman with a real .dtb file and return the resulting data
552
553 Args:
554 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
555
556 Returns:
557 Resulting image contents
558 """
559 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
560
Simon Glass72232452016-11-25 20:15:53 -0700561 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass1e324002018-06-01 09:38:19 -0600562 """Helper function which discards the device-tree binary
563
564 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600565 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600566 use_real_dtb: True to use the test file as the contents of
567 the u-boot-dtb entry. Normally this is not needed and the
568 test contents (the U_BOOT_DTB_DATA string) can be used.
569 But in some test we need the real contents.
Simon Glassdef77b52018-07-17 13:25:27 -0600570
571 Returns:
572 Resulting image contents
Simon Glass1e324002018-06-01 09:38:19 -0600573 """
Simon Glass72232452016-11-25 20:15:53 -0700574 return self._DoReadFileDtb(fname, use_real_dtb)[0]
575
Simon Glass57454f42016-11-25 20:15:52 -0700576 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600577 def _MakeInputFile(cls, fname, contents):
Simon Glass57454f42016-11-25 20:15:52 -0700578 """Create a new test input file, creating directories as needed
579
580 Args:
Simon Glasse8561af2018-08-01 15:22:37 -0600581 fname: Filename to create
Simon Glass57454f42016-11-25 20:15:52 -0700582 contents: File contents to write in to the file
583 Returns:
584 Full pathname of file created
585 """
Simon Glass862f8e22019-08-24 07:22:43 -0600586 pathname = os.path.join(cls._indir, fname)
Simon Glass57454f42016-11-25 20:15:52 -0700587 dirname = os.path.dirname(pathname)
588 if dirname and not os.path.exists(dirname):
589 os.makedirs(dirname)
590 with open(pathname, 'wb') as fd:
591 fd.write(contents)
592 return pathname
593
594 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600595 def _MakeInputDir(cls, dirname):
Simon Glassc1ae83c2018-07-17 13:25:44 -0600596 """Create a new test input directory, creating directories as needed
597
598 Args:
599 dirname: Directory name to create
600
601 Returns:
602 Full pathname of directory created
603 """
Simon Glass862f8e22019-08-24 07:22:43 -0600604 pathname = os.path.join(cls._indir, dirname)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600605 if not os.path.exists(pathname):
606 os.makedirs(pathname)
607 return pathname
608
609 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600610 def _SetupSplElf(cls, src_fname='bss_data'):
Simon Glass7057d022018-10-01 21:12:47 -0600611 """Set up an ELF file with a '_dt_ucode_base_size' symbol
612
613 Args:
614 Filename of ELF file to use as SPL
615 """
Simon Glass93a806f2019-08-24 07:22:59 -0600616 TestFunctional._MakeInputFile('spl/u-boot-spl',
Simon Glass80025522022-01-29 14:14:04 -0700617 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass7057d022018-10-01 21:12:47 -0600618
619 @classmethod
Simon Glass3eb5b202019-08-24 07:23:00 -0600620 def _SetupTplElf(cls, src_fname='bss_data'):
621 """Set up an ELF file with a '_dt_ucode_base_size' symbol
622
623 Args:
624 Filename of ELF file to use as TPL
625 """
626 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
Simon Glass80025522022-01-29 14:14:04 -0700627 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass3eb5b202019-08-24 07:23:00 -0600628
629 @classmethod
Simon Glass56d05412022-02-28 07:16:54 -0700630 def _SetupVplElf(cls, src_fname='bss_data'):
631 """Set up an ELF file with a '_dt_ucode_base_size' symbol
632
633 Args:
634 Filename of ELF file to use as VPL
635 """
636 TestFunctional._MakeInputFile('vpl/u-boot-vpl',
637 tools.read_file(cls.ElfTestFile(src_fname)))
638
639 @classmethod
Simon Glasse88cef92020-07-09 18:39:41 -0600640 def _SetupDescriptor(cls):
641 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
642 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
643
644 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600645 def TestFile(cls, fname):
646 return os.path.join(cls._binman_dir, 'test', fname)
Simon Glass57454f42016-11-25 20:15:52 -0700647
Simon Glassf6290892019-08-24 07:22:53 -0600648 @classmethod
649 def ElfTestFile(cls, fname):
650 return os.path.join(cls._elf_testdir, fname)
651
Simon Glassad5cfe12023-01-07 14:07:14 -0700652 @classmethod
653 def make_tee_bin(cls, fname, paged_sz=0, extra_data=b''):
654 init_sz, start_hi, start_lo, dummy = (len(U_BOOT_DATA), 0, TEE_ADDR, 0)
655 data = b'OPTE\x01xxx' + struct.pack('<5I', init_sz, start_hi, start_lo,
656 dummy, paged_sz) + U_BOOT_DATA
657 data += extra_data
658 TestFunctional._MakeInputFile(fname, data)
659
Simon Glass57454f42016-11-25 20:15:52 -0700660 def AssertInList(self, grep_list, target):
661 """Assert that at least one of a list of things is in a target
662
663 Args:
664 grep_list: List of strings to check
665 target: Target string
666 """
667 for grep in grep_list:
668 if grep in target:
669 return
Simon Glass848cdb52019-05-17 22:00:50 -0600670 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass57454f42016-11-25 20:15:52 -0700671
672 def CheckNoGaps(self, entries):
673 """Check that all entries fit together without gaps
674
675 Args:
676 entries: List of entries to check
677 """
Simon Glasse8561af2018-08-01 15:22:37 -0600678 offset = 0
Simon Glass57454f42016-11-25 20:15:52 -0700679 for entry in entries.values():
Simon Glasse8561af2018-08-01 15:22:37 -0600680 self.assertEqual(offset, entry.offset)
681 offset += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700682
Simon Glass72232452016-11-25 20:15:53 -0700683 def GetFdtLen(self, dtb):
Simon Glass1e324002018-06-01 09:38:19 -0600684 """Get the totalsize field from a device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700685
686 Args:
Simon Glass1e324002018-06-01 09:38:19 -0600687 dtb: Device-tree binary contents
Simon Glass72232452016-11-25 20:15:53 -0700688
689 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600690 Total size of device-tree binary, from the header
Simon Glass72232452016-11-25 20:15:53 -0700691 """
692 return struct.unpack('>L', dtb[4:8])[0]
693
Simon Glass0f621332019-07-08 14:25:27 -0600694 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glassa87014e2018-07-06 10:27:42 -0600695 def AddNode(node, path):
696 if node.name != '/':
697 path += '/' + node.name
Simon Glass0f621332019-07-08 14:25:27 -0600698 for prop in node.props.values():
699 if prop.name in prop_names:
700 prop_path = path + ':' + prop.name
701 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
702 prop.value)
Simon Glassa87014e2018-07-06 10:27:42 -0600703 for subnode in node.subnodes:
Simon Glassa87014e2018-07-06 10:27:42 -0600704 AddNode(subnode, path)
705
706 tree = {}
Simon Glassa87014e2018-07-06 10:27:42 -0600707 AddNode(dtb.GetRoot(), '')
708 return tree
709
Simon Glass57454f42016-11-25 20:15:52 -0700710 def testRun(self):
711 """Test a basic run with valid args"""
712 result = self._RunBinman('-h')
713
714 def testFullHelp(self):
715 """Test that the full help is displayed with -H"""
716 result = self._RunBinman('-H')
Simon Glass75ead662021-03-18 20:25:13 +1300717 help_file = os.path.join(self._binman_dir, 'README.rst')
Tom Rinic3c0b6d2018-01-16 15:29:50 -0500718 # Remove possible extraneous strings
719 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
720 gothelp = result.stdout.replace(extra, '')
721 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass57454f42016-11-25 20:15:52 -0700722 self.assertEqual(0, len(result.stderr))
723 self.assertEqual(0, result.return_code)
724
725 def testFullHelpInternal(self):
726 """Test that the full help is displayed with -H"""
727 try:
728 command.test_result = command.CommandResult()
729 result = self._DoBinman('-H')
Simon Glass75ead662021-03-18 20:25:13 +1300730 help_file = os.path.join(self._binman_dir, 'README.rst')
Simon Glass57454f42016-11-25 20:15:52 -0700731 finally:
732 command.test_result = None
733
734 def testHelp(self):
735 """Test that the basic help is displayed with -h"""
736 result = self._RunBinman('-h')
737 self.assertTrue(len(result.stdout) > 200)
738 self.assertEqual(0, len(result.stderr))
739 self.assertEqual(0, result.return_code)
740
Simon Glass57454f42016-11-25 20:15:52 -0700741 def testBoard(self):
742 """Test that we can run it with a specific board"""
Simon Glass511f6582018-10-01 12:22:30 -0600743 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass57454f42016-11-25 20:15:52 -0700744 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glassed930672021-03-18 20:25:05 +1300745 result = self._DoBinman('build', '-n', '-b', 'sandbox')
Simon Glass57454f42016-11-25 20:15:52 -0700746 self.assertEqual(0, result)
747
748 def testNeedBoard(self):
749 """Test that we get an error when no board ius supplied"""
750 with self.assertRaises(ValueError) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600751 result = self._DoBinman('build')
Simon Glass57454f42016-11-25 20:15:52 -0700752 self.assertIn("Must provide a board to process (use -b <board>)",
753 str(e.exception))
754
755 def testMissingDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600756 """Test that an invalid device-tree file generates an error"""
Simon Glass57454f42016-11-25 20:15:52 -0700757 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600758 self._RunBinman('build', '-d', 'missing_file')
Simon Glass57454f42016-11-25 20:15:52 -0700759 # We get one error from libfdt, and a different one from fdtget.
760 self.AssertInList(["Couldn't open blob from 'missing_file'",
761 'No such file or directory'], str(e.exception))
762
763 def testBrokenDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600764 """Test that an invalid device-tree source file generates an error
Simon Glass57454f42016-11-25 20:15:52 -0700765
766 Since this is a source file it should be compiled and the error
767 will come from the device-tree compiler (dtc).
768 """
769 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600770 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700771 self.assertIn("FATAL ERROR: Unable to parse input tree",
772 str(e.exception))
773
774 def testMissingNode(self):
775 """Test that a device tree without a 'binman' node generates an error"""
776 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600777 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700778 self.assertIn("does not have a 'binman' node", str(e.exception))
779
780 def testEmpty(self):
781 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glassf46732a2019-07-08 14:25:29 -0600782 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700783 self.assertEqual(0, len(result.stderr))
784 self.assertEqual(0, result.return_code)
785
786 def testInvalidEntry(self):
787 """Test that an invalid entry is flagged"""
788 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600789 result = self._RunBinman('build', '-d',
Simon Glass511f6582018-10-01 12:22:30 -0600790 self.TestFile('004_invalid_entry.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700791 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
792 "'/binman/not-a-valid-type'", str(e.exception))
793
794 def testSimple(self):
795 """Test a simple binman with a single file"""
Simon Glass511f6582018-10-01 12:22:30 -0600796 data = self._DoReadFile('005_simple.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700797 self.assertEqual(U_BOOT_DATA, data)
798
Simon Glass075a45c2017-11-13 18:55:00 -0700799 def testSimpleDebug(self):
800 """Test a simple binman run with debugging enabled"""
Simon Glass52d06212019-07-08 14:25:53 -0600801 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass075a45c2017-11-13 18:55:00 -0700802
Simon Glass57454f42016-11-25 20:15:52 -0700803 def testDual(self):
804 """Test that we can handle creating two images
805
806 This also tests image padding.
807 """
Simon Glass511f6582018-10-01 12:22:30 -0600808 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700809 self.assertEqual(0, retcode)
810
811 image = control.images['image1']
Simon Glass39dd2152019-07-08 14:25:47 -0600812 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glass80025522022-01-29 14:14:04 -0700813 fname = tools.get_output_filename('image1.bin')
Simon Glass57454f42016-11-25 20:15:52 -0700814 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600815 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700816 data = fd.read()
817 self.assertEqual(U_BOOT_DATA, data)
818
819 image = control.images['image2']
Simon Glass39dd2152019-07-08 14:25:47 -0600820 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glass80025522022-01-29 14:14:04 -0700821 fname = tools.get_output_filename('image2.bin')
Simon Glass57454f42016-11-25 20:15:52 -0700822 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600823 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700824 data = fd.read()
825 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glass80025522022-01-29 14:14:04 -0700826 self.assertEqual(tools.get_bytes(0, 3), data[:3])
827 self.assertEqual(tools.get_bytes(0, 5), data[7:])
Simon Glass57454f42016-11-25 20:15:52 -0700828
829 def testBadAlign(self):
830 """Test that an invalid alignment value is detected"""
831 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600832 self._DoTestFile('007_bad_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700833 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
834 "of two", str(e.exception))
835
836 def testPackSimple(self):
837 """Test that packing works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -0600838 retcode = self._DoTestFile('008_pack.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700839 self.assertEqual(0, retcode)
840 self.assertIn('image', control.images)
841 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600842 entries = image.GetEntries()
Simon Glass57454f42016-11-25 20:15:52 -0700843 self.assertEqual(5, len(entries))
844
845 # First u-boot
846 self.assertIn('u-boot', entries)
847 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600848 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700849 self.assertEqual(len(U_BOOT_DATA), entry.size)
850
851 # Second u-boot, aligned to 16-byte boundary
852 self.assertIn('u-boot-align', entries)
853 entry = entries['u-boot-align']
Simon Glasse8561af2018-08-01 15:22:37 -0600854 self.assertEqual(16, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700855 self.assertEqual(len(U_BOOT_DATA), entry.size)
856
857 # Third u-boot, size 23 bytes
858 self.assertIn('u-boot-size', entries)
859 entry = entries['u-boot-size']
Simon Glasse8561af2018-08-01 15:22:37 -0600860 self.assertEqual(20, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700861 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
862 self.assertEqual(23, entry.size)
863
864 # Fourth u-boot, placed immediate after the above
865 self.assertIn('u-boot-next', entries)
866 entry = entries['u-boot-next']
Simon Glasse8561af2018-08-01 15:22:37 -0600867 self.assertEqual(43, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700868 self.assertEqual(len(U_BOOT_DATA), entry.size)
869
Simon Glasse8561af2018-08-01 15:22:37 -0600870 # Fifth u-boot, placed at a fixed offset
Simon Glass57454f42016-11-25 20:15:52 -0700871 self.assertIn('u-boot-fixed', entries)
872 entry = entries['u-boot-fixed']
Simon Glasse8561af2018-08-01 15:22:37 -0600873 self.assertEqual(61, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700874 self.assertEqual(len(U_BOOT_DATA), entry.size)
875
Simon Glass39dd2152019-07-08 14:25:47 -0600876 self.assertEqual(65, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700877
878 def testPackExtra(self):
879 """Test that extra packing feature works as expected"""
Simon Glassafb9caa2020-10-26 17:40:10 -0600880 data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
881 update_dtb=True)
Simon Glass57454f42016-11-25 20:15:52 -0700882
Simon Glass57454f42016-11-25 20:15:52 -0700883 self.assertIn('image', control.images)
884 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600885 entries = image.GetEntries()
Samuel Hollande2574022023-01-21 17:25:16 -0600886 self.assertEqual(6, len(entries))
Simon Glass57454f42016-11-25 20:15:52 -0700887
Samuel Hollande2574022023-01-21 17:25:16 -0600888 # First u-boot with padding before and after (included in minimum size)
Simon Glass57454f42016-11-25 20:15:52 -0700889 self.assertIn('u-boot', entries)
890 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600891 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700892 self.assertEqual(3, entry.pad_before)
893 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600894 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glass80025522022-01-29 14:14:04 -0700895 self.assertEqual(tools.get_bytes(0, 3) + U_BOOT_DATA +
896 tools.get_bytes(0, 5), data[:entry.size])
Simon Glass187202f2020-10-26 17:40:08 -0600897 pos = entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700898
899 # Second u-boot has an aligned size, but it has no effect
900 self.assertIn('u-boot-align-size-nop', entries)
901 entry = entries['u-boot-align-size-nop']
Simon Glass187202f2020-10-26 17:40:08 -0600902 self.assertEqual(pos, entry.offset)
903 self.assertEqual(len(U_BOOT_DATA), entry.size)
904 self.assertEqual(U_BOOT_DATA, entry.data)
905 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
906 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700907
908 # Third u-boot has an aligned size too
909 self.assertIn('u-boot-align-size', entries)
910 entry = entries['u-boot-align-size']
Simon Glass187202f2020-10-26 17:40:08 -0600911 self.assertEqual(pos, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700912 self.assertEqual(32, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600913 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glass80025522022-01-29 14:14:04 -0700914 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600915 data[pos:pos + entry.size])
916 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700917
918 # Fourth u-boot has an aligned end
919 self.assertIn('u-boot-align-end', entries)
920 entry = entries['u-boot-align-end']
Simon Glasse8561af2018-08-01 15:22:37 -0600921 self.assertEqual(48, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700922 self.assertEqual(16, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600923 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glass80025522022-01-29 14:14:04 -0700924 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 16 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600925 data[pos:pos + entry.size])
926 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700927
928 # Fifth u-boot immediately afterwards
929 self.assertIn('u-boot-align-both', entries)
930 entry = entries['u-boot-align-both']
Simon Glasse8561af2018-08-01 15:22:37 -0600931 self.assertEqual(64, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700932 self.assertEqual(64, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600933 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glass80025522022-01-29 14:14:04 -0700934 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 64 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600935 data[pos:pos + entry.size])
Simon Glass57454f42016-11-25 20:15:52 -0700936
Samuel Hollande2574022023-01-21 17:25:16 -0600937 # Sixth u-boot with both minimum size and aligned size
938 self.assertIn('u-boot-min-size', entries)
939 entry = entries['u-boot-min-size']
940 self.assertEqual(128, entry.offset)
941 self.assertEqual(32, entry.size)
942 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
943 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
944 data[pos:pos + entry.size])
945
Simon Glass57454f42016-11-25 20:15:52 -0700946 self.CheckNoGaps(entries)
Samuel Hollande2574022023-01-21 17:25:16 -0600947 self.assertEqual(160, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700948
Simon Glassafb9caa2020-10-26 17:40:10 -0600949 dtb = fdt.Fdt(out_dtb_fname)
950 dtb.Scan()
951 props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
952 expected = {
953 'image-pos': 0,
954 'offset': 0,
Samuel Hollande2574022023-01-21 17:25:16 -0600955 'size': 160,
Simon Glassafb9caa2020-10-26 17:40:10 -0600956
957 'u-boot:image-pos': 0,
958 'u-boot:offset': 0,
959 'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
960
961 'u-boot-align-size-nop:image-pos': 12,
962 'u-boot-align-size-nop:offset': 12,
963 'u-boot-align-size-nop:size': 4,
964
965 'u-boot-align-size:image-pos': 16,
966 'u-boot-align-size:offset': 16,
967 'u-boot-align-size:size': 32,
968
969 'u-boot-align-end:image-pos': 48,
970 'u-boot-align-end:offset': 48,
971 'u-boot-align-end:size': 16,
972
973 'u-boot-align-both:image-pos': 64,
974 'u-boot-align-both:offset': 64,
975 'u-boot-align-both:size': 64,
Samuel Hollande2574022023-01-21 17:25:16 -0600976
977 'u-boot-min-size:image-pos': 128,
978 'u-boot-min-size:offset': 128,
979 'u-boot-min-size:size': 32,
Simon Glassafb9caa2020-10-26 17:40:10 -0600980 }
981 self.assertEqual(expected, props)
982
Simon Glass57454f42016-11-25 20:15:52 -0700983 def testPackAlignPowerOf2(self):
984 """Test that invalid entry alignment is detected"""
985 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600986 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700987 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
988 "of two", str(e.exception))
989
990 def testPackAlignSizePowerOf2(self):
991 """Test that invalid entry size alignment is detected"""
992 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600993 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700994 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
995 "power of two", str(e.exception))
996
997 def testPackInvalidAlign(self):
Simon Glasse8561af2018-08-01 15:22:37 -0600998 """Test detection of an offset that does not match its alignment"""
Simon Glass57454f42016-11-25 20:15:52 -0700999 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001000 self._DoTestFile('012_pack_inv_align.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001001 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass57454f42016-11-25 20:15:52 -07001002 "align 0x4 (4)", str(e.exception))
1003
1004 def testPackInvalidSizeAlign(self):
1005 """Test that invalid entry size alignment is detected"""
1006 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001007 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001008 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
1009 "align-size 0x4 (4)", str(e.exception))
1010
1011 def testPackOverlap(self):
1012 """Test that overlapping regions are detected"""
1013 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001014 self._DoTestFile('014_pack_overlap.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001015 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -07001016 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1017 str(e.exception))
1018
1019 def testPackEntryOverflow(self):
1020 """Test that entries that overflow their size are detected"""
1021 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001022 self._DoTestFile('015_pack_overflow.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001023 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
1024 "but entry size is 0x3 (3)", str(e.exception))
1025
1026 def testPackImageOverflow(self):
1027 """Test that entries which overflow the image size are detected"""
1028 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001029 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glasseca32212018-06-01 09:38:12 -06001030 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass57454f42016-11-25 20:15:52 -07001031 "size 0x3 (3)", str(e.exception))
1032
1033 def testPackImageSize(self):
1034 """Test that the image size can be set"""
Simon Glass511f6582018-10-01 12:22:30 -06001035 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001036 self.assertEqual(0, retcode)
1037 self.assertIn('image', control.images)
1038 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -06001039 self.assertEqual(7, image.size)
Simon Glass57454f42016-11-25 20:15:52 -07001040
1041 def testPackImageSizeAlign(self):
1042 """Test that image size alignemnt works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -06001043 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001044 self.assertEqual(0, retcode)
1045 self.assertIn('image', control.images)
1046 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -06001047 self.assertEqual(16, image.size)
Simon Glass57454f42016-11-25 20:15:52 -07001048
1049 def testPackInvalidImageAlign(self):
1050 """Test that invalid image alignment is detected"""
1051 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001052 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glasseca32212018-06-01 09:38:12 -06001053 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass57454f42016-11-25 20:15:52 -07001054 "align-size 0x8 (8)", str(e.exception))
1055
Simon Glass2a0fa982022-02-11 13:23:21 -07001056 def testPackAlignPowerOf2Inv(self):
Simon Glass57454f42016-11-25 20:15:52 -07001057 """Test that invalid image alignment is detected"""
1058 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001059 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001060 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass57454f42016-11-25 20:15:52 -07001061 "two", str(e.exception))
1062
1063 def testImagePadByte(self):
1064 """Test that the image pad byte can be specified"""
Simon Glass7057d022018-10-01 21:12:47 -06001065 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001066 data = self._DoReadFile('021_image_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07001067 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0xff, 1) +
Simon Glassac0d4952019-05-14 15:53:47 -06001068 U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -07001069
1070 def testImageName(self):
1071 """Test that image files can be named"""
Simon Glass511f6582018-10-01 12:22:30 -06001072 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001073 self.assertEqual(0, retcode)
1074 image = control.images['image1']
Simon Glass80025522022-01-29 14:14:04 -07001075 fname = tools.get_output_filename('test-name')
Simon Glass57454f42016-11-25 20:15:52 -07001076 self.assertTrue(os.path.exists(fname))
1077
1078 image = control.images['image2']
Simon Glass80025522022-01-29 14:14:04 -07001079 fname = tools.get_output_filename('test-name.xx')
Simon Glass57454f42016-11-25 20:15:52 -07001080 self.assertTrue(os.path.exists(fname))
1081
1082 def testBlobFilename(self):
1083 """Test that generic blobs can be provided by filename"""
Simon Glass511f6582018-10-01 12:22:30 -06001084 data = self._DoReadFile('023_blob.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001085 self.assertEqual(BLOB_DATA, data)
1086
1087 def testPackSorted(self):
1088 """Test that entries can be sorted"""
Simon Glass7057d022018-10-01 21:12:47 -06001089 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001090 data = self._DoReadFile('024_sorted.dts')
Simon Glass80025522022-01-29 14:14:04 -07001091 self.assertEqual(tools.get_bytes(0, 1) + U_BOOT_SPL_DATA +
1092 tools.get_bytes(0, 2) + U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -07001093
Simon Glasse8561af2018-08-01 15:22:37 -06001094 def testPackZeroOffset(self):
1095 """Test that an entry at offset 0 is not given a new offset"""
Simon Glass57454f42016-11-25 20:15:52 -07001096 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001097 self._DoTestFile('025_pack_zero_size.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001098 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -07001099 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1100 str(e.exception))
1101
1102 def testPackUbootDtb(self):
1103 """Test that a device tree can be added to U-Boot"""
Simon Glass511f6582018-10-01 12:22:30 -06001104 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001105 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glass72232452016-11-25 20:15:53 -07001106
1107 def testPackX86RomNoSize(self):
1108 """Test that the end-at-4gb property requires a size property"""
1109 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001110 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001111 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glass72232452016-11-25 20:15:53 -07001112 "using end-at-4gb", str(e.exception))
1113
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301114 def test4gbAndSkipAtStartTogether(self):
1115 """Test that the end-at-4gb and skip-at-size property can't be used
1116 together"""
1117 with self.assertRaises(ValueError) as e:
Simon Glass11f2bd02019-08-24 07:23:02 -06001118 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001119 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301120 "'skip-at-start'", str(e.exception))
1121
Simon Glass72232452016-11-25 20:15:53 -07001122 def testPackX86RomOutside(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001123 """Test that the end-at-4gb property checks for offset boundaries"""
Simon Glass72232452016-11-25 20:15:53 -07001124 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001125 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glassd6179862020-10-26 17:40:05 -06001126 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
1127 "is outside the section '/binman' starting at "
1128 '0xffffffe0 (4294967264) of size 0x20 (32)',
Simon Glass72232452016-11-25 20:15:53 -07001129 str(e.exception))
1130
1131 def testPackX86Rom(self):
1132 """Test that a basic x86 ROM can be created"""
Simon Glass7057d022018-10-01 21:12:47 -06001133 self._SetupSplElf()
Simon Glass1d167762019-08-24 07:23:01 -06001134 data = self._DoReadFile('029_x86_rom.dts')
Simon Glass80025522022-01-29 14:14:04 -07001135 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 3) + U_BOOT_SPL_DATA +
1136 tools.get_bytes(0, 2), data)
Simon Glass72232452016-11-25 20:15:53 -07001137
1138 def testPackX86RomMeNoDesc(self):
1139 """Test that an invalid Intel descriptor entry is detected"""
Simon Glasse88cef92020-07-09 18:39:41 -06001140 try:
Simon Glass14c596c2020-07-25 15:11:19 -06001141 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
Simon Glasse88cef92020-07-09 18:39:41 -06001142 with self.assertRaises(ValueError) as e:
Simon Glass14c596c2020-07-25 15:11:19 -06001143 self._DoTestFile('163_x86_rom_me_empty.dts')
Simon Glasse88cef92020-07-09 18:39:41 -06001144 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1145 str(e.exception))
1146 finally:
1147 self._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -07001148
1149 def testPackX86RomBadDesc(self):
1150 """Test that the Intel requires a descriptor entry"""
1151 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06001152 self._DoTestFile('030_x86_rom_me_no_desc.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001153 self.assertIn("Node '/binman/intel-me': No offset set with "
1154 "offset-unset: should another entry provide this correct "
1155 "offset?", str(e.exception))
Simon Glass72232452016-11-25 20:15:53 -07001156
1157 def testPackX86RomMe(self):
1158 """Test that an x86 ROM with an ME region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001159 data = self._DoReadFile('031_x86_rom_me.dts')
Simon Glass80025522022-01-29 14:14:04 -07001160 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glass759af872019-07-08 13:18:54 -06001161 if data[:0x1000] != expected_desc:
1162 self.fail('Expected descriptor binary at start of image')
Simon Glass72232452016-11-25 20:15:53 -07001163 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1164
1165 def testPackVga(self):
1166 """Test that an image with a VGA binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001167 data = self._DoReadFile('032_intel_vga.dts')
Simon Glass72232452016-11-25 20:15:53 -07001168 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1169
1170 def testPackStart16(self):
1171 """Test that an image with an x86 start16 region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001172 data = self._DoReadFile('033_x86_start16.dts')
Simon Glass72232452016-11-25 20:15:53 -07001173 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1174
Jagdish Gediya311d4842018-09-03 21:35:08 +05301175 def testPackPowerpcMpc85xxBootpgResetvec(self):
1176 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1177 created"""
Simon Glass11f2bd02019-08-24 07:23:02 -06001178 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
Jagdish Gediya311d4842018-09-03 21:35:08 +05301179 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1180
Simon Glass6ba679c2018-07-06 10:27:17 -06001181 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glass820af1d2018-07-06 10:27:16 -06001182 """Handle running a test for insertion of microcode
1183
1184 Args:
1185 dts_fname: Name of test .dts file
1186 nodtb_data: Data that we expect in the first section
Simon Glass6ba679c2018-07-06 10:27:17 -06001187 ucode_second: True if the microsecond entry is second instead of
1188 third
Simon Glass820af1d2018-07-06 10:27:16 -06001189
1190 Returns:
1191 Tuple:
1192 Contents of first region (U-Boot or SPL)
Simon Glasse8561af2018-08-01 15:22:37 -06001193 Offset and size components of microcode pointer, as inserted
Simon Glass820af1d2018-07-06 10:27:16 -06001194 in the above (two 4-byte words)
1195 """
Simon Glass3d274232017-11-12 21:52:27 -07001196 data = self._DoReadFile(dts_fname, True)
Simon Glass72232452016-11-25 20:15:53 -07001197
1198 # Now check the device tree has no microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001199 if ucode_second:
1200 ucode_content = data[len(nodtb_data):]
1201 ucode_pos = len(nodtb_data)
1202 dtb_with_ucode = ucode_content[16:]
1203 fdt_len = self.GetFdtLen(dtb_with_ucode)
1204 else:
1205 dtb_with_ucode = data[len(nodtb_data):]
1206 fdt_len = self.GetFdtLen(dtb_with_ucode)
1207 ucode_content = dtb_with_ucode[fdt_len:]
1208 ucode_pos = len(nodtb_data) + fdt_len
Simon Glass80025522022-01-29 14:14:04 -07001209 fname = tools.get_output_filename('test.dtb')
Simon Glass72232452016-11-25 20:15:53 -07001210 with open(fname, 'wb') as fd:
Simon Glass820af1d2018-07-06 10:27:16 -06001211 fd.write(dtb_with_ucode)
Simon Glass22c92ca2017-05-27 07:38:29 -06001212 dtb = fdt.FdtScan(fname)
1213 ucode = dtb.GetNode('/microcode')
Simon Glass72232452016-11-25 20:15:53 -07001214 self.assertTrue(ucode)
1215 for node in ucode.subnodes:
1216 self.assertFalse(node.props.get('data'))
1217
Simon Glass72232452016-11-25 20:15:53 -07001218 # Check that the microcode appears immediately after the Fdt
1219 # This matches the concatenation of the data properties in
Simon Glasse83679d2017-11-12 21:52:26 -07001220 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glass72232452016-11-25 20:15:53 -07001221 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1222 0x78235609)
Simon Glass820af1d2018-07-06 10:27:16 -06001223 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glass72232452016-11-25 20:15:53 -07001224
1225 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001226 # expected offset and size
Simon Glass72232452016-11-25 20:15:53 -07001227 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1228 len(ucode_data))
Simon Glass6ba679c2018-07-06 10:27:17 -06001229 u_boot = data[:len(nodtb_data)]
1230 return u_boot, pos_and_size
Simon Glass3d274232017-11-12 21:52:27 -07001231
1232 def testPackUbootMicrocode(self):
1233 """Test that x86 microcode can be handled correctly
1234
1235 We expect to see the following in the image, in order:
1236 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1237 place
1238 u-boot.dtb with the microcode removed
1239 the microcode
1240 """
Simon Glass511f6582018-10-01 12:22:30 -06001241 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass3d274232017-11-12 21:52:27 -07001242 U_BOOT_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06001243 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1244 b' somewhere in here', first)
Simon Glass72232452016-11-25 20:15:53 -07001245
Simon Glassbac25c82017-05-27 07:38:26 -06001246 def _RunPackUbootSingleMicrocode(self):
Simon Glass72232452016-11-25 20:15:53 -07001247 """Test that x86 microcode can be handled correctly
1248
1249 We expect to see the following in the image, in order:
1250 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1251 place
1252 u-boot.dtb with the microcode
1253 an empty microcode region
1254 """
1255 # We need the libfdt library to run this test since only that allows
1256 # finding the offset of a property. This is required by
1257 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass511f6582018-10-01 12:22:30 -06001258 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glass72232452016-11-25 20:15:53 -07001259
1260 second = data[len(U_BOOT_NODTB_DATA):]
1261
1262 fdt_len = self.GetFdtLen(second)
1263 third = second[fdt_len:]
1264 second = second[:fdt_len]
1265
Simon Glassbac25c82017-05-27 07:38:26 -06001266 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1267 self.assertIn(ucode_data, second)
1268 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glass72232452016-11-25 20:15:53 -07001269
Simon Glassbac25c82017-05-27 07:38:26 -06001270 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001271 # expected offset and size
Simon Glassbac25c82017-05-27 07:38:26 -06001272 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1273 len(ucode_data))
1274 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glass303f62f2019-05-17 22:00:46 -06001275 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1276 b' somewhere in here', first)
Simon Glass996021e2016-11-25 20:15:54 -07001277
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001278 def testPackUbootSingleMicrocode(self):
1279 """Test that x86 microcode can be handled correctly with fdt_normal.
1280 """
Simon Glassbac25c82017-05-27 07:38:26 -06001281 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001282
Simon Glass996021e2016-11-25 20:15:54 -07001283 def testUBootImg(self):
1284 """Test that u-boot.img can be put in a file"""
Simon Glass511f6582018-10-01 12:22:30 -06001285 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glass996021e2016-11-25 20:15:54 -07001286 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001287
1288 def testNoMicrocode(self):
1289 """Test that a missing microcode region is detected"""
1290 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001291 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001292 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1293 "node found in ", str(e.exception))
1294
1295 def testMicrocodeWithoutNode(self):
1296 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1297 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001298 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001299 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1300 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1301
1302 def testMicrocodeWithoutNode2(self):
1303 """Test that a missing u-boot-ucode node is detected"""
1304 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001305 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001306 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1307 "microcode region u-boot-ucode", str(e.exception))
1308
1309 def testMicrocodeWithoutPtrInElf(self):
1310 """Test that a U-Boot binary without the microcode symbol is detected"""
1311 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001312 try:
Simon Glassfaaaa162019-08-24 07:22:55 -06001313 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001314 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001315
1316 with self.assertRaises(ValueError) as e:
Simon Glassbac25c82017-05-27 07:38:26 -06001317 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001318 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1319 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1320
1321 finally:
1322 # Put the original file back
Simon Glass4affd4b2019-08-24 07:22:54 -06001323 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001324 tools.read_file(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001325
1326 def testMicrocodeNotInImage(self):
1327 """Test that microcode must be placed within the image"""
1328 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001329 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001330 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1331 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glassad5a7712018-06-01 09:38:14 -06001332 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001333
1334 def testWithoutMicrocode(self):
1335 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glassfaaaa162019-08-24 07:22:55 -06001336 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001337 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass511f6582018-10-01 12:22:30 -06001338 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001339
1340 # Now check the device tree has no microcode
1341 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1342 second = data[len(U_BOOT_NODTB_DATA):]
1343
1344 fdt_len = self.GetFdtLen(second)
1345 self.assertEqual(dtb, second[:fdt_len])
1346
1347 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1348 third = data[used_len:]
Simon Glass80025522022-01-29 14:14:04 -07001349 self.assertEqual(tools.get_bytes(0, 0x200 - used_len), third)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001350
1351 def testUnknownPosSize(self):
1352 """Test that microcode must be placed within the image"""
1353 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001354 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glasse8561af2018-08-01 15:22:37 -06001355 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001356 "entry 'invalid-entry'", str(e.exception))
Simon Glassb4176d42016-11-25 20:15:56 -07001357
1358 def testPackFsp(self):
1359 """Test that an image with a FSP binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001360 data = self._DoReadFile('042_intel_fsp.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001361 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1362
1363 def testPackCmc(self):
Bin Mengd7bcdf52017-08-15 22:41:54 -07001364 """Test that an image with a CMC binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001365 data = self._DoReadFile('043_intel_cmc.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001366 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Mengd7bcdf52017-08-15 22:41:54 -07001367
1368 def testPackVbt(self):
1369 """Test that an image with a VBT binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001370 data = self._DoReadFile('046_intel_vbt.dts')
Bin Mengd7bcdf52017-08-15 22:41:54 -07001371 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glassac599912017-11-12 21:52:22 -07001372
Simon Glass7f94e832017-11-12 21:52:25 -07001373 def testSplBssPad(self):
1374 """Test that we can pad SPL's BSS with zeros"""
Simon Glass3d274232017-11-12 21:52:27 -07001375 # ELF file with a '__bss_size' symbol
Simon Glass7057d022018-10-01 21:12:47 -06001376 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001377 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07001378 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glassac0d4952019-05-14 15:53:47 -06001379 data)
Simon Glass7f94e832017-11-12 21:52:25 -07001380
Simon Glass04cda032018-10-01 21:12:42 -06001381 def testSplBssPadMissing(self):
1382 """Test that a missing symbol is detected"""
Simon Glass7057d022018-10-01 21:12:47 -06001383 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass24ad3652017-11-13 18:54:54 -07001384 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001385 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass24ad3652017-11-13 18:54:54 -07001386 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1387 str(e.exception))
1388
Simon Glasse83679d2017-11-12 21:52:26 -07001389 def testPackStart16Spl(self):
Simon Glassed40e962018-09-14 04:57:10 -06001390 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001391 data = self._DoReadFile('048_x86_start16_spl.dts')
Simon Glasse83679d2017-11-12 21:52:26 -07001392 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1393
Simon Glass6ba679c2018-07-06 10:27:17 -06001394 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1395 """Helper function for microcode tests
Simon Glass3d274232017-11-12 21:52:27 -07001396
1397 We expect to see the following in the image, in order:
1398 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1399 correct place
1400 u-boot.dtb with the microcode removed
1401 the microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001402
1403 Args:
1404 dts: Device tree file to use for test
1405 ucode_second: True if the microsecond entry is second instead of
1406 third
Simon Glass3d274232017-11-12 21:52:27 -07001407 """
Simon Glass7057d022018-10-01 21:12:47 -06001408 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass6ba679c2018-07-06 10:27:17 -06001409 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1410 ucode_second=ucode_second)
Simon Glass303f62f2019-05-17 22:00:46 -06001411 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1412 b'ter somewhere in here', first)
Simon Glass3d274232017-11-12 21:52:27 -07001413
Simon Glass6ba679c2018-07-06 10:27:17 -06001414 def testPackUbootSplMicrocode(self):
1415 """Test that x86 microcode can be handled correctly in SPL"""
Simon Glass511f6582018-10-01 12:22:30 -06001416 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass6ba679c2018-07-06 10:27:17 -06001417
1418 def testPackUbootSplMicrocodeReorder(self):
1419 """Test that order doesn't matter for microcode entries
1420
1421 This is the same as testPackUbootSplMicrocode but when we process the
1422 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1423 entry, so we reply on binman to try later.
1424 """
Simon Glass511f6582018-10-01 12:22:30 -06001425 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass6ba679c2018-07-06 10:27:17 -06001426 ucode_second=True)
1427
Simon Glassa409c932017-11-12 21:52:28 -07001428 def testPackMrc(self):
1429 """Test that an image with an MRC binary can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001430 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassa409c932017-11-12 21:52:28 -07001431 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1432
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001433 def testSplDtb(self):
1434 """Test that an image with spl/u-boot-spl.dtb can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001435 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001436 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1437
Simon Glass0a6da312017-11-13 18:54:56 -07001438 def testSplNoDtb(self):
1439 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12001440 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001441 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass0a6da312017-11-13 18:54:56 -07001442 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1443
Simon Glass7098b7f2021-03-21 18:24:30 +13001444 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
1445 use_expanded=False):
Simon Glass31e04cb2021-03-18 20:24:56 +13001446 """Check the image contains the expected symbol values
1447
1448 Args:
1449 dts: Device tree file to use for test
1450 base_data: Data before and after 'u-boot' section
1451 u_boot_offset: Offset of 'u-boot' section in image
Simon Glass7098b7f2021-03-21 18:24:30 +13001452 entry_args: Dict of entry args to supply to binman
1453 key: arg name
1454 value: value of that arg
1455 use_expanded: True to use expanded entries where available, e.g.
1456 'u-boot-expanded' instead of 'u-boot'
Simon Glass31e04cb2021-03-18 20:24:56 +13001457 """
Simon Glass5d0c0262019-08-24 07:22:56 -06001458 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass4ca8e042017-11-13 18:55:01 -07001459 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1460 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001461 self.assertEqual(syms['_binman_sym_magic'].address, addr)
Simon Glass31e04cb2021-03-18 20:24:56 +13001462 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001463 addr + 4)
Simon Glass4ca8e042017-11-13 18:55:01 -07001464
Simon Glass7057d022018-10-01 21:12:47 -06001465 self._SetupSplElf('u_boot_binman_syms')
Simon Glass7098b7f2021-03-21 18:24:30 +13001466 data = self._DoReadFileDtb(dts, entry_args=entry_args,
1467 use_expanded=use_expanded)[0]
Simon Glass31e04cb2021-03-18 20:24:56 +13001468 # The image should contain the symbols from u_boot_binman_syms.c
1469 # Note that image_pos is adjusted by the base address of the image,
1470 # which is 0x10 in our test image
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001471 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE,
1472 0x00, u_boot_offset + len(U_BOOT_DATA),
Simon Glass31e04cb2021-03-18 20:24:56 +13001473 0x10 + u_boot_offset, 0x04)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001474 expected = (sym_values + base_data[24:] +
Simon Glass80025522022-01-29 14:14:04 -07001475 tools.get_bytes(0xff, 1) + U_BOOT_DATA + sym_values +
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001476 base_data[24:])
Simon Glass4ca8e042017-11-13 18:55:01 -07001477 self.assertEqual(expected, data)
1478
Simon Glass31e04cb2021-03-18 20:24:56 +13001479 def testSymbols(self):
1480 """Test binman can assign symbols embedded in U-Boot"""
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001481 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glass31e04cb2021-03-18 20:24:56 +13001482
1483 def testSymbolsNoDtb(self):
1484 """Test binman can assign symbols embedded in U-Boot SPL"""
Simon Glass3bbc9932021-03-21 18:24:29 +13001485 self.checkSymbols('196_symbols_nodtb.dts',
Simon Glass31e04cb2021-03-18 20:24:56 +13001486 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1487 0x38)
1488
Simon Glasse76a3e62018-06-01 09:38:11 -06001489 def testPackUnitAddress(self):
1490 """Test that we support multiple binaries with the same name"""
Simon Glass511f6582018-10-01 12:22:30 -06001491 data = self._DoReadFile('054_unit_address.dts')
Simon Glasse76a3e62018-06-01 09:38:11 -06001492 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1493
Simon Glassa91e1152018-06-01 09:38:16 -06001494 def testSections(self):
1495 """Basic test of sections"""
Simon Glass511f6582018-10-01 12:22:30 -06001496 data = self._DoReadFile('055_sections.dts')
Simon Glass80025522022-01-29 14:14:04 -07001497 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1498 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
1499 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glassa91e1152018-06-01 09:38:16 -06001500 self.assertEqual(expected, data)
Simon Glassac599912017-11-12 21:52:22 -07001501
Simon Glass30732662018-06-01 09:38:20 -06001502 def testMap(self):
1503 """Tests outputting a map of the images"""
Simon Glass511f6582018-10-01 12:22:30 -06001504 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001505 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700150600000000 00000000 00000028 image
Simon Glass7eca7922018-07-17 13:25:49 -0600150700000000 00000000 00000010 section@0
150800000000 00000000 00000004 u-boot
150900000010 00000010 00000010 section@1
151000000010 00000000 00000004 u-boot
151100000020 00000020 00000004 section@2
151200000020 00000000 00000004 u-boot
Simon Glass30732662018-06-01 09:38:20 -06001513''', map_data)
1514
Simon Glass3b78d532018-06-01 09:38:21 -06001515 def testNamePrefix(self):
1516 """Tests that name prefixes are used"""
Simon Glass511f6582018-10-01 12:22:30 -06001517 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001518 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700151900000000 00000000 00000028 image
Simon Glass7eca7922018-07-17 13:25:49 -0600152000000000 00000000 00000010 section@0
152100000000 00000000 00000004 ro-u-boot
152200000010 00000010 00000010 section@1
152300000010 00000000 00000004 rw-u-boot
Simon Glass3b78d532018-06-01 09:38:21 -06001524''', map_data)
1525
Simon Glass6ba679c2018-07-06 10:27:17 -06001526 def testUnknownContents(self):
1527 """Test that obtaining the contents works as expected"""
1528 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001529 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass39dd2152019-07-08 14:25:47 -06001530 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glassc585dd42020-04-17 18:09:03 -06001531 "processing of contents: remaining ["
1532 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass6ba679c2018-07-06 10:27:17 -06001533
Simon Glass2e1169f2018-07-06 10:27:19 -06001534 def testBadChangeSize(self):
1535 """Test that trying to change the size of an entry fails"""
Simon Glasse61b6f62019-07-08 14:25:37 -06001536 try:
1537 state.SetAllowEntryExpansion(False)
1538 with self.assertRaises(ValueError) as e:
1539 self._DoReadFile('059_change_size.dts', True)
Simon Glass8c702fb2019-07-20 12:23:57 -06001540 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glasse61b6f62019-07-08 14:25:37 -06001541 str(e.exception))
1542 finally:
1543 state.SetAllowEntryExpansion(True)
Simon Glass2e1169f2018-07-06 10:27:19 -06001544
Simon Glassa87014e2018-07-06 10:27:42 -06001545 def testUpdateFdt(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001546 """Test that we can update the device tree with offset/size info"""
Simon Glass511f6582018-10-01 12:22:30 -06001547 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glassa87014e2018-07-06 10:27:42 -06001548 update_dtb=True)
Simon Glass5463a6a2018-07-17 13:25:52 -06001549 dtb = fdt.Fdt(out_dtb_fname)
1550 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06001551 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glassa87014e2018-07-06 10:27:42 -06001552 self.assertEqual({
Simon Glass9dcc8612018-08-01 15:22:42 -06001553 'image-pos': 0,
Simon Glass3a9a2b82018-07-17 13:25:28 -06001554 'offset': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001555 '_testing:offset': 32,
Simon Glass8c702fb2019-07-20 12:23:57 -06001556 '_testing:size': 2,
Simon Glass9dcc8612018-08-01 15:22:42 -06001557 '_testing:image-pos': 32,
Simon Glasse8561af2018-08-01 15:22:37 -06001558 'section@0/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001559 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001560 'section@0/u-boot:image-pos': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001561 'section@0:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001562 'section@0:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001563 'section@0:image-pos': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001564
Simon Glasse8561af2018-08-01 15:22:37 -06001565 'section@1/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001566 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001567 'section@1/u-boot:image-pos': 16,
Simon Glasse8561af2018-08-01 15:22:37 -06001568 'section@1:offset': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001569 'section@1:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001570 'section@1:image-pos': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001571 'size': 40
1572 }, props)
1573
1574 def testUpdateFdtBad(self):
1575 """Test that we detect when ProcessFdt never completes"""
1576 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001577 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glassa87014e2018-07-06 10:27:42 -06001578 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glassc585dd42020-04-17 18:09:03 -06001579 '[<binman.etype._testing.Entry__testing',
1580 str(e.exception))
Simon Glass2e1169f2018-07-06 10:27:19 -06001581
Simon Glass91710b32018-07-17 13:25:32 -06001582 def testEntryArgs(self):
1583 """Test passing arguments to entries from the command line"""
1584 entry_args = {
1585 'test-str-arg': 'test1',
1586 'test-int-arg': '456',
1587 }
Simon Glass511f6582018-10-01 12:22:30 -06001588 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001589 self.assertIn('image', control.images)
1590 entry = control.images['image'].GetEntries()['_testing']
1591 self.assertEqual('test0', entry.test_str_fdt)
1592 self.assertEqual('test1', entry.test_str_arg)
1593 self.assertEqual(123, entry.test_int_fdt)
1594 self.assertEqual(456, entry.test_int_arg)
1595
1596 def testEntryArgsMissing(self):
1597 """Test missing arguments and properties"""
1598 entry_args = {
1599 'test-int-arg': '456',
1600 }
Simon Glass511f6582018-10-01 12:22:30 -06001601 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001602 entry = control.images['image'].GetEntries()['_testing']
1603 self.assertEqual('test0', entry.test_str_fdt)
1604 self.assertEqual(None, entry.test_str_arg)
1605 self.assertEqual(None, entry.test_int_fdt)
1606 self.assertEqual(456, entry.test_int_arg)
1607
1608 def testEntryArgsRequired(self):
1609 """Test missing arguments and properties"""
1610 entry_args = {
1611 'test-int-arg': '456',
1612 }
1613 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001614 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass21db0ff2020-09-01 05:13:54 -06001615 self.assertIn("Node '/binman/_testing': "
1616 'Missing required properties/entry args: test-str-arg, '
1617 'test-int-fdt, test-int-arg',
Simon Glass91710b32018-07-17 13:25:32 -06001618 str(e.exception))
1619
1620 def testEntryArgsInvalidFormat(self):
1621 """Test that an invalid entry-argument format is detected"""
Simon Glassf46732a2019-07-08 14:25:29 -06001622 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1623 '-ano-value']
Simon Glass91710b32018-07-17 13:25:32 -06001624 with self.assertRaises(ValueError) as e:
1625 self._DoBinman(*args)
1626 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1627
1628 def testEntryArgsInvalidInteger(self):
1629 """Test that an invalid entry-argument integer is detected"""
1630 entry_args = {
1631 'test-int-arg': 'abc',
1632 }
1633 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001634 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001635 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1636 "'test-int-arg' (value 'abc') to integer",
1637 str(e.exception))
1638
1639 def testEntryArgsInvalidDatatype(self):
1640 """Test that an invalid entry-argument datatype is detected
1641
1642 This test could be written in entry_test.py except that it needs
1643 access to control.entry_args, which seems more than that module should
1644 be able to see.
1645 """
1646 entry_args = {
1647 'test-bad-datatype-arg': '12',
1648 }
1649 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001650 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass91710b32018-07-17 13:25:32 -06001651 entry_args=entry_args)
1652 self.assertIn('GetArg() internal error: Unknown data type ',
1653 str(e.exception))
1654
Simon Glass2ca52032018-07-17 13:25:33 -06001655 def testText(self):
1656 """Test for a text entry type"""
1657 entry_args = {
1658 'test-id': TEXT_DATA,
1659 'test-id2': TEXT_DATA2,
1660 'test-id3': TEXT_DATA3,
1661 }
Simon Glass511f6582018-10-01 12:22:30 -06001662 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glass2ca52032018-07-17 13:25:33 -06001663 entry_args=entry_args)
Simon Glass80025522022-01-29 14:14:04 -07001664 expected = (tools.to_bytes(TEXT_DATA) +
1665 tools.get_bytes(0, 8 - len(TEXT_DATA)) +
1666 tools.to_bytes(TEXT_DATA2) + tools.to_bytes(TEXT_DATA3) +
Simon Glass47f6a622019-07-08 13:18:40 -06001667 b'some text' + b'more text')
Simon Glass2ca52032018-07-17 13:25:33 -06001668 self.assertEqual(expected, data)
1669
Simon Glass969616c2018-07-17 13:25:36 -06001670 def testEntryDocs(self):
1671 """Test for creation of entry documentation"""
1672 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001673 control.WriteEntryDocs(control.GetEntryModules())
Simon Glass969616c2018-07-17 13:25:36 -06001674 self.assertTrue(len(stdout.getvalue()) > 0)
1675
1676 def testEntryDocsMissing(self):
1677 """Test handling of missing entry documentation"""
1678 with self.assertRaises(ValueError) as e:
1679 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001680 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glass969616c2018-07-17 13:25:36 -06001681 self.assertIn('Documentation is missing for modules: u_boot',
1682 str(e.exception))
1683
Simon Glass704784b2018-07-17 13:25:38 -06001684 def testFmap(self):
1685 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06001686 data = self._DoReadFile('067_fmap.dts')
Simon Glass704784b2018-07-17 13:25:38 -06001687 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass80025522022-01-29 14:14:04 -07001688 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1689 U_BOOT_DATA + tools.get_bytes(ord('a'), 12))
Simon Glass704784b2018-07-17 13:25:38 -06001690 self.assertEqual(expected, data[:32])
Simon Glass303f62f2019-05-17 22:00:46 -06001691 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass704784b2018-07-17 13:25:38 -06001692 self.assertEqual(1, fhdr.ver_major)
1693 self.assertEqual(0, fhdr.ver_minor)
1694 self.assertEqual(0, fhdr.base)
Simon Glassb1d414c2021-04-03 11:05:10 +13001695 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 5
Simon Glass82059c22021-04-03 11:05:09 +13001696 self.assertEqual(16 + 16 + expect_size, fhdr.image_size)
Simon Glass303f62f2019-05-17 22:00:46 -06001697 self.assertEqual(b'FMAP', fhdr.name)
Simon Glassb1d414c2021-04-03 11:05:10 +13001698 self.assertEqual(5, fhdr.nareas)
Simon Glass82059c22021-04-03 11:05:09 +13001699 fiter = iter(fentries)
Simon Glass704784b2018-07-17 13:25:38 -06001700
Simon Glass82059c22021-04-03 11:05:09 +13001701 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001702 self.assertEqual(b'SECTION0', fentry.name)
1703 self.assertEqual(0, fentry.offset)
1704 self.assertEqual(16, fentry.size)
Simon Glasscda991e2023-02-12 17:11:15 -07001705 self.assertEqual(fmap_util.FMAP_AREA_PRESERVE, fentry.flags)
Simon Glassb1d414c2021-04-03 11:05:10 +13001706
1707 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001708 self.assertEqual(b'RO_U_BOOT', fentry.name)
1709 self.assertEqual(0, fentry.offset)
1710 self.assertEqual(4, fentry.size)
1711 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001712
Simon Glass82059c22021-04-03 11:05:09 +13001713 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001714 self.assertEqual(b'SECTION1', fentry.name)
1715 self.assertEqual(16, fentry.offset)
1716 self.assertEqual(16, fentry.size)
1717 self.assertEqual(0, fentry.flags)
1718
1719 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001720 self.assertEqual(b'RW_U_BOOT', fentry.name)
1721 self.assertEqual(16, fentry.offset)
1722 self.assertEqual(4, fentry.size)
1723 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001724
Simon Glass82059c22021-04-03 11:05:09 +13001725 fentry = next(fiter)
1726 self.assertEqual(b'FMAP', fentry.name)
1727 self.assertEqual(32, fentry.offset)
1728 self.assertEqual(expect_size, fentry.size)
1729 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001730
Simon Glassdb168d42018-07-17 13:25:39 -06001731 def testBlobNamedByArg(self):
1732 """Test we can add a blob with the filename coming from an entry arg"""
1733 entry_args = {
1734 'cros-ec-rw-path': 'ecrw.bin',
1735 }
Simon Glass21db0ff2020-09-01 05:13:54 -06001736 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassdb168d42018-07-17 13:25:39 -06001737
Simon Glass53f53992018-07-17 13:25:40 -06001738 def testFill(self):
1739 """Test for an fill entry type"""
Simon Glass511f6582018-10-01 12:22:30 -06001740 data = self._DoReadFile('069_fill.dts')
Simon Glass80025522022-01-29 14:14:04 -07001741 expected = tools.get_bytes(0xff, 8) + tools.get_bytes(0, 8)
Simon Glass53f53992018-07-17 13:25:40 -06001742 self.assertEqual(expected, data)
1743
1744 def testFillNoSize(self):
1745 """Test for an fill entry type with no size"""
1746 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001747 self._DoReadFile('070_fill_no_size.dts')
Simon Glass0cf5bce2022-08-13 11:40:44 -06001748 self.assertIn("'fill' entry is missing properties: size",
Simon Glass53f53992018-07-17 13:25:40 -06001749 str(e.exception))
1750
Simon Glassc1ae83c2018-07-17 13:25:44 -06001751 def _HandleGbbCommand(self, pipe_list):
1752 """Fake calls to the futility utility"""
Simon Glass9a1c7262023-02-22 12:14:49 -07001753 if 'futility' in pipe_list[0][0]:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001754 fname = pipe_list[0][-1]
1755 # Append our GBB data to the file, which will happen every time the
1756 # futility command is called.
Simon Glass33486662019-05-14 15:53:42 -06001757 with open(fname, 'ab') as fd:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001758 fd.write(GBB_DATA)
1759 return command.CommandResult()
1760
1761 def testGbb(self):
1762 """Test for the Chromium OS Google Binary Block"""
1763 command.test_result = self._HandleGbbCommand
1764 entry_args = {
1765 'keydir': 'devkeys',
1766 'bmpblk': 'bmpblk.bin',
1767 }
Simon Glass511f6582018-10-01 12:22:30 -06001768 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glassc1ae83c2018-07-17 13:25:44 -06001769
1770 # Since futility
Simon Glass80025522022-01-29 14:14:04 -07001771 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
1772 tools.get_bytes(0, 0x2180 - 16))
Simon Glassc1ae83c2018-07-17 13:25:44 -06001773 self.assertEqual(expected, data)
1774
1775 def testGbbTooSmall(self):
1776 """Test for the Chromium OS Google Binary Block being large enough"""
1777 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001778 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001779 self.assertIn("Node '/binman/gbb': GBB is too small",
1780 str(e.exception))
1781
1782 def testGbbNoSize(self):
1783 """Test for the Chromium OS Google Binary Block having a size"""
1784 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001785 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001786 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1787 str(e.exception))
1788
Simon Glass66152ce2022-01-09 20:14:09 -07001789 def testGbbMissing(self):
1790 """Test that binman still produces an image if futility is missing"""
1791 entry_args = {
1792 'keydir': 'devkeys',
1793 }
1794 with test_util.capture_sys_output() as (_, stderr):
1795 self._DoTestFile('071_gbb.dts', force_missing_bintools='futility',
1796 entry_args=entry_args)
1797 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07001798 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass66152ce2022-01-09 20:14:09 -07001799
Simon Glass5c350162018-07-17 13:25:47 -06001800 def _HandleVblockCommand(self, pipe_list):
Simon Glass220c6222021-01-06 21:35:17 -07001801 """Fake calls to the futility utility
1802
1803 The expected pipe is:
1804
1805 [('futility', 'vbutil_firmware', '--vblock',
1806 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1807 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1808 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1809 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1810
1811 This writes to the output file (here, 'vblock.vblock'). If
1812 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1813 of the input data (here, 'input.vblock').
1814 """
Simon Glass9a1c7262023-02-22 12:14:49 -07001815 if 'futility' in pipe_list[0][0]:
Simon Glass5c350162018-07-17 13:25:47 -06001816 fname = pipe_list[0][3]
Simon Glass639505b2018-09-14 04:57:11 -06001817 with open(fname, 'wb') as fd:
Simon Glass220c6222021-01-06 21:35:17 -07001818 if self._hash_data:
1819 infile = pipe_list[0][11]
1820 m = hashlib.sha256()
Simon Glass80025522022-01-29 14:14:04 -07001821 data = tools.read_file(infile)
Simon Glass220c6222021-01-06 21:35:17 -07001822 m.update(data)
1823 fd.write(m.digest())
1824 else:
1825 fd.write(VBLOCK_DATA)
1826
Simon Glass5c350162018-07-17 13:25:47 -06001827 return command.CommandResult()
1828
1829 def testVblock(self):
1830 """Test for the Chromium OS Verified Boot Block"""
Simon Glass220c6222021-01-06 21:35:17 -07001831 self._hash_data = False
Simon Glass5c350162018-07-17 13:25:47 -06001832 command.test_result = self._HandleVblockCommand
1833 entry_args = {
1834 'keydir': 'devkeys',
1835 }
Simon Glass511f6582018-10-01 12:22:30 -06001836 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass5c350162018-07-17 13:25:47 -06001837 entry_args=entry_args)
1838 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1839 self.assertEqual(expected, data)
1840
1841 def testVblockNoContent(self):
1842 """Test we detect a vblock which has no content to sign"""
1843 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001844 self._DoReadFile('075_vblock_no_content.dts')
Simon Glasse1915782021-03-21 18:24:31 +13001845 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
Simon Glass5c350162018-07-17 13:25:47 -06001846 'property', str(e.exception))
1847
1848 def testVblockBadPhandle(self):
1849 """Test that we detect a vblock with an invalid phandle in contents"""
1850 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001851 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001852 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1853 '1000', str(e.exception))
1854
1855 def testVblockBadEntry(self):
1856 """Test that we detect an entry that points to a non-entry"""
1857 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001858 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001859 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1860 "'other'", str(e.exception))
1861
Simon Glass220c6222021-01-06 21:35:17 -07001862 def testVblockContent(self):
1863 """Test that the vblock signs the right data"""
1864 self._hash_data = True
1865 command.test_result = self._HandleVblockCommand
1866 entry_args = {
1867 'keydir': 'devkeys',
1868 }
1869 data = self._DoReadFileDtb(
1870 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1871 entry_args=entry_args)[0]
1872 hashlen = 32 # SHA256 hash is 32 bytes
1873 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1874 hashval = data[-hashlen:]
1875 dtb = data[len(U_BOOT_DATA):-hashlen]
1876
1877 expected_data = U_BOOT_DATA + dtb
1878
1879 # The hashval should be a hash of the dtb
1880 m = hashlib.sha256()
1881 m.update(expected_data)
1882 expected_hashval = m.digest()
1883 self.assertEqual(expected_hashval, hashval)
1884
Simon Glass66152ce2022-01-09 20:14:09 -07001885 def testVblockMissing(self):
1886 """Test that binman still produces an image if futility is missing"""
1887 entry_args = {
1888 'keydir': 'devkeys',
1889 }
1890 with test_util.capture_sys_output() as (_, stderr):
1891 self._DoTestFile('074_vblock.dts',
1892 force_missing_bintools='futility',
1893 entry_args=entry_args)
1894 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07001895 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass66152ce2022-01-09 20:14:09 -07001896
Simon Glass8425a1f2018-07-17 13:25:48 -06001897 def testTpl(self):
Simon Glass3eb5b202019-08-24 07:23:00 -06001898 """Test that an image with TPL and its device tree can be created"""
Simon Glass8425a1f2018-07-17 13:25:48 -06001899 # ELF file with a '__bss_size' symbol
Simon Glass3eb5b202019-08-24 07:23:00 -06001900 self._SetupTplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001901 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glass8425a1f2018-07-17 13:25:48 -06001902 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1903
Simon Glass24b97442018-07-17 13:25:51 -06001904 def testUsesPos(self):
1905 """Test that the 'pos' property cannot be used anymore"""
1906 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001907 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass24b97442018-07-17 13:25:51 -06001908 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1909 "'pos'", str(e.exception))
1910
Simon Glass274bf092018-09-14 04:57:08 -06001911 def testFillZero(self):
1912 """Test for an fill entry type with a size of 0"""
Simon Glass511f6582018-10-01 12:22:30 -06001913 data = self._DoReadFile('080_fill_empty.dts')
Simon Glass80025522022-01-29 14:14:04 -07001914 self.assertEqual(tools.get_bytes(0, 16), data)
Simon Glass274bf092018-09-14 04:57:08 -06001915
Simon Glass267de432018-09-14 04:57:09 -06001916 def testTextMissing(self):
1917 """Test for a text entry type where there is no text"""
1918 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001919 self._DoReadFileDtb('066_text.dts',)
Simon Glass267de432018-09-14 04:57:09 -06001920 self.assertIn("Node '/binman/text': No value provided for text label "
1921 "'test-id'", str(e.exception))
1922
Simon Glassed40e962018-09-14 04:57:10 -06001923 def testPackStart16Tpl(self):
1924 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001925 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glassed40e962018-09-14 04:57:10 -06001926 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1927
Simon Glass3b376c32018-09-14 04:57:12 -06001928 def testSelectImage(self):
1929 """Test that we can select which images to build"""
Simon Glassb4595d82019-04-25 21:58:34 -06001930 expected = 'Skipping images: image1'
1931
1932 # We should only get the expected message in verbose mode
Simon Glass8a50b4a2019-07-08 13:18:48 -06001933 for verbosity in (0, 2):
Simon Glassb4595d82019-04-25 21:58:34 -06001934 with test_util.capture_sys_output() as (stdout, stderr):
1935 retcode = self._DoTestFile('006_dual_image.dts',
1936 verbosity=verbosity,
1937 images=['image2'])
1938 self.assertEqual(0, retcode)
1939 if verbosity:
1940 self.assertIn(expected, stdout.getvalue())
1941 else:
1942 self.assertNotIn(expected, stdout.getvalue())
Simon Glass3b376c32018-09-14 04:57:12 -06001943
Simon Glass80025522022-01-29 14:14:04 -07001944 self.assertFalse(os.path.exists(tools.get_output_filename('image1.bin')))
1945 self.assertTrue(os.path.exists(tools.get_output_filename('image2.bin')))
Simon Glassb3d6fc72019-07-20 12:24:10 -06001946 self._CleanupOutputDir()
Simon Glass3b376c32018-09-14 04:57:12 -06001947
Simon Glasse219aa42018-09-14 04:57:24 -06001948 def testUpdateFdtAll(self):
1949 """Test that all device trees are updated with offset/size info"""
Simon Glass5b4bce32019-07-08 14:25:26 -06001950 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glasse219aa42018-09-14 04:57:24 -06001951
1952 base_expected = {
Simon Glasse219aa42018-09-14 04:57:24 -06001953 'offset': 0,
Simon Glass56d05412022-02-28 07:16:54 -07001954 'image-pos': 0,
1955 'size': 2320,
Simon Glasse219aa42018-09-14 04:57:24 -06001956 'section:offset': 0,
Simon Glass56d05412022-02-28 07:16:54 -07001957 'section:image-pos': 0,
1958 'section:size': 565,
1959 'section/u-boot-dtb:offset': 0,
1960 'section/u-boot-dtb:image-pos': 0,
1961 'section/u-boot-dtb:size': 565,
1962 'u-boot-spl-dtb:offset': 565,
1963 'u-boot-spl-dtb:image-pos': 565,
1964 'u-boot-spl-dtb:size': 585,
1965 'u-boot-tpl-dtb:offset': 1150,
1966 'u-boot-tpl-dtb:image-pos': 1150,
1967 'u-boot-tpl-dtb:size': 585,
1968 'u-boot-vpl-dtb:image-pos': 1735,
1969 'u-boot-vpl-dtb:offset': 1735,
1970 'u-boot-vpl-dtb:size': 585,
Simon Glasse219aa42018-09-14 04:57:24 -06001971 }
1972
1973 # We expect three device-tree files in the output, one after the other.
1974 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1975 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1976 # main U-Boot tree. All three should have the same postions and offset.
1977 start = 0
Simon Glass56d05412022-02-28 07:16:54 -07001978 self.maxDiff = None
1979 for item in ['', 'spl', 'tpl', 'vpl']:
Simon Glasse219aa42018-09-14 04:57:24 -06001980 dtb = fdt.Fdt.FromData(data[start:])
1981 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06001982 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
Simon Glass56d05412022-02-28 07:16:54 -07001983 ['spl', 'tpl', 'vpl'])
Simon Glasse219aa42018-09-14 04:57:24 -06001984 expected = dict(base_expected)
1985 if item:
1986 expected[item] = 0
1987 self.assertEqual(expected, props)
1988 start += dtb._fdt_obj.totalsize()
1989
1990 def testUpdateFdtOutput(self):
1991 """Test that output DTB files are updated"""
1992 try:
Simon Glass511f6582018-10-01 12:22:30 -06001993 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glasse219aa42018-09-14 04:57:24 -06001994 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1995
1996 # Unfortunately, compiling a source file always results in a file
1997 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass511f6582018-10-01 12:22:30 -06001998 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glasse219aa42018-09-14 04:57:24 -06001999 # binman as a file called u-boot.dtb. To fix this, copy the file
2000 # over to the expected place.
Simon Glasse219aa42018-09-14 04:57:24 -06002001 start = 0
2002 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
Simon Glass56d05412022-02-28 07:16:54 -07002003 'tpl/u-boot-tpl.dtb.out', 'vpl/u-boot-vpl.dtb.out']:
Simon Glasse219aa42018-09-14 04:57:24 -06002004 dtb = fdt.Fdt.FromData(data[start:])
2005 size = dtb._fdt_obj.totalsize()
Simon Glass80025522022-01-29 14:14:04 -07002006 pathname = tools.get_output_filename(os.path.split(fname)[1])
2007 outdata = tools.read_file(pathname)
Simon Glasse219aa42018-09-14 04:57:24 -06002008 name = os.path.split(fname)[0]
2009
2010 if name:
Simon Glass56d05412022-02-28 07:16:54 -07002011 orig_indata = self._GetDtbContentsForSpls(dtb_data, name)
Simon Glasse219aa42018-09-14 04:57:24 -06002012 else:
2013 orig_indata = dtb_data
2014 self.assertNotEqual(outdata, orig_indata,
2015 "Expected output file '%s' be updated" % pathname)
2016 self.assertEqual(outdata, data[start:start + size],
2017 "Expected output file '%s' to match output image" %
2018 pathname)
2019 start += size
2020 finally:
2021 self._ResetDtbs()
2022
Simon Glass7ba33592018-09-14 04:57:26 -06002023 def _decompress(self, data):
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02002024 bintool = self.comp_bintools['lz4']
2025 return bintool.decompress(data)
Simon Glass7ba33592018-09-14 04:57:26 -06002026
2027 def testCompress(self):
2028 """Test compression of blobs"""
Simon Glass1de34482019-07-08 13:18:53 -06002029 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06002030 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass7ba33592018-09-14 04:57:26 -06002031 use_real_dtb=True, update_dtb=True)
2032 dtb = fdt.Fdt(out_dtb_fname)
2033 dtb.Scan()
2034 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2035 orig = self._decompress(data)
2036 self.assertEquals(COMPRESS_DATA, orig)
Simon Glass789b34402020-10-26 17:40:15 -06002037
2038 # Do a sanity check on various fields
2039 image = control.images['image']
2040 entries = image.GetEntries()
2041 self.assertEqual(1, len(entries))
2042
2043 entry = entries['blob']
2044 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
2045 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
2046 orig = self._decompress(entry.data)
2047 self.assertEqual(orig, entry.uncomp_data)
2048
Simon Glass72eeff12020-10-26 17:40:16 -06002049 self.assertEqual(image.data, entry.data)
2050
Simon Glass7ba33592018-09-14 04:57:26 -06002051 expected = {
2052 'blob:uncomp-size': len(COMPRESS_DATA),
2053 'blob:size': len(data),
2054 'size': len(data),
2055 }
2056 self.assertEqual(expected, props)
2057
Simon Glassac6328c2018-09-14 04:57:28 -06002058 def testFiles(self):
2059 """Test bringing in multiple files"""
Simon Glass511f6582018-10-01 12:22:30 -06002060 data = self._DoReadFile('084_files.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002061 self.assertEqual(FILES_DATA, data)
2062
2063 def testFilesCompress(self):
2064 """Test bringing in multiple files and compressing them"""
Simon Glass1de34482019-07-08 13:18:53 -06002065 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06002066 data = self._DoReadFile('085_files_compress.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002067
2068 image = control.images['image']
2069 entries = image.GetEntries()
2070 files = entries['files']
Simon Glass39dd2152019-07-08 14:25:47 -06002071 entries = files._entries
Simon Glassac6328c2018-09-14 04:57:28 -06002072
Simon Glass303f62f2019-05-17 22:00:46 -06002073 orig = b''
Simon Glassac6328c2018-09-14 04:57:28 -06002074 for i in range(1, 3):
2075 key = '%d.dat' % i
2076 start = entries[key].image_pos
2077 len = entries[key].size
2078 chunk = data[start:start + len]
2079 orig += self._decompress(chunk)
2080
2081 self.assertEqual(FILES_DATA, orig)
2082
2083 def testFilesMissing(self):
2084 """Test missing files"""
2085 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002086 data = self._DoReadFile('086_files_none.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002087 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
2088 'no files', str(e.exception))
2089
2090 def testFilesNoPattern(self):
2091 """Test missing files"""
2092 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002093 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002094 self.assertIn("Node '/binman/files': Missing 'pattern' property",
2095 str(e.exception))
2096
Simon Glassdd156a42022-03-05 20:18:59 -07002097 def testExtendSize(self):
2098 """Test an extending entry"""
2099 data, _, map_data, _ = self._DoReadFileDtb('088_extend_size.dts',
Simon Glassfa79a812018-09-14 04:57:29 -06002100 map=True)
Simon Glass80025522022-01-29 14:14:04 -07002101 expect = (tools.get_bytes(ord('a'), 8) + U_BOOT_DATA +
2102 MRC_DATA + tools.get_bytes(ord('b'), 1) + U_BOOT_DATA +
2103 tools.get_bytes(ord('c'), 8) + U_BOOT_DATA +
2104 tools.get_bytes(ord('d'), 8))
Simon Glassfa79a812018-09-14 04:57:29 -06002105 self.assertEqual(expect, data)
2106 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700210700000000 00000000 00000028 image
Simon Glassfa79a812018-09-14 04:57:29 -0600210800000000 00000000 00000008 fill
210900000008 00000008 00000004 u-boot
21100000000c 0000000c 00000004 section
21110000000c 00000000 00000003 intel-mrc
211200000010 00000010 00000004 u-boot2
211300000014 00000014 0000000c section2
211400000014 00000000 00000008 fill
21150000001c 00000008 00000004 u-boot
211600000020 00000020 00000008 fill2
2117''', map_data)
2118
Simon Glassdd156a42022-03-05 20:18:59 -07002119 def testExtendSizeBad(self):
2120 """Test an extending entry which fails to provide contents"""
Simon Glasscd817d52018-09-14 04:57:36 -06002121 with test_util.capture_sys_output() as (stdout, stderr):
2122 with self.assertRaises(ValueError) as e:
Simon Glassdd156a42022-03-05 20:18:59 -07002123 self._DoReadFileDtb('089_extend_size_bad.dts', map=True)
Simon Glassfa79a812018-09-14 04:57:29 -06002124 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
2125 'expanding entry', str(e.exception))
2126
Simon Glassae7cf032018-09-14 04:57:31 -06002127 def testHash(self):
2128 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002129 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002130 use_real_dtb=True, update_dtb=True)
2131 dtb = fdt.Fdt(out_dtb_fname)
2132 dtb.Scan()
2133 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
2134 m = hashlib.sha256()
2135 m.update(U_BOOT_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002136 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002137
2138 def testHashNoAlgo(self):
2139 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002140 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glassae7cf032018-09-14 04:57:31 -06002141 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2142 'hash node', str(e.exception))
2143
2144 def testHashBadAlgo(self):
2145 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002146 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glass64af7c22022-02-08 10:59:44 -07002147 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm 'invalid'",
Simon Glassae7cf032018-09-14 04:57:31 -06002148 str(e.exception))
2149
2150 def testHashSection(self):
2151 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002152 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002153 use_real_dtb=True, update_dtb=True)
2154 dtb = fdt.Fdt(out_dtb_fname)
2155 dtb.Scan()
2156 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2157 m = hashlib.sha256()
2158 m.update(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07002159 m.update(tools.get_bytes(ord('a'), 16))
Simon Glass303f62f2019-05-17 22:00:46 -06002160 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002161
Simon Glass3fb4f422018-09-14 04:57:32 -06002162 def testPackUBootTplMicrocode(self):
2163 """Test that x86 microcode can be handled correctly in TPL
2164
2165 We expect to see the following in the image, in order:
2166 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2167 place
2168 u-boot-tpl.dtb with the microcode removed
2169 the microcode
2170 """
Simon Glass3eb5b202019-08-24 07:23:00 -06002171 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass511f6582018-10-01 12:22:30 -06002172 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glass3fb4f422018-09-14 04:57:32 -06002173 U_BOOT_TPL_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002174 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2175 b'ter somewhere in here', first)
Simon Glass3fb4f422018-09-14 04:57:32 -06002176
Simon Glassc64aea52018-09-14 04:57:34 -06002177 def testFmapX86(self):
2178 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002179 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassc64aea52018-09-14 04:57:34 -06002180 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass80025522022-01-29 14:14:04 -07002181 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('a'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002182 self.assertEqual(expected, data[:32])
2183 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2184
2185 self.assertEqual(0x100, fhdr.image_size)
2186
2187 self.assertEqual(0, fentries[0].offset)
2188 self.assertEqual(4, fentries[0].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002189 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002190
2191 self.assertEqual(4, fentries[1].offset)
2192 self.assertEqual(3, fentries[1].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002193 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002194
2195 self.assertEqual(32, fentries[2].offset)
2196 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2197 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002198 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002199
2200 def testFmapX86Section(self):
2201 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002202 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glass80025522022-01-29 14:14:04 -07002203 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('b'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002204 self.assertEqual(expected, data[:32])
2205 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2206
Simon Glassb1d414c2021-04-03 11:05:10 +13002207 self.assertEqual(0x180, fhdr.image_size)
2208 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
Simon Glass82059c22021-04-03 11:05:09 +13002209 fiter = iter(fentries)
Simon Glassc64aea52018-09-14 04:57:34 -06002210
Simon Glass82059c22021-04-03 11:05:09 +13002211 fentry = next(fiter)
2212 self.assertEqual(b'U_BOOT', fentry.name)
2213 self.assertEqual(0, fentry.offset)
2214 self.assertEqual(4, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002215
Simon Glass82059c22021-04-03 11:05:09 +13002216 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13002217 self.assertEqual(b'SECTION', fentry.name)
2218 self.assertEqual(4, fentry.offset)
2219 self.assertEqual(0x20 + expect_size, fentry.size)
2220
2221 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13002222 self.assertEqual(b'INTEL_MRC', fentry.name)
2223 self.assertEqual(4, fentry.offset)
2224 self.assertEqual(3, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002225
Simon Glass82059c22021-04-03 11:05:09 +13002226 fentry = next(fiter)
2227 self.assertEqual(b'FMAP', fentry.name)
2228 self.assertEqual(36, fentry.offset)
2229 self.assertEqual(expect_size, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002230
Simon Glassb1714232018-09-14 04:57:35 -06002231 def testElf(self):
2232 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002233 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002234 self._SetupTplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002235 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002236 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002237 data = self._DoReadFile('096_elf.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002238
Simon Glass0d673792019-07-08 13:18:25 -06002239 def testElfStrip(self):
Simon Glassb1714232018-09-14 04:57:35 -06002240 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002241 self._SetupSplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002242 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002243 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002244 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002245
Simon Glasscd817d52018-09-14 04:57:36 -06002246 def testPackOverlapMap(self):
2247 """Test that overlapping regions are detected"""
2248 with test_util.capture_sys_output() as (stdout, stderr):
2249 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002250 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glass80025522022-01-29 14:14:04 -07002251 map_fname = tools.get_output_filename('image.map')
Simon Glasscd817d52018-09-14 04:57:36 -06002252 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2253 stdout.getvalue())
2254
2255 # We should not get an inmage, but there should be a map file
Simon Glass80025522022-01-29 14:14:04 -07002256 self.assertFalse(os.path.exists(tools.get_output_filename('image.bin')))
Simon Glasscd817d52018-09-14 04:57:36 -06002257 self.assertTrue(os.path.exists(map_fname))
Simon Glass80025522022-01-29 14:14:04 -07002258 map_data = tools.read_file(map_fname, binary=False)
Simon Glasscd817d52018-09-14 04:57:36 -06002259 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -07002260<none> 00000000 00000008 image
Simon Glasscd817d52018-09-14 04:57:36 -06002261<none> 00000000 00000004 u-boot
2262<none> 00000003 00000004 u-boot-align
2263''', map_data)
2264
Simon Glass0d673792019-07-08 13:18:25 -06002265 def testPackRefCode(self):
Simon Glass41902e42018-10-01 12:22:31 -06002266 """Test that an image with an Intel Reference code binary works"""
2267 data = self._DoReadFile('100_intel_refcode.dts')
2268 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2269
Simon Glasseb023b32019-04-25 21:58:39 -06002270 def testSectionOffset(self):
2271 """Tests use of a section with an offset"""
2272 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2273 map=True)
2274 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700227500000000 00000000 00000038 image
Simon Glasseb023b32019-04-25 21:58:39 -0600227600000004 00000004 00000010 section@0
227700000004 00000000 00000004 u-boot
227800000018 00000018 00000010 section@1
227900000018 00000000 00000004 u-boot
22800000002c 0000002c 00000004 section@2
22810000002c 00000000 00000004 u-boot
2282''', map_data)
2283 self.assertEqual(data,
Simon Glass80025522022-01-29 14:14:04 -07002284 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2285 tools.get_bytes(0x21, 12) +
2286 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2287 tools.get_bytes(0x61, 12) +
2288 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2289 tools.get_bytes(0x26, 8))
Simon Glasseb023b32019-04-25 21:58:39 -06002290
Simon Glass1de34482019-07-08 13:18:53 -06002291 def testCbfsRaw(self):
2292 """Test base handling of a Coreboot Filesystem (CBFS)
2293
2294 The exact contents of the CBFS is verified by similar tests in
2295 cbfs_util_test.py. The tests here merely check that the files added to
2296 the CBFS can be found in the final image.
2297 """
2298 data = self._DoReadFile('102_cbfs_raw.dts')
2299 size = 0xb0
2300
2301 cbfs = cbfs_util.CbfsReader(data)
2302 self.assertEqual(size, cbfs.rom_size)
2303
2304 self.assertIn('u-boot-dtb', cbfs.files)
2305 cfile = cbfs.files['u-boot-dtb']
2306 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2307
2308 def testCbfsArch(self):
2309 """Test on non-x86 architecture"""
2310 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2311 size = 0x100
2312
2313 cbfs = cbfs_util.CbfsReader(data)
2314 self.assertEqual(size, cbfs.rom_size)
2315
2316 self.assertIn('u-boot-dtb', cbfs.files)
2317 cfile = cbfs.files['u-boot-dtb']
2318 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2319
2320 def testCbfsStage(self):
2321 """Tests handling of a Coreboot Filesystem (CBFS)"""
2322 if not elf.ELF_TOOLS:
2323 self.skipTest('Python elftools not available')
2324 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2325 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2326 size = 0xb0
2327
2328 data = self._DoReadFile('104_cbfs_stage.dts')
2329 cbfs = cbfs_util.CbfsReader(data)
2330 self.assertEqual(size, cbfs.rom_size)
2331
2332 self.assertIn('u-boot', cbfs.files)
2333 cfile = cbfs.files['u-boot']
2334 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2335
2336 def testCbfsRawCompress(self):
2337 """Test handling of compressing raw files"""
2338 self._CheckLz4()
2339 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2340 size = 0x140
2341
2342 cbfs = cbfs_util.CbfsReader(data)
2343 self.assertIn('u-boot', cbfs.files)
2344 cfile = cbfs.files['u-boot']
2345 self.assertEqual(COMPRESS_DATA, cfile.data)
2346
2347 def testCbfsBadArch(self):
2348 """Test handling of a bad architecture"""
2349 with self.assertRaises(ValueError) as e:
2350 self._DoReadFile('106_cbfs_bad_arch.dts')
2351 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2352
2353 def testCbfsNoSize(self):
2354 """Test handling of a missing size property"""
2355 with self.assertRaises(ValueError) as e:
2356 self._DoReadFile('107_cbfs_no_size.dts')
2357 self.assertIn('entry must have a size property', str(e.exception))
2358
Simon Glass3e28f4f2021-11-23 11:03:54 -07002359 def testCbfsNoContents(self):
Simon Glass1de34482019-07-08 13:18:53 -06002360 """Test handling of a CBFS entry which does not provide contentsy"""
2361 with self.assertRaises(ValueError) as e:
2362 self._DoReadFile('108_cbfs_no_contents.dts')
2363 self.assertIn('Could not complete processing of contents',
2364 str(e.exception))
2365
2366 def testCbfsBadCompress(self):
2367 """Test handling of a bad architecture"""
2368 with self.assertRaises(ValueError) as e:
2369 self._DoReadFile('109_cbfs_bad_compress.dts')
2370 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2371 str(e.exception))
2372
2373 def testCbfsNamedEntries(self):
2374 """Test handling of named entries"""
2375 data = self._DoReadFile('110_cbfs_name.dts')
2376
2377 cbfs = cbfs_util.CbfsReader(data)
2378 self.assertIn('FRED', cbfs.files)
2379 cfile1 = cbfs.files['FRED']
2380 self.assertEqual(U_BOOT_DATA, cfile1.data)
2381
2382 self.assertIn('hello', cbfs.files)
2383 cfile2 = cbfs.files['hello']
2384 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2385
Simon Glass759af872019-07-08 13:18:54 -06002386 def _SetupIfwi(self, fname):
2387 """Set up to run an IFWI test
2388
2389 Args:
2390 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2391 """
2392 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002393 self._SetupTplElf()
Simon Glass759af872019-07-08 13:18:54 -06002394
2395 # Intel Integrated Firmware Image (IFWI) file
2396 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2397 data = fd.read()
2398 TestFunctional._MakeInputFile(fname,data)
2399
2400 def _CheckIfwi(self, data):
2401 """Check that an image with an IFWI contains the correct output
2402
2403 Args:
2404 data: Conents of output file
2405 """
Simon Glass80025522022-01-29 14:14:04 -07002406 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glass759af872019-07-08 13:18:54 -06002407 if data[:0x1000] != expected_desc:
2408 self.fail('Expected descriptor binary at start of image')
2409
2410 # We expect to find the TPL wil in subpart IBBP entry IBBL
Simon Glass80025522022-01-29 14:14:04 -07002411 image_fname = tools.get_output_filename('image.bin')
2412 tpl_fname = tools.get_output_filename('tpl.out')
Simon Glass57c7a482022-01-09 20:14:01 -07002413 ifwitool = bintool.Bintool.create('ifwitool')
2414 ifwitool.extract(image_fname, 'IBBP', 'IBBL', tpl_fname)
Simon Glass759af872019-07-08 13:18:54 -06002415
Simon Glass80025522022-01-29 14:14:04 -07002416 tpl_data = tools.read_file(tpl_fname)
Simon Glassf55bd692019-08-24 07:22:51 -06002417 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glass759af872019-07-08 13:18:54 -06002418
2419 def testPackX86RomIfwi(self):
2420 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2421 self._SetupIfwi('fitimage.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002422 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glass759af872019-07-08 13:18:54 -06002423 self._CheckIfwi(data)
2424
2425 def testPackX86RomIfwiNoDesc(self):
2426 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2427 self._SetupIfwi('ifwi.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002428 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glass759af872019-07-08 13:18:54 -06002429 self._CheckIfwi(data)
2430
2431 def testPackX86RomIfwiNoData(self):
2432 """Test that an x86 ROM with IFWI handles missing data"""
2433 self._SetupIfwi('ifwi.bin')
2434 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06002435 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glass759af872019-07-08 13:18:54 -06002436 self.assertIn('Could not complete processing of contents',
2437 str(e.exception))
Simon Glass91710b32018-07-17 13:25:32 -06002438
Simon Glass66152ce2022-01-09 20:14:09 -07002439 def testIfwiMissing(self):
2440 """Test that binman still produces an image if ifwitool is missing"""
2441 self._SetupIfwi('fitimage.bin')
2442 with test_util.capture_sys_output() as (_, stderr):
2443 self._DoTestFile('111_x86_rom_ifwi.dts',
2444 force_missing_bintools='ifwitool')
2445 err = stderr.getvalue()
2446 self.assertRegex(err,
Simon Glass49cd2b32023-02-07 14:34:18 -07002447 "Image 'image'.*missing bintools.*: ifwitool")
Simon Glass66152ce2022-01-09 20:14:09 -07002448
Simon Glassc2f1aed2019-07-08 13:18:56 -06002449 def testCbfsOffset(self):
2450 """Test a CBFS with files at particular offsets
2451
2452 Like all CFBS tests, this is just checking the logic that calls
2453 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2454 """
2455 data = self._DoReadFile('114_cbfs_offset.dts')
2456 size = 0x200
2457
2458 cbfs = cbfs_util.CbfsReader(data)
2459 self.assertEqual(size, cbfs.rom_size)
2460
2461 self.assertIn('u-boot', cbfs.files)
2462 cfile = cbfs.files['u-boot']
2463 self.assertEqual(U_BOOT_DATA, cfile.data)
2464 self.assertEqual(0x40, cfile.cbfs_offset)
2465
2466 self.assertIn('u-boot-dtb', cbfs.files)
2467 cfile2 = cbfs.files['u-boot-dtb']
2468 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2469 self.assertEqual(0x140, cfile2.cbfs_offset)
2470
Simon Glass0f621332019-07-08 14:25:27 -06002471 def testFdtmap(self):
2472 """Test an FDT map can be inserted in the image"""
2473 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2474 fdtmap_data = data[len(U_BOOT_DATA):]
2475 magic = fdtmap_data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002476 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07002477 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass0f621332019-07-08 14:25:27 -06002478
2479 fdt_data = fdtmap_data[16:]
2480 dtb = fdt.Fdt.FromData(fdt_data)
2481 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002482 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass0f621332019-07-08 14:25:27 -06002483 self.assertEqual({
2484 'image-pos': 0,
2485 'offset': 0,
2486 'u-boot:offset': 0,
2487 'u-boot:size': len(U_BOOT_DATA),
2488 'u-boot:image-pos': 0,
2489 'fdtmap:image-pos': 4,
2490 'fdtmap:offset': 4,
2491 'fdtmap:size': len(fdtmap_data),
2492 'size': len(data),
2493 }, props)
2494
2495 def testFdtmapNoMatch(self):
2496 """Check handling of an FDT map when the section cannot be found"""
2497 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2498
2499 # Mangle the section name, which should cause a mismatch between the
2500 # correct FDT path and the one expected by the section
2501 image = control.images['image']
Simon Glasscec34ba2019-07-08 14:25:28 -06002502 image._node.path += '-suffix'
Simon Glass0f621332019-07-08 14:25:27 -06002503 entries = image.GetEntries()
2504 fdtmap = entries['fdtmap']
2505 with self.assertRaises(ValueError) as e:
2506 fdtmap._GetFdtmap()
2507 self.assertIn("Cannot locate node for path '/binman-suffix'",
2508 str(e.exception))
2509
Simon Glasscec34ba2019-07-08 14:25:28 -06002510 def testFdtmapHeader(self):
2511 """Test an FDT map and image header can be inserted in the image"""
2512 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2513 fdtmap_pos = len(U_BOOT_DATA)
2514 fdtmap_data = data[fdtmap_pos:]
2515 fdt_data = fdtmap_data[16:]
2516 dtb = fdt.Fdt.FromData(fdt_data)
2517 fdt_size = dtb.GetFdtObj().totalsize()
2518 hdr_data = data[-8:]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002519 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002520 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2521 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2522
2523 def testFdtmapHeaderStart(self):
2524 """Test an image header can be inserted at the image start"""
2525 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2526 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2527 hdr_data = data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002528 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002529 offset = struct.unpack('<I', hdr_data[4:])[0]
2530 self.assertEqual(fdtmap_pos, offset)
2531
2532 def testFdtmapHeaderPos(self):
2533 """Test an image header can be inserted at a chosen position"""
2534 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2535 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2536 hdr_data = data[0x80:0x88]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002537 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002538 offset = struct.unpack('<I', hdr_data[4:])[0]
2539 self.assertEqual(fdtmap_pos, offset)
2540
2541 def testHeaderMissingFdtmap(self):
2542 """Test an image header requires an fdtmap"""
2543 with self.assertRaises(ValueError) as e:
2544 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2545 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2546 str(e.exception))
2547
2548 def testHeaderNoLocation(self):
2549 """Test an image header with a no specified location is detected"""
2550 with self.assertRaises(ValueError) as e:
2551 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2552 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2553 str(e.exception))
2554
Simon Glasse61b6f62019-07-08 14:25:37 -06002555 def testEntryExpand(self):
Simon Glassdd156a42022-03-05 20:18:59 -07002556 """Test extending an entry after it is packed"""
2557 data = self._DoReadFile('121_entry_extend.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002558 self.assertEqual(b'aaa', data[:3])
2559 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2560 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002561
Simon Glassdd156a42022-03-05 20:18:59 -07002562 def testEntryExtendBad(self):
2563 """Test extending an entry after it is packed, twice"""
Simon Glasse61b6f62019-07-08 14:25:37 -06002564 with self.assertRaises(ValueError) as e:
Simon Glassdd156a42022-03-05 20:18:59 -07002565 self._DoReadFile('122_entry_extend_twice.dts')
Simon Glass9d8ee322019-07-20 12:23:58 -06002566 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glasse61b6f62019-07-08 14:25:37 -06002567 str(e.exception))
2568
Simon Glassdd156a42022-03-05 20:18:59 -07002569 def testEntryExtendSection(self):
2570 """Test extending an entry within a section after it is packed"""
2571 data = self._DoReadFile('123_entry_extend_section.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002572 self.assertEqual(b'aaa', data[:3])
2573 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2574 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002575
Simon Glass90d29682019-07-08 14:25:38 -06002576 def testCompressDtb(self):
2577 """Test that compress of device-tree files is supported"""
2578 self._CheckLz4()
2579 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2580 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2581 comp_data = data[len(U_BOOT_DATA):]
2582 orig = self._decompress(comp_data)
2583 dtb = fdt.Fdt.FromData(orig)
2584 dtb.Scan()
2585 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2586 expected = {
2587 'u-boot:size': len(U_BOOT_DATA),
2588 'u-boot-dtb:uncomp-size': len(orig),
2589 'u-boot-dtb:size': len(comp_data),
2590 'size': len(data),
2591 }
2592 self.assertEqual(expected, props)
2593
Simon Glass151bbbf2019-07-08 14:25:41 -06002594 def testCbfsUpdateFdt(self):
2595 """Test that we can update the device tree with CBFS offset/size info"""
2596 self._CheckLz4()
2597 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2598 update_dtb=True)
2599 dtb = fdt.Fdt(out_dtb_fname)
2600 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002601 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass151bbbf2019-07-08 14:25:41 -06002602 del props['cbfs/u-boot:size']
2603 self.assertEqual({
2604 'offset': 0,
2605 'size': len(data),
2606 'image-pos': 0,
2607 'cbfs:offset': 0,
2608 'cbfs:size': len(data),
2609 'cbfs:image-pos': 0,
2610 'cbfs/u-boot:offset': 0x38,
2611 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2612 'cbfs/u-boot:image-pos': 0x38,
2613 'cbfs/u-boot-dtb:offset': 0xb8,
2614 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2615 'cbfs/u-boot-dtb:image-pos': 0xb8,
2616 }, props)
2617
Simon Glass3c9b4f22019-07-08 14:25:42 -06002618 def testCbfsBadType(self):
2619 """Test an image header with a no specified location is detected"""
2620 with self.assertRaises(ValueError) as e:
2621 self._DoReadFile('126_cbfs_bad_type.dts')
2622 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2623
Simon Glass6b156f82019-07-08 14:25:43 -06002624 def testList(self):
2625 """Test listing the files in an image"""
2626 self._CheckLz4()
2627 data = self._DoReadFile('127_list.dts')
2628 image = control.images['image']
2629 entries = image.BuildEntryList()
2630 self.assertEqual(7, len(entries))
2631
2632 ent = entries[0]
2633 self.assertEqual(0, ent.indent)
Simon Glass49cd2b32023-02-07 14:34:18 -07002634 self.assertEqual('image', ent.name)
Simon Glass6b156f82019-07-08 14:25:43 -06002635 self.assertEqual('section', ent.etype)
2636 self.assertEqual(len(data), ent.size)
2637 self.assertEqual(0, ent.image_pos)
2638 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002639 self.assertEqual(0, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002640
2641 ent = entries[1]
2642 self.assertEqual(1, ent.indent)
2643 self.assertEqual('u-boot', ent.name)
2644 self.assertEqual('u-boot', ent.etype)
2645 self.assertEqual(len(U_BOOT_DATA), ent.size)
2646 self.assertEqual(0, ent.image_pos)
2647 self.assertEqual(None, ent.uncomp_size)
2648 self.assertEqual(0, ent.offset)
2649
2650 ent = entries[2]
2651 self.assertEqual(1, ent.indent)
2652 self.assertEqual('section', ent.name)
2653 self.assertEqual('section', ent.etype)
2654 section_size = ent.size
2655 self.assertEqual(0x100, ent.image_pos)
2656 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002657 self.assertEqual(0x100, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002658
2659 ent = entries[3]
2660 self.assertEqual(2, ent.indent)
2661 self.assertEqual('cbfs', ent.name)
2662 self.assertEqual('cbfs', ent.etype)
2663 self.assertEqual(0x400, ent.size)
2664 self.assertEqual(0x100, ent.image_pos)
2665 self.assertEqual(None, ent.uncomp_size)
2666 self.assertEqual(0, ent.offset)
2667
2668 ent = entries[4]
2669 self.assertEqual(3, ent.indent)
2670 self.assertEqual('u-boot', ent.name)
2671 self.assertEqual('u-boot', ent.etype)
2672 self.assertEqual(len(U_BOOT_DATA), ent.size)
2673 self.assertEqual(0x138, ent.image_pos)
2674 self.assertEqual(None, ent.uncomp_size)
2675 self.assertEqual(0x38, ent.offset)
2676
2677 ent = entries[5]
2678 self.assertEqual(3, ent.indent)
2679 self.assertEqual('u-boot-dtb', ent.name)
2680 self.assertEqual('text', ent.etype)
2681 self.assertGreater(len(COMPRESS_DATA), ent.size)
2682 self.assertEqual(0x178, ent.image_pos)
2683 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2684 self.assertEqual(0x78, ent.offset)
2685
2686 ent = entries[6]
2687 self.assertEqual(2, ent.indent)
2688 self.assertEqual('u-boot-dtb', ent.name)
2689 self.assertEqual('u-boot-dtb', ent.etype)
2690 self.assertEqual(0x500, ent.image_pos)
2691 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2692 dtb_size = ent.size
2693 # Compressing this data expands it since headers are added
2694 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2695 self.assertEqual(0x400, ent.offset)
2696
2697 self.assertEqual(len(data), 0x100 + section_size)
2698 self.assertEqual(section_size, 0x400 + dtb_size)
2699
Simon Glass8d8bf4e2019-07-08 14:25:44 -06002700 def testFindFdtmap(self):
2701 """Test locating an FDT map in an image"""
2702 self._CheckLz4()
2703 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2704 image = control.images['image']
2705 entries = image.GetEntries()
2706 entry = entries['fdtmap']
2707 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2708
2709 def testFindFdtmapMissing(self):
2710 """Test failing to locate an FDP map"""
2711 data = self._DoReadFile('005_simple.dts')
2712 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2713
Simon Glassed39a3c2019-07-08 14:25:45 -06002714 def testFindImageHeader(self):
2715 """Test locating a image header"""
2716 self._CheckLz4()
Simon Glassb8424fa2019-07-08 14:25:46 -06002717 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002718 image = control.images['image']
2719 entries = image.GetEntries()
2720 entry = entries['fdtmap']
2721 # The header should point to the FDT map
2722 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2723
2724 def testFindImageHeaderStart(self):
2725 """Test locating a image header located at the start of an image"""
Simon Glassb8424fa2019-07-08 14:25:46 -06002726 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002727 image = control.images['image']
2728 entries = image.GetEntries()
2729 entry = entries['fdtmap']
2730 # The header should point to the FDT map
2731 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2732
2733 def testFindImageHeaderMissing(self):
2734 """Test failing to locate an image header"""
2735 data = self._DoReadFile('005_simple.dts')
2736 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2737
Simon Glassb8424fa2019-07-08 14:25:46 -06002738 def testReadImage(self):
2739 """Test reading an image and accessing its FDT map"""
2740 self._CheckLz4()
2741 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass80025522022-01-29 14:14:04 -07002742 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002743 orig_image = control.images['image']
2744 image = Image.FromFile(image_fname)
2745 self.assertEqual(orig_image.GetEntries().keys(),
2746 image.GetEntries().keys())
2747
2748 orig_entry = orig_image.GetEntries()['fdtmap']
2749 entry = image.GetEntries()['fdtmap']
2750 self.assertEquals(orig_entry.offset, entry.offset)
2751 self.assertEquals(orig_entry.size, entry.size)
2752 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2753
2754 def testReadImageNoHeader(self):
2755 """Test accessing an image's FDT map without an image header"""
2756 self._CheckLz4()
2757 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
Simon Glass80025522022-01-29 14:14:04 -07002758 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002759 image = Image.FromFile(image_fname)
2760 self.assertTrue(isinstance(image, Image))
Simon Glass072959a2019-07-20 12:23:50 -06002761 self.assertEqual('image', image.image_name[-5:])
Simon Glassb8424fa2019-07-08 14:25:46 -06002762
2763 def testReadImageFail(self):
2764 """Test failing to read an image image's FDT map"""
2765 self._DoReadFile('005_simple.dts')
Simon Glass80025522022-01-29 14:14:04 -07002766 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002767 with self.assertRaises(ValueError) as e:
2768 image = Image.FromFile(image_fname)
2769 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glassc2f1aed2019-07-08 13:18:56 -06002770
Simon Glassb2fd11d2019-07-08 14:25:48 -06002771 def testListCmd(self):
2772 """Test listing the files in an image using an Fdtmap"""
2773 self._CheckLz4()
2774 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2775
2776 # lz4 compression size differs depending on the version
2777 image = control.images['image']
2778 entries = image.GetEntries()
2779 section_size = entries['section'].size
2780 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2781 fdtmap_offset = entries['fdtmap'].offset
2782
Simon Glassb3d6fc72019-07-20 12:24:10 -06002783 try:
2784 tmpdir, updated_fname = self._SetupImageInTmpdir()
2785 with test_util.capture_sys_output() as (stdout, stderr):
2786 self._DoBinman('ls', '-i', updated_fname)
2787 finally:
2788 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002789 lines = stdout.getvalue().splitlines()
2790 expected = [
2791'Name Image-pos Size Entry-type Offset Uncomp-size',
2792'----------------------------------------------------------------------',
Simon Glass49cd2b32023-02-07 14:34:18 -07002793'image 0 c00 section 0',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002794' u-boot 0 4 u-boot 0',
2795' section 100 %x section 100' % section_size,
2796' cbfs 100 400 cbfs 0',
2797' u-boot 138 4 u-boot 38',
Simon Glassc5fd10a2019-10-31 07:43:03 -06002798' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002799' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassc5fd10a2019-10-31 07:43:03 -06002800' fdtmap %x 3bd fdtmap %x' %
Simon Glassb2fd11d2019-07-08 14:25:48 -06002801 (fdtmap_offset, fdtmap_offset),
2802' image-header bf8 8 image-header bf8',
2803 ]
2804 self.assertEqual(expected, lines)
2805
2806 def testListCmdFail(self):
2807 """Test failing to list an image"""
2808 self._DoReadFile('005_simple.dts')
Simon Glassb3d6fc72019-07-20 12:24:10 -06002809 try:
2810 tmpdir, updated_fname = self._SetupImageInTmpdir()
2811 with self.assertRaises(ValueError) as e:
2812 self._DoBinman('ls', '-i', updated_fname)
2813 finally:
2814 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002815 self.assertIn("Cannot find FDT map in image", str(e.exception))
2816
2817 def _RunListCmd(self, paths, expected):
2818 """List out entries and check the result
2819
2820 Args:
2821 paths: List of paths to pass to the list command
2822 expected: Expected list of filenames to be returned, in order
2823 """
2824 self._CheckLz4()
2825 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002826 image_fname = tools.get_output_filename('image.bin')
Simon Glassb2fd11d2019-07-08 14:25:48 -06002827 image = Image.FromFile(image_fname)
2828 lines = image.GetListEntries(paths)[1]
2829 files = [line[0].strip() for line in lines[1:]]
2830 self.assertEqual(expected, files)
2831
2832 def testListCmdSection(self):
2833 """Test listing the files in a section"""
2834 self._RunListCmd(['section'],
2835 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2836
2837 def testListCmdFile(self):
2838 """Test listing a particular file"""
2839 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2840
2841 def testListCmdWildcard(self):
2842 """Test listing a wildcarded file"""
2843 self._RunListCmd(['*boot*'],
2844 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2845
2846 def testListCmdWildcardMulti(self):
2847 """Test listing a wildcarded file"""
2848 self._RunListCmd(['*cb*', '*head*'],
2849 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2850
2851 def testListCmdEmpty(self):
2852 """Test listing a wildcarded file"""
2853 self._RunListCmd(['nothing'], [])
2854
2855 def testListCmdPath(self):
2856 """Test listing the files in a sub-entry of a section"""
2857 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2858
Simon Glass4c613bf2019-07-08 14:25:50 -06002859 def _RunExtractCmd(self, entry_name, decomp=True):
2860 """Extract an entry from an image
2861
2862 Args:
2863 entry_name: Entry name to extract
2864 decomp: True to decompress the data if compressed, False to leave
2865 it in its raw uncompressed format
2866
2867 Returns:
2868 data from entry
2869 """
2870 self._CheckLz4()
2871 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002872 image_fname = tools.get_output_filename('image.bin')
Simon Glass4c613bf2019-07-08 14:25:50 -06002873 return control.ReadEntry(image_fname, entry_name, decomp)
2874
2875 def testExtractSimple(self):
2876 """Test extracting a single file"""
2877 data = self._RunExtractCmd('u-boot')
2878 self.assertEqual(U_BOOT_DATA, data)
2879
Simon Glass980a2842019-07-08 14:25:52 -06002880 def testExtractSection(self):
2881 """Test extracting the files in a section"""
2882 data = self._RunExtractCmd('section')
2883 cbfs_data = data[:0x400]
2884 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassc5fd10a2019-10-31 07:43:03 -06002885 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass980a2842019-07-08 14:25:52 -06002886 dtb_data = data[0x400:]
2887 dtb = self._decompress(dtb_data)
2888 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2889
2890 def testExtractCompressed(self):
2891 """Test extracting compressed data"""
2892 data = self._RunExtractCmd('section/u-boot-dtb')
2893 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2894
2895 def testExtractRaw(self):
2896 """Test extracting compressed data without decompressing it"""
2897 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2898 dtb = self._decompress(data)
2899 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2900
2901 def testExtractCbfs(self):
2902 """Test extracting CBFS data"""
2903 data = self._RunExtractCmd('section/cbfs/u-boot')
2904 self.assertEqual(U_BOOT_DATA, data)
2905
2906 def testExtractCbfsCompressed(self):
2907 """Test extracting CBFS compressed data"""
2908 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2909 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2910
2911 def testExtractCbfsRaw(self):
2912 """Test extracting CBFS compressed data without decompressing it"""
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02002913 bintool = self.comp_bintools['lzma_alone']
2914 self._CheckBintool(bintool)
Simon Glass980a2842019-07-08 14:25:52 -06002915 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02002916 dtb = bintool.decompress(data)
Simon Glass980a2842019-07-08 14:25:52 -06002917 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2918
Simon Glass4c613bf2019-07-08 14:25:50 -06002919 def testExtractBadEntry(self):
2920 """Test extracting a bad section path"""
2921 with self.assertRaises(ValueError) as e:
2922 self._RunExtractCmd('section/does-not-exist')
2923 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2924 str(e.exception))
2925
2926 def testExtractMissingFile(self):
2927 """Test extracting file that does not exist"""
2928 with self.assertRaises(IOError) as e:
2929 control.ReadEntry('missing-file', 'name')
2930
2931 def testExtractBadFile(self):
2932 """Test extracting an invalid file"""
2933 fname = os.path.join(self._indir, 'badfile')
Simon Glass80025522022-01-29 14:14:04 -07002934 tools.write_file(fname, b'')
Simon Glass4c613bf2019-07-08 14:25:50 -06002935 with self.assertRaises(ValueError) as e:
2936 control.ReadEntry(fname, 'name')
2937
Simon Glass980a2842019-07-08 14:25:52 -06002938 def testExtractCmd(self):
2939 """Test extracting a file fron an image on the command line"""
2940 self._CheckLz4()
2941 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass980a2842019-07-08 14:25:52 -06002942 fname = os.path.join(self._indir, 'output.extact')
Simon Glassb3d6fc72019-07-20 12:24:10 -06002943 try:
2944 tmpdir, updated_fname = self._SetupImageInTmpdir()
2945 with test_util.capture_sys_output() as (stdout, stderr):
2946 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2947 '-f', fname)
2948 finally:
2949 shutil.rmtree(tmpdir)
Simon Glass80025522022-01-29 14:14:04 -07002950 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06002951 self.assertEqual(U_BOOT_DATA, data)
2952
2953 def testExtractOneEntry(self):
2954 """Test extracting a single entry fron an image """
2955 self._CheckLz4()
2956 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002957 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06002958 fname = os.path.join(self._indir, 'output.extact')
2959 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07002960 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06002961 self.assertEqual(U_BOOT_DATA, data)
2962
2963 def _CheckExtractOutput(self, decomp):
2964 """Helper to test file output with and without decompression
2965
2966 Args:
2967 decomp: True to decompress entry data, False to output it raw
2968 """
2969 def _CheckPresent(entry_path, expect_data, expect_size=None):
2970 """Check and remove expected file
2971
2972 This checks the data/size of a file and removes the file both from
2973 the outfiles set and from the output directory. Once all files are
2974 processed, both the set and directory should be empty.
2975
2976 Args:
2977 entry_path: Entry path
2978 expect_data: Data to expect in file, or None to skip check
2979 expect_size: Size of data to expect in file, or None to skip
2980 """
2981 path = os.path.join(outdir, entry_path)
Simon Glass80025522022-01-29 14:14:04 -07002982 data = tools.read_file(path)
Simon Glass980a2842019-07-08 14:25:52 -06002983 os.remove(path)
2984 if expect_data:
2985 self.assertEqual(expect_data, data)
2986 elif expect_size:
2987 self.assertEqual(expect_size, len(data))
2988 outfiles.remove(path)
2989
2990 def _CheckDirPresent(name):
2991 """Remove expected directory
2992
2993 This gives an error if the directory does not exist as expected
2994
2995 Args:
2996 name: Name of directory to remove
2997 """
2998 path = os.path.join(outdir, name)
2999 os.rmdir(path)
3000
3001 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003002 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003003 outdir = os.path.join(self._indir, 'extract')
3004 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
3005
3006 # Create a set of all file that were output (should be 9)
3007 outfiles = set()
3008 for root, dirs, files in os.walk(outdir):
3009 outfiles |= set([os.path.join(root, fname) for fname in files])
3010 self.assertEqual(9, len(outfiles))
3011 self.assertEqual(9, len(einfos))
3012
3013 image = control.images['image']
3014 entries = image.GetEntries()
3015
3016 # Check the 9 files in various ways
3017 section = entries['section']
3018 section_entries = section.GetEntries()
3019 cbfs_entries = section_entries['cbfs'].GetEntries()
3020 _CheckPresent('u-boot', U_BOOT_DATA)
3021 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
3022 dtb_len = EXTRACT_DTB_SIZE
3023 if not decomp:
3024 dtb_len = cbfs_entries['u-boot-dtb'].size
3025 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
3026 if not decomp:
3027 dtb_len = section_entries['u-boot-dtb'].size
3028 _CheckPresent('section/u-boot-dtb', None, dtb_len)
3029
3030 fdtmap = entries['fdtmap']
3031 _CheckPresent('fdtmap', fdtmap.data)
3032 hdr = entries['image-header']
3033 _CheckPresent('image-header', hdr.data)
3034
3035 _CheckPresent('section/root', section.data)
3036 cbfs = section_entries['cbfs']
3037 _CheckPresent('section/cbfs/root', cbfs.data)
Simon Glass80025522022-01-29 14:14:04 -07003038 data = tools.read_file(image_fname)
Simon Glass980a2842019-07-08 14:25:52 -06003039 _CheckPresent('root', data)
3040
3041 # There should be no files left. Remove all the directories to check.
3042 # If there are any files/dirs remaining, one of these checks will fail.
3043 self.assertEqual(0, len(outfiles))
3044 _CheckDirPresent('section/cbfs')
3045 _CheckDirPresent('section')
3046 _CheckDirPresent('')
3047 self.assertFalse(os.path.exists(outdir))
3048
3049 def testExtractAllEntries(self):
3050 """Test extracting all entries"""
3051 self._CheckLz4()
3052 self._CheckExtractOutput(decomp=True)
3053
3054 def testExtractAllEntriesRaw(self):
3055 """Test extracting all entries without decompressing them"""
3056 self._CheckLz4()
3057 self._CheckExtractOutput(decomp=False)
3058
3059 def testExtractSelectedEntries(self):
3060 """Test extracting some entries"""
3061 self._CheckLz4()
3062 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003063 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003064 outdir = os.path.join(self._indir, 'extract')
3065 einfos = control.ExtractEntries(image_fname, None, outdir,
3066 ['*cb*', '*head*'])
3067
3068 # File output is tested by testExtractAllEntries(), so just check that
3069 # the expected entries are selected
3070 names = [einfo.name for einfo in einfos]
3071 self.assertEqual(names,
3072 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
3073
3074 def testExtractNoEntryPaths(self):
3075 """Test extracting some entries"""
3076 self._CheckLz4()
3077 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003078 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003079 with self.assertRaises(ValueError) as e:
3080 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassa772d3f2019-07-20 12:24:14 -06003081 self.assertIn('Must specify an entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003082 str(e.exception))
3083
3084 def testExtractTooManyEntryPaths(self):
3085 """Test extracting some entries"""
3086 self._CheckLz4()
3087 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003088 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003089 with self.assertRaises(ValueError) as e:
3090 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassa772d3f2019-07-20 12:24:14 -06003091 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003092 str(e.exception))
3093
Simon Glass52d06212019-07-08 14:25:53 -06003094 def testPackAlignSection(self):
3095 """Test that sections can have alignment"""
3096 self._DoReadFile('131_pack_align_section.dts')
3097
3098 self.assertIn('image', control.images)
3099 image = control.images['image']
3100 entries = image.GetEntries()
3101 self.assertEqual(3, len(entries))
3102
3103 # First u-boot
3104 self.assertIn('u-boot', entries)
3105 entry = entries['u-boot']
3106 self.assertEqual(0, entry.offset)
3107 self.assertEqual(0, entry.image_pos)
3108 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3109 self.assertEqual(len(U_BOOT_DATA), entry.size)
3110
3111 # Section0
3112 self.assertIn('section0', entries)
3113 section0 = entries['section0']
3114 self.assertEqual(0x10, section0.offset)
3115 self.assertEqual(0x10, section0.image_pos)
3116 self.assertEqual(len(U_BOOT_DATA), section0.size)
3117
3118 # Second u-boot
3119 section_entries = section0.GetEntries()
3120 self.assertIn('u-boot', section_entries)
3121 entry = section_entries['u-boot']
3122 self.assertEqual(0, entry.offset)
3123 self.assertEqual(0x10, entry.image_pos)
3124 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3125 self.assertEqual(len(U_BOOT_DATA), entry.size)
3126
3127 # Section1
3128 self.assertIn('section1', entries)
3129 section1 = entries['section1']
3130 self.assertEqual(0x14, section1.offset)
3131 self.assertEqual(0x14, section1.image_pos)
3132 self.assertEqual(0x20, section1.size)
3133
3134 # Second u-boot
3135 section_entries = section1.GetEntries()
3136 self.assertIn('u-boot', section_entries)
3137 entry = section_entries['u-boot']
3138 self.assertEqual(0, entry.offset)
3139 self.assertEqual(0x14, entry.image_pos)
3140 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3141 self.assertEqual(len(U_BOOT_DATA), entry.size)
3142
3143 # Section2
3144 self.assertIn('section2', section_entries)
3145 section2 = section_entries['section2']
3146 self.assertEqual(0x4, section2.offset)
3147 self.assertEqual(0x18, section2.image_pos)
3148 self.assertEqual(4, section2.size)
3149
3150 # Third u-boot
3151 section_entries = section2.GetEntries()
3152 self.assertIn('u-boot', section_entries)
3153 entry = section_entries['u-boot']
3154 self.assertEqual(0, entry.offset)
3155 self.assertEqual(0x18, entry.image_pos)
3156 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3157 self.assertEqual(len(U_BOOT_DATA), entry.size)
3158
Simon Glassf8a54bc2019-07-20 12:23:56 -06003159 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3160 dts='132_replace.dts'):
Simon Glass072959a2019-07-20 12:23:50 -06003161 """Replace an entry in an image
3162
3163 This writes the entry data to update it, then opens the updated file and
3164 returns the value that it now finds there.
3165
3166 Args:
3167 entry_name: Entry name to replace
3168 data: Data to replace it with
3169 decomp: True to compress the data if needed, False if data is
3170 already compressed so should be used as is
Simon Glassf8a54bc2019-07-20 12:23:56 -06003171 allow_resize: True to allow entries to change size, False to raise
3172 an exception
Simon Glass072959a2019-07-20 12:23:50 -06003173
3174 Returns:
3175 Tuple:
3176 data from entry
3177 data from fdtmap (excluding header)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003178 Image object that was modified
Simon Glass072959a2019-07-20 12:23:50 -06003179 """
Simon Glassf8a54bc2019-07-20 12:23:56 -06003180 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass072959a2019-07-20 12:23:50 -06003181 update_dtb=True)[1]
3182
3183 self.assertIn('image', control.images)
3184 image = control.images['image']
3185 entries = image.GetEntries()
3186 orig_dtb_data = entries['u-boot-dtb'].data
3187 orig_fdtmap_data = entries['fdtmap'].data
3188
Simon Glass80025522022-01-29 14:14:04 -07003189 image_fname = tools.get_output_filename('image.bin')
3190 updated_fname = tools.get_output_filename('image-updated.bin')
3191 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassf8a54bc2019-07-20 12:23:56 -06003192 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3193 allow_resize)
Simon Glass072959a2019-07-20 12:23:50 -06003194 data = control.ReadEntry(updated_fname, entry_name, decomp)
3195
Simon Glassf8a54bc2019-07-20 12:23:56 -06003196 # The DT data should not change unless resized:
3197 if not allow_resize:
3198 new_dtb_data = entries['u-boot-dtb'].data
3199 self.assertEqual(new_dtb_data, orig_dtb_data)
3200 new_fdtmap_data = entries['fdtmap'].data
3201 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass072959a2019-07-20 12:23:50 -06003202
Simon Glassf8a54bc2019-07-20 12:23:56 -06003203 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass072959a2019-07-20 12:23:50 -06003204
3205 def testReplaceSimple(self):
3206 """Test replacing a single file"""
3207 expected = b'x' * len(U_BOOT_DATA)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003208 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3209 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003210 self.assertEqual(expected, data)
3211
3212 # Test that the state looks right. There should be an FDT for the fdtmap
3213 # that we jsut read back in, and it should match what we find in the
3214 # 'control' tables. Checking for an FDT that does not exist should
3215 # return None.
3216 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glassf8a54bc2019-07-20 12:23:56 -06003217 self.assertIsNotNone(path)
Simon Glass072959a2019-07-20 12:23:50 -06003218 self.assertEqual(expected_fdtmap, fdtmap)
3219
3220 dtb = state.GetFdtForEtype('fdtmap')
3221 self.assertEqual(dtb.GetContents(), fdtmap)
3222
3223 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3224 self.assertIsNone(missing_path)
3225 self.assertIsNone(missing_fdtmap)
3226
3227 missing_dtb = state.GetFdtForEtype('missing')
3228 self.assertIsNone(missing_dtb)
3229
3230 self.assertEqual('/binman', state.fdt_path_prefix)
3231
3232 def testReplaceResizeFail(self):
3233 """Test replacing a file by something larger"""
3234 expected = U_BOOT_DATA + b'x'
3235 with self.assertRaises(ValueError) as e:
Simon Glassf8a54bc2019-07-20 12:23:56 -06003236 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3237 dts='139_replace_repack.dts')
Simon Glass072959a2019-07-20 12:23:50 -06003238 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3239 str(e.exception))
3240
3241 def testReplaceMulti(self):
3242 """Test replacing entry data where multiple images are generated"""
3243 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3244 update_dtb=True)[0]
3245 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003246 updated_fname = tools.get_output_filename('image-updated.bin')
3247 tools.write_file(updated_fname, data)
Simon Glass072959a2019-07-20 12:23:50 -06003248 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003249 control.WriteEntry(updated_fname, entry_name, expected,
3250 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003251 data = control.ReadEntry(updated_fname, entry_name)
3252 self.assertEqual(expected, data)
3253
3254 # Check the state looks right.
3255 self.assertEqual('/binman/image', state.fdt_path_prefix)
3256
3257 # Now check we can write the first image
Simon Glass80025522022-01-29 14:14:04 -07003258 image_fname = tools.get_output_filename('first-image.bin')
3259 updated_fname = tools.get_output_filename('first-updated.bin')
3260 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glass072959a2019-07-20 12:23:50 -06003261 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003262 control.WriteEntry(updated_fname, entry_name, expected,
3263 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003264 data = control.ReadEntry(updated_fname, entry_name)
3265 self.assertEqual(expected, data)
3266
3267 # Check the state looks right.
3268 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass39dd2152019-07-08 14:25:47 -06003269
Simon Glassfb30e292019-07-20 12:23:51 -06003270 def testUpdateFdtAllRepack(self):
3271 """Test that all device trees are updated with offset/size info"""
3272 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3273 SECTION_SIZE = 0x300
3274 DTB_SIZE = 602
3275 FDTMAP_SIZE = 608
3276 base_expected = {
3277 'offset': 0,
3278 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3279 'image-pos': 0,
3280 'section:offset': 0,
3281 'section:size': SECTION_SIZE,
3282 'section:image-pos': 0,
3283 'section/u-boot-dtb:offset': 4,
3284 'section/u-boot-dtb:size': 636,
3285 'section/u-boot-dtb:image-pos': 4,
3286 'u-boot-spl-dtb:offset': SECTION_SIZE,
3287 'u-boot-spl-dtb:size': DTB_SIZE,
3288 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3289 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3290 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3291 'u-boot-tpl-dtb:size': DTB_SIZE,
3292 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3293 'fdtmap:size': FDTMAP_SIZE,
3294 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3295 }
3296 main_expected = {
3297 'section:orig-size': SECTION_SIZE,
3298 'section/u-boot-dtb:orig-offset': 4,
3299 }
3300
3301 # We expect three device-tree files in the output, with the first one
3302 # within a fixed-size section.
3303 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3304 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3305 # main U-Boot tree. All three should have the same positions and offset
3306 # except that the main tree should include the main_expected properties
3307 start = 4
3308 for item in ['', 'spl', 'tpl', None]:
3309 if item is None:
3310 start += 16 # Move past fdtmap header
3311 dtb = fdt.Fdt.FromData(data[start:])
3312 dtb.Scan()
3313 props = self._GetPropTree(dtb,
3314 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3315 prefix='/' if item is None else '/binman/')
3316 expected = dict(base_expected)
3317 if item:
3318 expected[item] = 0
3319 else:
3320 # Main DTB and fdtdec should include the 'orig-' properties
3321 expected.update(main_expected)
3322 # Helpful for debugging:
3323 #for prop in sorted(props):
3324 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3325 self.assertEqual(expected, props)
3326 if item == '':
3327 start = SECTION_SIZE
3328 else:
3329 start += dtb._fdt_obj.totalsize()
3330
Simon Glass11453762019-07-20 12:23:55 -06003331 def testFdtmapHeaderMiddle(self):
3332 """Test an FDT map in the middle of an image when it should be at end"""
3333 with self.assertRaises(ValueError) as e:
3334 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3335 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3336 str(e.exception))
3337
3338 def testFdtmapHeaderStartBad(self):
3339 """Test an FDT map in middle of an image when it should be at start"""
3340 with self.assertRaises(ValueError) as e:
3341 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3342 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3343 str(e.exception))
3344
3345 def testFdtmapHeaderEndBad(self):
3346 """Test an FDT map at the start of an image when it should be at end"""
3347 with self.assertRaises(ValueError) as e:
3348 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3349 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3350 str(e.exception))
3351
3352 def testFdtmapHeaderNoSize(self):
3353 """Test an image header at the end of an image with undefined size"""
3354 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3355
Simon Glassf8a54bc2019-07-20 12:23:56 -06003356 def testReplaceResize(self):
3357 """Test replacing a single file in an entry with a larger file"""
3358 expected = U_BOOT_DATA + b'x'
3359 data, _, image = self._RunReplaceCmd('u-boot', expected,
3360 dts='139_replace_repack.dts')
3361 self.assertEqual(expected, data)
3362
3363 entries = image.GetEntries()
3364 dtb_data = entries['u-boot-dtb'].data
3365 dtb = fdt.Fdt.FromData(dtb_data)
3366 dtb.Scan()
3367
3368 # The u-boot section should now be larger in the dtb
3369 node = dtb.GetNode('/binman/u-boot')
3370 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3371
3372 # Same for the fdtmap
3373 fdata = entries['fdtmap'].data
3374 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3375 fdtb.Scan()
3376 fnode = fdtb.GetNode('/u-boot')
3377 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3378
3379 def testReplaceResizeNoRepack(self):
3380 """Test replacing an entry with a larger file when not allowed"""
3381 expected = U_BOOT_DATA + b'x'
3382 with self.assertRaises(ValueError) as e:
3383 self._RunReplaceCmd('u-boot', expected)
3384 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3385 str(e.exception))
3386
Simon Glass9d8ee322019-07-20 12:23:58 -06003387 def testEntryShrink(self):
3388 """Test contracting an entry after it is packed"""
3389 try:
3390 state.SetAllowEntryContraction(True)
3391 data = self._DoReadFileDtb('140_entry_shrink.dts',
3392 update_dtb=True)[0]
3393 finally:
3394 state.SetAllowEntryContraction(False)
3395 self.assertEqual(b'a', data[:1])
3396 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3397 self.assertEqual(b'a', data[-1:])
3398
3399 def testEntryShrinkFail(self):
3400 """Test not being allowed to contract an entry after it is packed"""
3401 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3402
3403 # In this case there is a spare byte at the end of the data. The size of
3404 # the contents is only 1 byte but we still have the size before it
3405 # shrunk.
3406 self.assertEqual(b'a\0', data[:2])
3407 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3408 self.assertEqual(b'a\0', data[-2:])
3409
Simon Glass70e32982019-07-20 12:24:01 -06003410 def testDescriptorOffset(self):
3411 """Test that the Intel descriptor is always placed at at the start"""
3412 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3413 image = control.images['image']
3414 entries = image.GetEntries()
3415 desc = entries['intel-descriptor']
3416 self.assertEqual(0xff800000, desc.offset);
3417 self.assertEqual(0xff800000, desc.image_pos);
3418
Simon Glass37fdd142019-07-20 12:24:06 -06003419 def testReplaceCbfs(self):
3420 """Test replacing a single file in CBFS without changing the size"""
3421 self._CheckLz4()
3422 expected = b'x' * len(U_BOOT_DATA)
3423 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003424 updated_fname = tools.get_output_filename('image-updated.bin')
3425 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003426 entry_name = 'section/cbfs/u-boot'
3427 control.WriteEntry(updated_fname, entry_name, expected,
3428 allow_resize=True)
3429 data = control.ReadEntry(updated_fname, entry_name)
3430 self.assertEqual(expected, data)
3431
3432 def testReplaceResizeCbfs(self):
3433 """Test replacing a single file in CBFS with one of a different size"""
3434 self._CheckLz4()
3435 expected = U_BOOT_DATA + b'x'
3436 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003437 updated_fname = tools.get_output_filename('image-updated.bin')
3438 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003439 entry_name = 'section/cbfs/u-boot'
3440 control.WriteEntry(updated_fname, entry_name, expected,
3441 allow_resize=True)
3442 data = control.ReadEntry(updated_fname, entry_name)
3443 self.assertEqual(expected, data)
3444
Simon Glass30033c22019-07-20 12:24:15 -06003445 def _SetupForReplace(self):
3446 """Set up some files to use to replace entries
3447
3448 This generates an image, copies it to a new file, extracts all the files
3449 in it and updates some of them
3450
3451 Returns:
3452 List
3453 Image filename
3454 Output directory
3455 Expected values for updated entries, each a string
3456 """
3457 data = self._DoReadFileRealDtb('143_replace_all.dts')
3458
Simon Glass80025522022-01-29 14:14:04 -07003459 updated_fname = tools.get_output_filename('image-updated.bin')
3460 tools.write_file(updated_fname, data)
Simon Glass30033c22019-07-20 12:24:15 -06003461
3462 outdir = os.path.join(self._indir, 'extract')
3463 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3464
3465 expected1 = b'x' + U_BOOT_DATA + b'y'
3466 u_boot_fname1 = os.path.join(outdir, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07003467 tools.write_file(u_boot_fname1, expected1)
Simon Glass30033c22019-07-20 12:24:15 -06003468
3469 expected2 = b'a' + U_BOOT_DATA + b'b'
3470 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
Simon Glass80025522022-01-29 14:14:04 -07003471 tools.write_file(u_boot_fname2, expected2)
Simon Glass30033c22019-07-20 12:24:15 -06003472
3473 expected_text = b'not the same text'
3474 text_fname = os.path.join(outdir, 'text')
Simon Glass80025522022-01-29 14:14:04 -07003475 tools.write_file(text_fname, expected_text)
Simon Glass30033c22019-07-20 12:24:15 -06003476
3477 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3478 dtb = fdt.FdtScan(dtb_fname)
3479 node = dtb.GetNode('/binman/text')
3480 node.AddString('my-property', 'the value')
3481 dtb.Sync(auto_resize=True)
3482 dtb.Flush()
3483
3484 return updated_fname, outdir, expected1, expected2, expected_text
3485
3486 def _CheckReplaceMultiple(self, entry_paths):
3487 """Handle replacing the contents of multiple entries
3488
3489 Args:
3490 entry_paths: List of entry paths to replace
3491
3492 Returns:
3493 List
3494 Dict of entries in the image:
3495 key: Entry name
3496 Value: Entry object
3497 Expected values for updated entries, each a string
3498 """
3499 updated_fname, outdir, expected1, expected2, expected_text = (
3500 self._SetupForReplace())
3501 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3502
3503 image = Image.FromFile(updated_fname)
3504 image.LoadData()
3505 return image.GetEntries(), expected1, expected2, expected_text
3506
3507 def testReplaceAll(self):
3508 """Test replacing the contents of all entries"""
3509 entries, expected1, expected2, expected_text = (
3510 self._CheckReplaceMultiple([]))
3511 data = entries['u-boot'].data
3512 self.assertEqual(expected1, data)
3513
3514 data = entries['u-boot2'].data
3515 self.assertEqual(expected2, data)
3516
3517 data = entries['text'].data
3518 self.assertEqual(expected_text, data)
3519
3520 # Check that the device tree is updated
3521 data = entries['u-boot-dtb'].data
3522 dtb = fdt.Fdt.FromData(data)
3523 dtb.Scan()
3524 node = dtb.GetNode('/binman/text')
3525 self.assertEqual('the value', node.props['my-property'].value)
3526
3527 def testReplaceSome(self):
3528 """Test replacing the contents of a few entries"""
3529 entries, expected1, expected2, expected_text = (
3530 self._CheckReplaceMultiple(['u-boot2', 'text']))
3531
3532 # This one should not change
3533 data = entries['u-boot'].data
3534 self.assertEqual(U_BOOT_DATA, data)
3535
3536 data = entries['u-boot2'].data
3537 self.assertEqual(expected2, data)
3538
3539 data = entries['text'].data
3540 self.assertEqual(expected_text, data)
3541
3542 def testReplaceCmd(self):
3543 """Test replacing a file fron an image on the command line"""
3544 self._DoReadFileRealDtb('143_replace_all.dts')
3545
3546 try:
3547 tmpdir, updated_fname = self._SetupImageInTmpdir()
3548
3549 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3550 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003551 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003552
3553 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
Simon Glass80025522022-01-29 14:14:04 -07003554 data = tools.read_file(updated_fname)
Simon Glass30033c22019-07-20 12:24:15 -06003555 self.assertEqual(expected, data[:len(expected)])
3556 map_fname = os.path.join(tmpdir, 'image-updated.map')
3557 self.assertFalse(os.path.exists(map_fname))
3558 finally:
3559 shutil.rmtree(tmpdir)
3560
3561 def testReplaceCmdSome(self):
3562 """Test replacing some files fron an image on the command line"""
3563 updated_fname, outdir, expected1, expected2, expected_text = (
3564 self._SetupForReplace())
3565
3566 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3567 'u-boot2', 'text')
3568
Simon Glass80025522022-01-29 14:14:04 -07003569 tools.prepare_output_dir(None)
Simon Glass30033c22019-07-20 12:24:15 -06003570 image = Image.FromFile(updated_fname)
3571 image.LoadData()
3572 entries = image.GetEntries()
3573
3574 # This one should not change
3575 data = entries['u-boot'].data
3576 self.assertEqual(U_BOOT_DATA, data)
3577
3578 data = entries['u-boot2'].data
3579 self.assertEqual(expected2, data)
3580
3581 data = entries['text'].data
3582 self.assertEqual(expected_text, data)
3583
3584 def testReplaceMissing(self):
3585 """Test replacing entries where the file is missing"""
3586 updated_fname, outdir, expected1, expected2, expected_text = (
3587 self._SetupForReplace())
3588
3589 # Remove one of the files, to generate a warning
3590 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3591 os.remove(u_boot_fname1)
3592
3593 with test_util.capture_sys_output() as (stdout, stderr):
3594 control.ReplaceEntries(updated_fname, None, outdir, [])
3595 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass6e02f7c2020-07-09 18:39:39 -06003596 stderr.getvalue())
Simon Glass30033c22019-07-20 12:24:15 -06003597
3598 def testReplaceCmdMap(self):
3599 """Test replacing a file fron an image on the command line"""
3600 self._DoReadFileRealDtb('143_replace_all.dts')
3601
3602 try:
3603 tmpdir, updated_fname = self._SetupImageInTmpdir()
3604
3605 fname = os.path.join(self._indir, 'update-u-boot.bin')
3606 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003607 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003608
3609 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3610 '-f', fname, '-m')
3611 map_fname = os.path.join(tmpdir, 'image-updated.map')
3612 self.assertTrue(os.path.exists(map_fname))
3613 finally:
3614 shutil.rmtree(tmpdir)
3615
3616 def testReplaceNoEntryPaths(self):
3617 """Test replacing an entry without an entry path"""
3618 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003619 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003620 with self.assertRaises(ValueError) as e:
3621 control.ReplaceEntries(image_fname, 'fname', None, [])
3622 self.assertIn('Must specify an entry path to read with -f',
3623 str(e.exception))
3624
3625 def testReplaceTooManyEntryPaths(self):
3626 """Test extracting some entries"""
3627 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003628 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003629 with self.assertRaises(ValueError) as e:
3630 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3631 self.assertIn('Must specify exactly one entry path to write with -f',
3632 str(e.exception))
3633
Simon Glass0b074d62019-08-24 07:22:48 -06003634 def testPackReset16(self):
3635 """Test that an image with an x86 reset16 region can be created"""
3636 data = self._DoReadFile('144_x86_reset16.dts')
3637 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3638
3639 def testPackReset16Spl(self):
3640 """Test that an image with an x86 reset16-spl region can be created"""
3641 data = self._DoReadFile('145_x86_reset16_spl.dts')
3642 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3643
3644 def testPackReset16Tpl(self):
3645 """Test that an image with an x86 reset16-tpl region can be created"""
3646 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3647 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3648
Simon Glass232f90c2019-08-24 07:22:50 -06003649 def testPackIntelFit(self):
3650 """Test that an image with an Intel FIT and pointer can be created"""
3651 data = self._DoReadFile('147_intel_fit.dts')
3652 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3653 fit = data[16:32];
3654 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3655 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3656
3657 image = control.images['image']
3658 entries = image.GetEntries()
3659 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3660 self.assertEqual(expected_ptr, ptr)
3661
3662 def testPackIntelFitMissing(self):
3663 """Test detection of a FIT pointer with not FIT region"""
3664 with self.assertRaises(ValueError) as e:
3665 self._DoReadFile('148_intel_fit_missing.dts')
3666 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3667 str(e.exception))
3668
Simon Glass72555fa2019-11-06 17:22:44 -07003669 def _CheckSymbolsTplSection(self, dts, expected_vals):
3670 data = self._DoReadFile(dts)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003671 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE, *expected_vals)
Simon Glass3eb5b202019-08-24 07:23:00 -06003672 upto1 = 4 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003673 expected1 = tools.get_bytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003674 self.assertEqual(expected1, data[:upto1])
3675
3676 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003677 expected2 = tools.get_bytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003678 self.assertEqual(expected2, data[upto1:upto2])
3679
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003680 upto3 = 0x3c + len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003681 expected3 = tools.get_bytes(0xff, 1) + U_BOOT_DATA
Simon Glass3eb5b202019-08-24 07:23:00 -06003682 self.assertEqual(expected3, data[upto2:upto3])
3683
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003684 expected4 = sym_values + U_BOOT_TPL_DATA[24:]
Simon Glass72555fa2019-11-06 17:22:44 -07003685 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3686
3687 def testSymbolsTplSection(self):
3688 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3689 self._SetupSplElf('u_boot_binman_syms')
3690 self._SetupTplElf('u_boot_binman_syms')
3691 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003692 [0x04, 0x20, 0x10 + 0x3c, 0x04])
Simon Glass72555fa2019-11-06 17:22:44 -07003693
3694 def testSymbolsTplSectionX86(self):
3695 """Test binman can assign symbols in a section with end-at-4gb"""
3696 self._SetupSplElf('u_boot_binman_syms_x86')
3697 self._SetupTplElf('u_boot_binman_syms_x86')
3698 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003699 [0xffffff04, 0xffffff20, 0xffffff3c,
Simon Glass72555fa2019-11-06 17:22:44 -07003700 0x04])
Simon Glass3eb5b202019-08-24 07:23:00 -06003701
Simon Glass98c59572019-08-24 07:23:03 -06003702 def testPackX86RomIfwiSectiom(self):
3703 """Test that a section can be placed in an IFWI region"""
3704 self._SetupIfwi('fitimage.bin')
3705 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3706 self._CheckIfwi(data)
3707
Simon Glassba7985d2019-08-24 07:23:07 -06003708 def testPackFspM(self):
3709 """Test that an image with a FSP memory-init binary can be created"""
3710 data = self._DoReadFile('152_intel_fsp_m.dts')
3711 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3712
Simon Glass4d9086d2019-10-20 21:31:35 -06003713 def testPackFspS(self):
3714 """Test that an image with a FSP silicon-init binary can be created"""
3715 data = self._DoReadFile('153_intel_fsp_s.dts')
3716 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassba7985d2019-08-24 07:23:07 -06003717
Simon Glass9ea87b22019-10-20 21:31:36 -06003718 def testPackFspT(self):
3719 """Test that an image with a FSP temp-ram-init binary can be created"""
3720 data = self._DoReadFile('154_intel_fsp_t.dts')
3721 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3722
Simon Glass48f3aad2020-07-09 18:39:31 -06003723 def testMkimage(self):
3724 """Test using mkimage to build an image"""
3725 data = self._DoReadFile('156_mkimage.dts')
3726
3727 # Just check that the data appears in the file somewhere
3728 self.assertIn(U_BOOT_SPL_DATA, data)
3729
Simon Glass66152ce2022-01-09 20:14:09 -07003730 def testMkimageMissing(self):
3731 """Test that binman still produces an image if mkimage is missing"""
3732 with test_util.capture_sys_output() as (_, stderr):
3733 self._DoTestFile('156_mkimage.dts',
3734 force_missing_bintools='mkimage')
3735 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003736 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass66152ce2022-01-09 20:14:09 -07003737
Simon Glass5e560182020-07-09 18:39:36 -06003738 def testExtblob(self):
3739 """Test an image with an external blob"""
3740 data = self._DoReadFile('157_blob_ext.dts')
3741 self.assertEqual(REFCODE_DATA, data)
3742
3743 def testExtblobMissing(self):
3744 """Test an image with a missing external blob"""
3745 with self.assertRaises(ValueError) as e:
3746 self._DoReadFile('158_blob_ext_missing.dts')
3747 self.assertIn("Filename 'missing-file' not found in input path",
3748 str(e.exception))
3749
Simon Glass5d94cc62020-07-09 18:39:38 -06003750 def testExtblobMissingOk(self):
3751 """Test an image with an missing external blob that is allowed"""
Simon Glassa003cd32020-07-09 18:39:40 -06003752 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass6bce5dc2022-11-09 19:14:42 -07003753 ret = self._DoTestFile('158_blob_ext_missing.dts',
3754 allow_missing=True)
3755 self.assertEqual(103, ret)
Simon Glassa003cd32020-07-09 18:39:40 -06003756 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003757 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass6bce5dc2022-11-09 19:14:42 -07003758 self.assertIn('Some images are invalid', err)
3759
3760 def testExtblobMissingOkFlag(self):
3761 """Test an image with an missing external blob allowed with -W"""
3762 with test_util.capture_sys_output() as (stdout, stderr):
3763 ret = self._DoTestFile('158_blob_ext_missing.dts',
3764 allow_missing=True, ignore_missing=True)
3765 self.assertEqual(0, ret)
3766 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003767 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass6bce5dc2022-11-09 19:14:42 -07003768 self.assertIn('Some images are invalid', err)
Simon Glassa003cd32020-07-09 18:39:40 -06003769
3770 def testExtblobMissingOkSect(self):
3771 """Test an image with an missing external blob that is allowed"""
3772 with test_util.capture_sys_output() as (stdout, stderr):
3773 self._DoTestFile('159_blob_ext_missing_sect.dts',
3774 allow_missing=True)
3775 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003776 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext blob-ext2")
Simon Glass5d94cc62020-07-09 18:39:38 -06003777
Simon Glasse88cef92020-07-09 18:39:41 -06003778 def testPackX86RomMeMissingDesc(self):
3779 """Test that an missing Intel descriptor entry is allowed"""
Simon Glasse88cef92020-07-09 18:39:41 -06003780 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass14c596c2020-07-25 15:11:19 -06003781 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glasse88cef92020-07-09 18:39:41 -06003782 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003783 self.assertRegex(err, "Image 'image'.*missing.*: intel-descriptor")
Simon Glasse88cef92020-07-09 18:39:41 -06003784
3785 def testPackX86RomMissingIfwi(self):
3786 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3787 self._SetupIfwi('fitimage.bin')
3788 pathname = os.path.join(self._indir, 'fitimage.bin')
3789 os.remove(pathname)
3790 with test_util.capture_sys_output() as (stdout, stderr):
3791 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3792 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003793 self.assertRegex(err, "Image 'image'.*missing.*: intel-ifwi")
Simon Glasse88cef92020-07-09 18:39:41 -06003794
Simon Glass2a0fa982022-02-11 13:23:21 -07003795 def testPackOverlapZero(self):
Simon Glassd70829a2020-07-09 18:39:42 -06003796 """Test that zero-size overlapping regions are ignored"""
3797 self._DoTestFile('160_pack_overlap_zero.dts')
3798
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003799 def _CheckSimpleFitData(self, fit_data, kernel_data, fdt1_data):
Simon Glass45d556d2020-07-09 18:39:45 -06003800 # The data should be inside the FIT
3801 dtb = fdt.Fdt.FromData(fit_data)
3802 dtb.Scan()
3803 fnode = dtb.GetNode('/images/kernel')
3804 self.assertIn('data', fnode.props)
3805
3806 fname = os.path.join(self._indir, 'fit_data.fit')
Simon Glass80025522022-01-29 14:14:04 -07003807 tools.write_file(fname, fit_data)
3808 out = tools.run('dumpimage', '-l', fname)
Simon Glass45d556d2020-07-09 18:39:45 -06003809
3810 # Check a few features to make sure the plumbing works. We don't need
3811 # to test the operation of mkimage or dumpimage here. First convert the
3812 # output into a dict where the keys are the fields printed by dumpimage
3813 # and the values are a list of values for each field
3814 lines = out.splitlines()
3815
3816 # Converts "Compression: gzip compressed" into two groups:
3817 # 'Compression' and 'gzip compressed'
3818 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3819 vals = collections.defaultdict(list)
3820 for line in lines:
3821 mat = re_line.match(line)
3822 vals[mat.group(1)].append(mat.group(2))
3823
3824 self.assertEquals('FIT description: test-desc', lines[0])
3825 self.assertIn('Created:', lines[1])
3826 self.assertIn('Image 0 (kernel)', vals)
3827 self.assertIn('Hash value', vals)
3828 data_sizes = vals.get('Data Size')
3829 self.assertIsNotNone(data_sizes)
3830 self.assertEqual(2, len(data_sizes))
3831 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003832 self.assertEqual(len(kernel_data), int(data_sizes[0].split()[0]))
3833 self.assertEqual(len(fdt1_data), int(data_sizes[1].split()[0]))
3834
Alper Nebi Yasak1a0ee0f2022-03-27 18:31:47 +03003835 # Check if entry listing correctly omits /images/
3836 image = control.images['image']
3837 fit_entry = image.GetEntries()['fit']
3838 subentries = list(fit_entry.GetEntries().keys())
3839 expected = ['kernel', 'fdt-1']
3840 self.assertEqual(expected, subentries)
3841
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003842 def testSimpleFit(self):
3843 """Test an image with a FIT inside"""
3844 data = self._DoReadFile('161_fit.dts')
3845 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3846 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3847 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3848
3849 self._CheckSimpleFitData(fit_data, U_BOOT_DATA, U_BOOT_SPL_DTB_DATA)
3850
3851 def testSimpleFitExpandsSubentries(self):
3852 """Test that FIT images expand their subentries"""
3853 data = self._DoReadFileDtb('161_fit.dts', use_expanded=True)[0]
3854 self.assertEqual(U_BOOT_EXP_DATA, data[:len(U_BOOT_EXP_DATA)])
3855 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3856 fit_data = data[len(U_BOOT_EXP_DATA):-len(U_BOOT_NODTB_DATA)]
3857
3858 self._CheckSimpleFitData(fit_data, U_BOOT_EXP_DATA, U_BOOT_SPL_DTB_DATA)
Simon Glass45d556d2020-07-09 18:39:45 -06003859
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003860 def testSimpleFitImagePos(self):
3861 """Test that we have correct image-pos for FIT subentries"""
3862 data, _, _, out_dtb_fname = self._DoReadFileDtb('161_fit.dts',
3863 update_dtb=True)
3864 dtb = fdt.Fdt(out_dtb_fname)
3865 dtb.Scan()
3866 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3867
Simon Glassb7bad182022-03-05 20:19:01 -07003868 self.maxDiff = None
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003869 self.assertEqual({
3870 'image-pos': 0,
3871 'offset': 0,
3872 'size': 1890,
3873
3874 'u-boot:image-pos': 0,
3875 'u-boot:offset': 0,
3876 'u-boot:size': 4,
3877
3878 'fit:image-pos': 4,
3879 'fit:offset': 4,
3880 'fit:size': 1840,
3881
Simon Glassb7bad182022-03-05 20:19:01 -07003882 'fit/images/kernel:image-pos': 304,
3883 'fit/images/kernel:offset': 300,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003884 'fit/images/kernel:size': 4,
3885
Simon Glassb7bad182022-03-05 20:19:01 -07003886 'fit/images/kernel/u-boot:image-pos': 304,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003887 'fit/images/kernel/u-boot:offset': 0,
3888 'fit/images/kernel/u-boot:size': 4,
3889
Simon Glassb7bad182022-03-05 20:19:01 -07003890 'fit/images/fdt-1:image-pos': 552,
3891 'fit/images/fdt-1:offset': 548,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003892 'fit/images/fdt-1:size': 6,
3893
Simon Glassb7bad182022-03-05 20:19:01 -07003894 'fit/images/fdt-1/u-boot-spl-dtb:image-pos': 552,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003895 'fit/images/fdt-1/u-boot-spl-dtb:offset': 0,
3896 'fit/images/fdt-1/u-boot-spl-dtb:size': 6,
3897
3898 'u-boot-nodtb:image-pos': 1844,
3899 'u-boot-nodtb:offset': 1844,
3900 'u-boot-nodtb:size': 46,
3901 }, props)
3902
3903 # Actually check the data is where we think it is
3904 for node, expected in [
3905 ("u-boot", U_BOOT_DATA),
3906 ("fit/images/kernel", U_BOOT_DATA),
3907 ("fit/images/kernel/u-boot", U_BOOT_DATA),
3908 ("fit/images/fdt-1", U_BOOT_SPL_DTB_DATA),
3909 ("fit/images/fdt-1/u-boot-spl-dtb", U_BOOT_SPL_DTB_DATA),
3910 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
3911 ]:
3912 image_pos = props[f"{node}:image-pos"]
3913 size = props[f"{node}:size"]
3914 self.assertEqual(len(expected), size)
3915 self.assertEqual(expected, data[image_pos:image_pos+size])
3916
Simon Glass45d556d2020-07-09 18:39:45 -06003917 def testFitExternal(self):
Simon Glass31ee50f2020-09-01 05:13:55 -06003918 """Test an image with an FIT with external images"""
Simon Glass45d556d2020-07-09 18:39:45 -06003919 data = self._DoReadFile('162_fit_external.dts')
3920 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3921
Simon Glass7932c882022-01-09 20:13:39 -07003922 # Size of the external-data region as set up by mkimage
3923 external_data_size = len(U_BOOT_DATA) + 2
3924 expected_size = (len(U_BOOT_DATA) + 0x400 +
Simon Glass80025522022-01-29 14:14:04 -07003925 tools.align(external_data_size, 4) +
Simon Glass7932c882022-01-09 20:13:39 -07003926 len(U_BOOT_NODTB_DATA))
3927
Simon Glass45d556d2020-07-09 18:39:45 -06003928 # The data should be outside the FIT
3929 dtb = fdt.Fdt.FromData(fit_data)
3930 dtb.Scan()
3931 fnode = dtb.GetNode('/images/kernel')
3932 self.assertNotIn('data', fnode.props)
Simon Glass7932c882022-01-09 20:13:39 -07003933 self.assertEqual(len(U_BOOT_DATA),
3934 fdt_util.fdt32_to_cpu(fnode.props['data-size'].value))
3935 fit_pos = 0x400;
3936 self.assertEqual(
3937 fit_pos,
3938 fdt_util.fdt32_to_cpu(fnode.props['data-position'].value))
3939
3940 self.assertEquals(expected_size, len(data))
3941 actual_pos = len(U_BOOT_DATA) + fit_pos
3942 self.assertEqual(U_BOOT_DATA + b'aa',
3943 data[actual_pos:actual_pos + external_data_size])
Simon Glassfb30e292019-07-20 12:23:51 -06003944
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003945 def testFitExternalImagePos(self):
3946 """Test that we have correct image-pos for external FIT subentries"""
3947 data, _, _, out_dtb_fname = self._DoReadFileDtb('162_fit_external.dts',
3948 update_dtb=True)
3949 dtb = fdt.Fdt(out_dtb_fname)
3950 dtb.Scan()
3951 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3952
3953 self.assertEqual({
3954 'image-pos': 0,
3955 'offset': 0,
3956 'size': 1082,
3957
3958 'u-boot:image-pos': 0,
3959 'u-boot:offset': 0,
3960 'u-boot:size': 4,
3961
3962 'fit:size': 1032,
3963 'fit:offset': 4,
3964 'fit:image-pos': 4,
3965
3966 'fit/images/kernel:size': 4,
3967 'fit/images/kernel:offset': 1024,
3968 'fit/images/kernel:image-pos': 1028,
3969
3970 'fit/images/kernel/u-boot:size': 4,
3971 'fit/images/kernel/u-boot:offset': 0,
3972 'fit/images/kernel/u-boot:image-pos': 1028,
3973
3974 'fit/images/fdt-1:size': 2,
3975 'fit/images/fdt-1:offset': 1028,
3976 'fit/images/fdt-1:image-pos': 1032,
3977
3978 'fit/images/fdt-1/_testing:size': 2,
3979 'fit/images/fdt-1/_testing:offset': 0,
3980 'fit/images/fdt-1/_testing:image-pos': 1032,
3981
3982 'u-boot-nodtb:image-pos': 1036,
3983 'u-boot-nodtb:offset': 1036,
3984 'u-boot-nodtb:size': 46,
3985 }, props)
3986
3987 # Actually check the data is where we think it is
3988 for node, expected in [
3989 ("u-boot", U_BOOT_DATA),
3990 ("fit/images/kernel", U_BOOT_DATA),
3991 ("fit/images/kernel/u-boot", U_BOOT_DATA),
3992 ("fit/images/fdt-1", b'aa'),
3993 ("fit/images/fdt-1/_testing", b'aa'),
3994 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
3995 ]:
3996 image_pos = props[f"{node}:image-pos"]
3997 size = props[f"{node}:size"]
3998 self.assertEqual(len(expected), size)
3999 self.assertEqual(expected, data[image_pos:image_pos+size])
4000
Simon Glass66152ce2022-01-09 20:14:09 -07004001 def testFitMissing(self):
Simon Glass039d65f2023-03-02 17:02:43 -07004002 """Test that binman complains if mkimage is missing"""
4003 with self.assertRaises(ValueError) as e:
4004 self._DoTestFile('162_fit_external.dts',
4005 force_missing_bintools='mkimage')
4006 self.assertIn("Node '/binman/fit': Missing tool: 'mkimage'",
4007 str(e.exception))
4008
4009 def testFitMissingOK(self):
Simon Glass66152ce2022-01-09 20:14:09 -07004010 """Test that binman still produces a FIT image if mkimage is missing"""
4011 with test_util.capture_sys_output() as (_, stderr):
Simon Glass039d65f2023-03-02 17:02:43 -07004012 self._DoTestFile('162_fit_external.dts', allow_missing=True,
Simon Glass66152ce2022-01-09 20:14:09 -07004013 force_missing_bintools='mkimage')
4014 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004015 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass66152ce2022-01-09 20:14:09 -07004016
Alper Nebi Yasak6aae2392020-08-31 12:58:18 +03004017 def testSectionIgnoreHashSignature(self):
4018 """Test that sections ignore hash, signature nodes for its data"""
4019 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
4020 expected = (U_BOOT_DATA + U_BOOT_DATA)
4021 self.assertEqual(expected, data)
4022
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03004023 def testPadInSections(self):
4024 """Test pad-before, pad-after for entries in sections"""
Simon Glassd12599d2020-10-26 17:40:09 -06004025 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4026 '166_pad_in_sections.dts', update_dtb=True)
Simon Glass80025522022-01-29 14:14:04 -07004027 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4028 U_BOOT_DATA + tools.get_bytes(ord('!'), 6) +
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03004029 U_BOOT_DATA)
4030 self.assertEqual(expected, data)
4031
Simon Glassd12599d2020-10-26 17:40:09 -06004032 dtb = fdt.Fdt(out_dtb_fname)
4033 dtb.Scan()
4034 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
4035 expected = {
4036 'image-pos': 0,
4037 'offset': 0,
4038 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
4039
4040 'section:image-pos': 0,
4041 'section:offset': 0,
4042 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
4043
4044 'section/before:image-pos': 0,
4045 'section/before:offset': 0,
4046 'section/before:size': len(U_BOOT_DATA),
4047
4048 'section/u-boot:image-pos': 4,
4049 'section/u-boot:offset': 4,
4050 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
4051
4052 'section/after:image-pos': 26,
4053 'section/after:offset': 26,
4054 'section/after:size': len(U_BOOT_DATA),
4055 }
4056 self.assertEqual(expected, props)
4057
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004058 def testFitImageSubentryAlignment(self):
4059 """Test relative alignability of FIT image subentries"""
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03004060 self._SetupSplElf()
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004061 entry_args = {
4062 'test-id': TEXT_DATA,
4063 }
4064 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
4065 entry_args=entry_args)
4066 dtb = fdt.Fdt.FromData(data)
4067 dtb.Scan()
4068
4069 node = dtb.GetNode('/images/kernel')
4070 data = dtb.GetProps(node)["data"].bytes
4071 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
Simon Glass80025522022-01-29 14:14:04 -07004072 expected = (tools.get_bytes(0, 0x20) + U_BOOT_SPL_DATA +
4073 tools.get_bytes(0, align_pad) + U_BOOT_DATA)
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004074 self.assertEqual(expected, data)
4075
4076 node = dtb.GetNode('/images/fdt-1')
4077 data = dtb.GetProps(node)["data"].bytes
Simon Glass80025522022-01-29 14:14:04 -07004078 expected = (U_BOOT_SPL_DTB_DATA + tools.get_bytes(0, 20) +
4079 tools.to_bytes(TEXT_DATA) + tools.get_bytes(0, 30) +
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004080 U_BOOT_DTB_DATA)
4081 self.assertEqual(expected, data)
4082
4083 def testFitExtblobMissingOk(self):
4084 """Test a FIT with a missing external blob that is allowed"""
4085 with test_util.capture_sys_output() as (stdout, stderr):
4086 self._DoTestFile('168_fit_missing_blob.dts',
4087 allow_missing=True)
4088 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004089 self.assertRegex(err, "Image 'image'.*missing.*: atf-bl31")
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004090
Simon Glass21db0ff2020-09-01 05:13:54 -06004091 def testBlobNamedByArgMissing(self):
4092 """Test handling of a missing entry arg"""
4093 with self.assertRaises(ValueError) as e:
4094 self._DoReadFile('068_blob_named_by_arg.dts')
4095 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
4096 str(e.exception))
4097
Simon Glass559c4de2020-09-01 05:13:58 -06004098 def testPackBl31(self):
4099 """Test that an image with an ATF BL31 binary can be created"""
4100 data = self._DoReadFile('169_atf_bl31.dts')
4101 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
4102
Samuel Holland9d8cc632020-10-21 21:12:15 -05004103 def testPackScp(self):
4104 """Test that an image with an SCP binary can be created"""
4105 data = self._DoReadFile('172_scp.dts')
4106 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
4107
Simon Glassa435cd12020-09-01 05:13:59 -06004108 def testFitFdt(self):
4109 """Test an image with an FIT with multiple FDT images"""
4110 def _CheckFdt(seq, expected_data):
4111 """Check the FDT nodes
4112
4113 Args:
4114 seq: Sequence number to check (0 or 1)
4115 expected_data: Expected contents of 'data' property
4116 """
4117 name = 'fdt-%d' % seq
4118 fnode = dtb.GetNode('/images/%s' % name)
4119 self.assertIsNotNone(fnode)
4120 self.assertEqual({'description','type', 'compression', 'data'},
4121 set(fnode.props.keys()))
4122 self.assertEqual(expected_data, fnode.props['data'].bytes)
4123 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
4124 fnode.props['description'].value)
Jan Kiszkaa1419df2022-02-28 17:06:20 +01004125 self.assertEqual(fnode.subnodes[0].name, 'hash')
Simon Glassa435cd12020-09-01 05:13:59 -06004126
4127 def _CheckConfig(seq, expected_data):
4128 """Check the configuration nodes
4129
4130 Args:
4131 seq: Sequence number to check (0 or 1)
4132 expected_data: Expected contents of 'data' property
4133 """
4134 cnode = dtb.GetNode('/configurations')
4135 self.assertIn('default', cnode.props)
Simon Glass1032acc2020-09-06 10:39:08 -06004136 self.assertEqual('config-2', cnode.props['default'].value)
Simon Glassa435cd12020-09-01 05:13:59 -06004137
4138 name = 'config-%d' % seq
4139 fnode = dtb.GetNode('/configurations/%s' % name)
4140 self.assertIsNotNone(fnode)
4141 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
4142 set(fnode.props.keys()))
4143 self.assertEqual('conf-test-fdt%d.dtb' % seq,
4144 fnode.props['description'].value)
4145 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
4146
4147 entry_args = {
4148 'of-list': 'test-fdt1 test-fdt2',
Simon Glass1032acc2020-09-06 10:39:08 -06004149 'default-dt': 'test-fdt2',
Simon Glassa435cd12020-09-01 05:13:59 -06004150 }
4151 data = self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004152 '170_fit_fdt.dts',
Simon Glassa435cd12020-09-01 05:13:59 -06004153 entry_args=entry_args,
4154 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4155 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4156 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4157
4158 dtb = fdt.Fdt.FromData(fit_data)
4159 dtb.Scan()
4160 fnode = dtb.GetNode('/images/kernel')
4161 self.assertIn('data', fnode.props)
4162
4163 # Check all the properties in fdt-1 and fdt-2
4164 _CheckFdt(1, TEST_FDT1_DATA)
4165 _CheckFdt(2, TEST_FDT2_DATA)
4166
4167 # Check configurations
4168 _CheckConfig(1, TEST_FDT1_DATA)
4169 _CheckConfig(2, TEST_FDT2_DATA)
4170
4171 def testFitFdtMissingList(self):
4172 """Test handling of a missing 'of-list' entry arg"""
4173 with self.assertRaises(ValueError) as e:
Bin Meng16cf5662021-05-10 20:23:32 +08004174 self._DoReadFile('170_fit_fdt.dts')
Simon Glassa435cd12020-09-01 05:13:59 -06004175 self.assertIn("Generator node requires 'of-list' entry argument",
4176 str(e.exception))
4177
4178 def testFitFdtEmptyList(self):
4179 """Test handling of an empty 'of-list' entry arg"""
4180 entry_args = {
4181 'of-list': '',
4182 }
4183 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
4184
4185 def testFitFdtMissingProp(self):
4186 """Test handling of a missing 'fit,fdt-list' property"""
4187 with self.assertRaises(ValueError) as e:
4188 self._DoReadFile('171_fit_fdt_missing_prop.dts')
4189 self.assertIn("Generator node requires 'fit,fdt-list' property",
4190 str(e.exception))
Simon Glass559c4de2020-09-01 05:13:58 -06004191
Simon Glass1032acc2020-09-06 10:39:08 -06004192 def testFitFdtMissing(self):
4193 """Test handling of a missing 'default-dt' entry arg"""
4194 entry_args = {
4195 'of-list': 'test-fdt1 test-fdt2',
4196 }
4197 with self.assertRaises(ValueError) as e:
4198 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004199 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004200 entry_args=entry_args,
4201 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4202 self.assertIn("Generated 'default' node requires default-dt entry argument",
4203 str(e.exception))
4204
4205 def testFitFdtNotInList(self):
4206 """Test handling of a default-dt that is not in the of-list"""
4207 entry_args = {
4208 'of-list': 'test-fdt1 test-fdt2',
4209 'default-dt': 'test-fdt3',
4210 }
4211 with self.assertRaises(ValueError) as e:
4212 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004213 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004214 entry_args=entry_args,
4215 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4216 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
4217 str(e.exception))
4218
Simon Glassa820af72020-09-06 10:39:09 -06004219 def testFitExtblobMissingHelp(self):
4220 """Test display of help messages when an external blob is missing"""
4221 control.missing_blob_help = control._ReadMissingBlobHelp()
4222 control.missing_blob_help['wibble'] = 'Wibble test'
4223 control.missing_blob_help['another'] = 'Another test'
4224 with test_util.capture_sys_output() as (stdout, stderr):
4225 self._DoTestFile('168_fit_missing_blob.dts',
4226 allow_missing=True)
4227 err = stderr.getvalue()
4228
4229 # We can get the tag from the name, the type or the missing-msg
4230 # property. Check all three.
4231 self.assertIn('You may need to build ARM Trusted', err)
4232 self.assertIn('Wibble test', err)
4233 self.assertIn('Another test', err)
4234
Simon Glass6f1f4d42020-09-06 10:35:32 -06004235 def testMissingBlob(self):
4236 """Test handling of a blob containing a missing file"""
4237 with self.assertRaises(ValueError) as e:
4238 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
4239 self.assertIn("Filename 'missing' not found in input path",
4240 str(e.exception))
4241
Simon Glassa0729502020-09-06 10:35:33 -06004242 def testEnvironment(self):
4243 """Test adding a U-Boot environment"""
4244 data = self._DoReadFile('174_env.dts')
4245 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
4246 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4247 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4248 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
4249 env)
4250
4251 def testEnvironmentNoSize(self):
4252 """Test that a missing 'size' property is detected"""
4253 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004254 self._DoTestFile('175_env_no_size.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004255 self.assertIn("'u-boot-env' entry must have a size property",
4256 str(e.exception))
4257
4258 def testEnvironmentTooSmall(self):
4259 """Test handling of an environment that does not fit"""
4260 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004261 self._DoTestFile('176_env_too_small.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004262
4263 # checksum, start byte, environment with \0 terminator, final \0
4264 need = 4 + 1 + len(ENV_DATA) + 1 + 1
4265 short = need - 0x8
4266 self.assertIn("too small to hold data (need %#x more bytes)" % short,
4267 str(e.exception))
4268
Simon Glassd1fdf752020-10-26 17:40:01 -06004269 def testSkipAtStart(self):
4270 """Test handling of skip-at-start section"""
4271 data = self._DoReadFile('177_skip_at_start.dts')
4272 self.assertEqual(U_BOOT_DATA, data)
4273
4274 image = control.images['image']
4275 entries = image.GetEntries()
4276 section = entries['section']
4277 self.assertEqual(0, section.offset)
4278 self.assertEqual(len(U_BOOT_DATA), section.size)
4279 self.assertEqual(U_BOOT_DATA, section.GetData())
4280
4281 entry = section.GetEntries()['u-boot']
4282 self.assertEqual(16, entry.offset)
4283 self.assertEqual(len(U_BOOT_DATA), entry.size)
4284 self.assertEqual(U_BOOT_DATA, entry.data)
4285
4286 def testSkipAtStartPad(self):
4287 """Test handling of skip-at-start section with padded entry"""
4288 data = self._DoReadFile('178_skip_at_start_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004289 before = tools.get_bytes(0, 8)
4290 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004291 all = before + U_BOOT_DATA + after
4292 self.assertEqual(all, data)
4293
4294 image = control.images['image']
4295 entries = image.GetEntries()
4296 section = entries['section']
4297 self.assertEqual(0, section.offset)
4298 self.assertEqual(len(all), section.size)
4299 self.assertEqual(all, section.GetData())
4300
4301 entry = section.GetEntries()['u-boot']
4302 self.assertEqual(16, entry.offset)
4303 self.assertEqual(len(all), entry.size)
4304 self.assertEqual(U_BOOT_DATA, entry.data)
4305
4306 def testSkipAtStartSectionPad(self):
4307 """Test handling of skip-at-start section with padding"""
4308 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004309 before = tools.get_bytes(0, 8)
4310 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004311 all = before + U_BOOT_DATA + after
Simon Glass510ef0f2020-10-26 17:40:13 -06004312 self.assertEqual(all, data)
Simon Glassd1fdf752020-10-26 17:40:01 -06004313
4314 image = control.images['image']
4315 entries = image.GetEntries()
4316 section = entries['section']
4317 self.assertEqual(0, section.offset)
4318 self.assertEqual(len(all), section.size)
Simon Glass72eeff12020-10-26 17:40:16 -06004319 self.assertEqual(U_BOOT_DATA, section.data)
Simon Glass510ef0f2020-10-26 17:40:13 -06004320 self.assertEqual(all, section.GetPaddedData())
Simon Glassd1fdf752020-10-26 17:40:01 -06004321
4322 entry = section.GetEntries()['u-boot']
4323 self.assertEqual(16, entry.offset)
4324 self.assertEqual(len(U_BOOT_DATA), entry.size)
4325 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassa0729502020-09-06 10:35:33 -06004326
Simon Glassbb395742020-10-26 17:40:14 -06004327 def testSectionPad(self):
4328 """Testing padding with sections"""
4329 data = self._DoReadFile('180_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004330 expected = (tools.get_bytes(ord('&'), 3) +
4331 tools.get_bytes(ord('!'), 5) +
Simon Glassbb395742020-10-26 17:40:14 -06004332 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004333 tools.get_bytes(ord('!'), 1) +
4334 tools.get_bytes(ord('&'), 2))
Simon Glassbb395742020-10-26 17:40:14 -06004335 self.assertEqual(expected, data)
4336
4337 def testSectionAlign(self):
4338 """Testing alignment with sections"""
4339 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4340 expected = (b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004341 tools.get_bytes(ord('&'), 1) + # padding to section align
Simon Glassbb395742020-10-26 17:40:14 -06004342 b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004343 tools.get_bytes(ord('!'), 3) + # padding to u-boot align
Simon Glassbb395742020-10-26 17:40:14 -06004344 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004345 tools.get_bytes(ord('!'), 4) + # padding to u-boot size
4346 tools.get_bytes(ord('!'), 4)) # padding to section size
Simon Glassbb395742020-10-26 17:40:14 -06004347 self.assertEqual(expected, data)
4348
Simon Glassd92c8362020-10-26 17:40:25 -06004349 def testCompressImage(self):
4350 """Test compression of the entire image"""
4351 self._CheckLz4()
4352 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4353 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4354 dtb = fdt.Fdt(out_dtb_fname)
4355 dtb.Scan()
4356 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4357 'uncomp-size'])
4358 orig = self._decompress(data)
4359 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4360
4361 # Do a sanity check on various fields
4362 image = control.images['image']
4363 entries = image.GetEntries()
4364 self.assertEqual(2, len(entries))
4365
4366 entry = entries['blob']
4367 self.assertEqual(COMPRESS_DATA, entry.data)
4368 self.assertEqual(len(COMPRESS_DATA), entry.size)
4369
4370 entry = entries['u-boot']
4371 self.assertEqual(U_BOOT_DATA, entry.data)
4372 self.assertEqual(len(U_BOOT_DATA), entry.size)
4373
4374 self.assertEqual(len(data), image.size)
4375 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4376 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4377 orig = self._decompress(image.data)
4378 self.assertEqual(orig, image.uncomp_data)
4379
4380 expected = {
4381 'blob:offset': 0,
4382 'blob:size': len(COMPRESS_DATA),
4383 'u-boot:offset': len(COMPRESS_DATA),
4384 'u-boot:size': len(U_BOOT_DATA),
4385 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4386 'offset': 0,
4387 'image-pos': 0,
4388 'size': len(data),
4389 }
4390 self.assertEqual(expected, props)
4391
4392 def testCompressImageLess(self):
4393 """Test compression where compression reduces the image size"""
4394 self._CheckLz4()
4395 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4396 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4397 dtb = fdt.Fdt(out_dtb_fname)
4398 dtb.Scan()
4399 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4400 'uncomp-size'])
4401 orig = self._decompress(data)
4402
4403 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
4404
4405 # Do a sanity check on various fields
4406 image = control.images['image']
4407 entries = image.GetEntries()
4408 self.assertEqual(2, len(entries))
4409
4410 entry = entries['blob']
4411 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4412 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4413
4414 entry = entries['u-boot']
4415 self.assertEqual(U_BOOT_DATA, entry.data)
4416 self.assertEqual(len(U_BOOT_DATA), entry.size)
4417
4418 self.assertEqual(len(data), image.size)
4419 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4420 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4421 image.uncomp_size)
4422 orig = self._decompress(image.data)
4423 self.assertEqual(orig, image.uncomp_data)
4424
4425 expected = {
4426 'blob:offset': 0,
4427 'blob:size': len(COMPRESS_DATA_BIG),
4428 'u-boot:offset': len(COMPRESS_DATA_BIG),
4429 'u-boot:size': len(U_BOOT_DATA),
4430 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4431 'offset': 0,
4432 'image-pos': 0,
4433 'size': len(data),
4434 }
4435 self.assertEqual(expected, props)
4436
4437 def testCompressSectionSize(self):
4438 """Test compression of a section with a fixed size"""
4439 self._CheckLz4()
4440 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4441 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4442 dtb = fdt.Fdt(out_dtb_fname)
4443 dtb.Scan()
4444 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4445 'uncomp-size'])
4446 orig = self._decompress(data)
4447 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4448 expected = {
4449 'section/blob:offset': 0,
4450 'section/blob:size': len(COMPRESS_DATA),
4451 'section/u-boot:offset': len(COMPRESS_DATA),
4452 'section/u-boot:size': len(U_BOOT_DATA),
4453 'section:offset': 0,
4454 'section:image-pos': 0,
4455 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4456 'section:size': 0x30,
4457 'offset': 0,
4458 'image-pos': 0,
4459 'size': 0x30,
4460 }
4461 self.assertEqual(expected, props)
4462
4463 def testCompressSection(self):
4464 """Test compression of a section with no fixed size"""
4465 self._CheckLz4()
4466 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4467 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4468 dtb = fdt.Fdt(out_dtb_fname)
4469 dtb.Scan()
4470 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4471 'uncomp-size'])
4472 orig = self._decompress(data)
4473 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4474 expected = {
4475 'section/blob:offset': 0,
4476 'section/blob:size': len(COMPRESS_DATA),
4477 'section/u-boot:offset': len(COMPRESS_DATA),
4478 'section/u-boot:size': len(U_BOOT_DATA),
4479 'section:offset': 0,
4480 'section:image-pos': 0,
4481 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4482 'section:size': len(data),
4483 'offset': 0,
4484 'image-pos': 0,
4485 'size': len(data),
4486 }
4487 self.assertEqual(expected, props)
4488
Stefan Herbrechtsmeier94813a02022-08-19 16:25:31 +02004489 def testLz4Missing(self):
4490 """Test that binman still produces an image if lz4 is missing"""
4491 with test_util.capture_sys_output() as (_, stderr):
4492 self._DoTestFile('185_compress_section.dts',
4493 force_missing_bintools='lz4')
4494 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004495 self.assertRegex(err, "Image 'image'.*missing bintools.*: lz4")
Stefan Herbrechtsmeier94813a02022-08-19 16:25:31 +02004496
Simon Glassd92c8362020-10-26 17:40:25 -06004497 def testCompressExtra(self):
4498 """Test compression of a section with no fixed size"""
4499 self._CheckLz4()
4500 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4501 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4502 dtb = fdt.Fdt(out_dtb_fname)
4503 dtb.Scan()
4504 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4505 'uncomp-size'])
4506
4507 base = data[len(U_BOOT_DATA):]
4508 self.assertEquals(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
4509 rest = base[len(U_BOOT_DATA):]
4510
4511 # Check compressed data
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02004512 bintool = self.comp_bintools['lz4']
4513 expect1 = bintool.compress(COMPRESS_DATA + U_BOOT_DATA)
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004514 data1 = rest[:len(expect1)]
4515 section1 = self._decompress(data1)
4516 self.assertEquals(expect1, data1)
Simon Glassd92c8362020-10-26 17:40:25 -06004517 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, section1)
4518 rest1 = rest[len(expect1):]
4519
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02004520 expect2 = bintool.compress(COMPRESS_DATA + COMPRESS_DATA)
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004521 data2 = rest1[:len(expect2)]
4522 section2 = self._decompress(data2)
4523 self.assertEquals(expect2, data2)
Simon Glassd92c8362020-10-26 17:40:25 -06004524 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA, section2)
4525 rest2 = rest1[len(expect2):]
4526
4527 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4528 len(expect2) + len(U_BOOT_DATA))
4529 #self.assertEquals(expect_size, len(data))
4530
4531 #self.assertEquals(U_BOOT_DATA, rest2)
4532
4533 self.maxDiff = None
4534 expected = {
4535 'u-boot:offset': 0,
4536 'u-boot:image-pos': 0,
4537 'u-boot:size': len(U_BOOT_DATA),
4538
4539 'base:offset': len(U_BOOT_DATA),
4540 'base:image-pos': len(U_BOOT_DATA),
4541 'base:size': len(data) - len(U_BOOT_DATA),
4542 'base/u-boot:offset': 0,
4543 'base/u-boot:image-pos': len(U_BOOT_DATA),
4544 'base/u-boot:size': len(U_BOOT_DATA),
4545 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4546 len(expect2),
4547 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4548 len(expect2),
4549 'base/u-boot2:size': len(U_BOOT_DATA),
4550
4551 'base/section:offset': len(U_BOOT_DATA),
4552 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4553 'base/section:size': len(expect1),
4554 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4555 'base/section/blob:offset': 0,
4556 'base/section/blob:size': len(COMPRESS_DATA),
4557 'base/section/u-boot:offset': len(COMPRESS_DATA),
4558 'base/section/u-boot:size': len(U_BOOT_DATA),
4559
4560 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4561 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4562 'base/section2:size': len(expect2),
4563 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4564 'base/section2/blob:offset': 0,
4565 'base/section2/blob:size': len(COMPRESS_DATA),
4566 'base/section2/blob2:offset': len(COMPRESS_DATA),
4567 'base/section2/blob2:size': len(COMPRESS_DATA),
4568
4569 'offset': 0,
4570 'image-pos': 0,
4571 'size': len(data),
4572 }
4573 self.assertEqual(expected, props)
4574
Simon Glassecbe4732021-01-06 21:35:15 -07004575 def testSymbolsSubsection(self):
4576 """Test binman can assign symbols from a subsection"""
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03004577 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glassecbe4732021-01-06 21:35:15 -07004578
Simon Glass3fb25402021-01-06 21:35:16 -07004579 def testReadImageEntryArg(self):
4580 """Test reading an image that would need an entry arg to generate"""
4581 entry_args = {
4582 'cros-ec-rw-path': 'ecrw.bin',
4583 }
4584 data = self.data = self._DoReadFileDtb(
4585 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4586 entry_args=entry_args)
4587
Simon Glass80025522022-01-29 14:14:04 -07004588 image_fname = tools.get_output_filename('image.bin')
Simon Glass3fb25402021-01-06 21:35:16 -07004589 orig_image = control.images['image']
4590
4591 # This should not generate an error about the missing 'cros-ec-rw-path'
4592 # since we are reading the image from a file. Compare with
4593 # testEntryArgsRequired()
4594 image = Image.FromFile(image_fname)
4595 self.assertEqual(orig_image.GetEntries().keys(),
4596 image.GetEntries().keys())
4597
Simon Glassa2af7302021-01-06 21:35:18 -07004598 def testFilesAlign(self):
4599 """Test alignment with files"""
4600 data = self._DoReadFile('190_files_align.dts')
4601
4602 # The first string is 15 bytes so will align to 16
4603 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4604 self.assertEqual(expect, data)
4605
Simon Glassdb84b562021-01-06 21:35:19 -07004606 def testReadImageSkip(self):
4607 """Test reading an image and accessing its FDT map"""
4608 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
Simon Glass80025522022-01-29 14:14:04 -07004609 image_fname = tools.get_output_filename('image.bin')
Simon Glassdb84b562021-01-06 21:35:19 -07004610 orig_image = control.images['image']
4611 image = Image.FromFile(image_fname)
4612 self.assertEqual(orig_image.GetEntries().keys(),
4613 image.GetEntries().keys())
4614
4615 orig_entry = orig_image.GetEntries()['fdtmap']
4616 entry = image.GetEntries()['fdtmap']
4617 self.assertEqual(orig_entry.offset, entry.offset)
4618 self.assertEqual(orig_entry.size, entry.size)
4619 self.assertEqual(16, entry.image_pos)
4620
4621 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4622
4623 self.assertEquals(U_BOOT_DATA, u_boot.ReadData())
4624
Simon Glassc98de972021-03-18 20:24:57 +13004625 def testTplNoDtb(self):
4626 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12004627 self._SetupTplElf()
Simon Glassc98de972021-03-18 20:24:57 +13004628 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4629 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4630 data[:len(U_BOOT_TPL_NODTB_DATA)])
4631
Simon Glass63f41d42021-03-18 20:24:58 +13004632 def testTplBssPad(self):
4633 """Test that we can pad TPL's BSS with zeros"""
4634 # ELF file with a '__bss_size' symbol
4635 self._SetupTplElf()
4636 data = self._DoReadFile('193_tpl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004637 self.assertEqual(U_BOOT_TPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glass63f41d42021-03-18 20:24:58 +13004638 data)
4639
4640 def testTplBssPadMissing(self):
4641 """Test that a missing symbol is detected"""
4642 self._SetupTplElf('u_boot_ucode_ptr')
4643 with self.assertRaises(ValueError) as e:
4644 self._DoReadFile('193_tpl_bss_pad.dts')
4645 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4646 str(e.exception))
4647
Simon Glass718b5292021-03-18 20:25:07 +13004648 def checkDtbSizes(self, data, pad_len, start):
4649 """Check the size arguments in a dtb embedded in an image
4650
4651 Args:
4652 data: The image data
4653 pad_len: Length of the pad section in the image, in bytes
4654 start: Start offset of the devicetree to examine, within the image
4655
4656 Returns:
4657 Size of the devicetree in bytes
4658 """
4659 dtb_data = data[start:]
4660 dtb = fdt.Fdt.FromData(dtb_data)
4661 fdt_size = dtb.GetFdtObj().totalsize()
4662 dtb.Scan()
4663 props = self._GetPropTree(dtb, 'size')
4664 self.assertEqual({
4665 'size': len(data),
4666 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4667 'u-boot-spl/u-boot-spl-dtb:size': 801,
4668 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4669 'u-boot-spl:size': 860,
4670 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4671 'u-boot/u-boot-dtb:size': 781,
4672 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4673 'u-boot:size': 827,
4674 }, props)
4675 return fdt_size
4676
4677 def testExpanded(self):
4678 """Test that an expanded entry type is selected when needed"""
4679 self._SetupSplElf()
4680 self._SetupTplElf()
4681
4682 # SPL has a devicetree, TPL does not
4683 entry_args = {
4684 'spl-dtb': '1',
4685 'spl-bss-pad': 'y',
4686 'tpl-dtb': '',
4687 }
4688 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4689 entry_args=entry_args)
4690 image = control.images['image']
4691 entries = image.GetEntries()
4692 self.assertEqual(3, len(entries))
4693
4694 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4695 self.assertIn('u-boot', entries)
4696 entry = entries['u-boot']
4697 self.assertEqual('u-boot-expanded', entry.etype)
4698 subent = entry.GetEntries()
4699 self.assertEqual(2, len(subent))
4700 self.assertIn('u-boot-nodtb', subent)
4701 self.assertIn('u-boot-dtb', subent)
4702
4703 # Second, u-boot-spl, which should be expanded into three parts
4704 self.assertIn('u-boot-spl', entries)
4705 entry = entries['u-boot-spl']
4706 self.assertEqual('u-boot-spl-expanded', entry.etype)
4707 subent = entry.GetEntries()
4708 self.assertEqual(3, len(subent))
4709 self.assertIn('u-boot-spl-nodtb', subent)
4710 self.assertIn('u-boot-spl-bss-pad', subent)
4711 self.assertIn('u-boot-spl-dtb', subent)
4712
4713 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4714 # devicetree
4715 self.assertIn('u-boot-tpl', entries)
4716 entry = entries['u-boot-tpl']
4717 self.assertEqual('u-boot-tpl', entry.etype)
4718 self.assertEqual(None, entry.GetEntries())
4719
4720 def testExpandedTpl(self):
4721 """Test that an expanded entry type is selected for TPL when needed"""
4722 self._SetupTplElf()
4723
4724 entry_args = {
4725 'tpl-bss-pad': 'y',
4726 'tpl-dtb': 'y',
4727 }
4728 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4729 entry_args=entry_args)
4730 image = control.images['image']
4731 entries = image.GetEntries()
4732 self.assertEqual(1, len(entries))
4733
4734 # We only have u-boot-tpl, which be expanded
4735 self.assertIn('u-boot-tpl', entries)
4736 entry = entries['u-boot-tpl']
4737 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4738 subent = entry.GetEntries()
4739 self.assertEqual(3, len(subent))
4740 self.assertIn('u-boot-tpl-nodtb', subent)
4741 self.assertIn('u-boot-tpl-bss-pad', subent)
4742 self.assertIn('u-boot-tpl-dtb', subent)
4743
4744 def testExpandedNoPad(self):
4745 """Test an expanded entry without BSS pad enabled"""
4746 self._SetupSplElf()
4747 self._SetupTplElf()
4748
4749 # SPL has a devicetree, TPL does not
4750 entry_args = {
4751 'spl-dtb': 'something',
4752 'spl-bss-pad': 'n',
4753 'tpl-dtb': '',
4754 }
4755 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4756 entry_args=entry_args)
4757 image = control.images['image']
4758 entries = image.GetEntries()
4759
4760 # Just check u-boot-spl, which should be expanded into two parts
4761 self.assertIn('u-boot-spl', entries)
4762 entry = entries['u-boot-spl']
4763 self.assertEqual('u-boot-spl-expanded', entry.etype)
4764 subent = entry.GetEntries()
4765 self.assertEqual(2, len(subent))
4766 self.assertIn('u-boot-spl-nodtb', subent)
4767 self.assertIn('u-boot-spl-dtb', subent)
4768
4769 def testExpandedTplNoPad(self):
4770 """Test that an expanded entry type with padding disabled in TPL"""
4771 self._SetupTplElf()
4772
4773 entry_args = {
4774 'tpl-bss-pad': '',
4775 'tpl-dtb': 'y',
4776 }
4777 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4778 entry_args=entry_args)
4779 image = control.images['image']
4780 entries = image.GetEntries()
4781 self.assertEqual(1, len(entries))
4782
4783 # We only have u-boot-tpl, which be expanded
4784 self.assertIn('u-boot-tpl', entries)
4785 entry = entries['u-boot-tpl']
4786 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4787 subent = entry.GetEntries()
4788 self.assertEqual(2, len(subent))
4789 self.assertIn('u-boot-tpl-nodtb', subent)
4790 self.assertIn('u-boot-tpl-dtb', subent)
4791
4792 def testFdtInclude(self):
4793 """Test that an Fdt is update within all binaries"""
4794 self._SetupSplElf()
4795 self._SetupTplElf()
4796
4797 # SPL has a devicetree, TPL does not
4798 self.maxDiff = None
4799 entry_args = {
4800 'spl-dtb': '1',
4801 'spl-bss-pad': 'y',
4802 'tpl-dtb': '',
4803 }
4804 # Build the image. It includes two separate devicetree binaries, each
4805 # with their own contents, but all contain the binman definition.
4806 data = self._DoReadFileDtb(
4807 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4808 update_dtb=True, entry_args=entry_args)[0]
4809 pad_len = 10
4810
4811 # Check the U-Boot dtb
4812 start = len(U_BOOT_NODTB_DATA)
4813 fdt_size = self.checkDtbSizes(data, pad_len, start)
4814
4815 # Now check SPL
4816 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4817 fdt_size = self.checkDtbSizes(data, pad_len, start)
4818
4819 # TPL has no devicetree
4820 start += fdt_size + len(U_BOOT_TPL_DATA)
4821 self.assertEqual(len(data), start)
Simon Glassbb395742020-10-26 17:40:14 -06004822
Simon Glass7098b7f2021-03-21 18:24:30 +13004823 def testSymbolsExpanded(self):
4824 """Test binman can assign symbols in expanded entries"""
4825 entry_args = {
4826 'spl-dtb': '1',
4827 }
4828 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4829 U_BOOT_SPL_DTB_DATA, 0x38,
4830 entry_args=entry_args, use_expanded=True)
4831
Simon Glasse1915782021-03-21 18:24:31 +13004832 def testCollection(self):
4833 """Test a collection"""
4834 data = self._DoReadFile('198_collection.dts')
4835 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004836 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
4837 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
Simon Glasse1915782021-03-21 18:24:31 +13004838 data)
4839
Simon Glass27a7f772021-03-21 18:24:32 +13004840 def testCollectionSection(self):
4841 """Test a collection where a section must be built first"""
4842 # Sections never have their contents when GetData() is called, but when
Simon Glass7e3f89f2021-11-23 11:03:47 -07004843 # BuildSectionData() is called with required=True, a section will force
Simon Glass27a7f772021-03-21 18:24:32 +13004844 # building the contents, producing an error is anything is still
4845 # missing.
4846 data = self._DoReadFile('199_collection_section.dts')
4847 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
Simon Glass80025522022-01-29 14:14:04 -07004848 self.assertEqual(section + U_BOOT_DATA + tools.get_bytes(0xff, 2) +
4849 section + tools.get_bytes(0xfe, 3) + U_BOOT_DATA,
Simon Glass27a7f772021-03-21 18:24:32 +13004850 data)
4851
Simon Glassf427c5f2021-03-21 18:24:33 +13004852 def testAlignDefault(self):
4853 """Test that default alignment works on sections"""
4854 data = self._DoReadFile('200_align_default.dts')
Simon Glass80025522022-01-29 14:14:04 -07004855 expected = (U_BOOT_DATA + tools.get_bytes(0, 8 - len(U_BOOT_DATA)) +
Simon Glassf427c5f2021-03-21 18:24:33 +13004856 U_BOOT_DATA)
4857 # Special alignment for section
Simon Glass80025522022-01-29 14:14:04 -07004858 expected += tools.get_bytes(0, 32 - len(expected))
Simon Glassf427c5f2021-03-21 18:24:33 +13004859 # No alignment within the nested section
4860 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
4861 # Now the final piece, which should be default-aligned
Simon Glass80025522022-01-29 14:14:04 -07004862 expected += tools.get_bytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
Simon Glassf427c5f2021-03-21 18:24:33 +13004863 self.assertEqual(expected, data)
Simon Glass27a7f772021-03-21 18:24:32 +13004864
Bin Mengc0b15742021-05-10 20:23:33 +08004865 def testPackOpenSBI(self):
4866 """Test that an image with an OpenSBI binary can be created"""
4867 data = self._DoReadFile('201_opensbi.dts')
4868 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
4869
Simon Glass76f496d2021-07-06 10:36:37 -06004870 def testSectionsSingleThread(self):
4871 """Test sections without multithreading"""
4872 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
Simon Glass80025522022-01-29 14:14:04 -07004873 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4874 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
4875 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glass76f496d2021-07-06 10:36:37 -06004876 self.assertEqual(expected, data)
4877
4878 def testThreadTimeout(self):
4879 """Test handling a thread that takes too long"""
4880 with self.assertRaises(ValueError) as e:
4881 self._DoTestFile('202_section_timeout.dts',
4882 test_section_timeout=True)
Simon Glass2d59d152021-10-18 12:13:15 -06004883 self.assertIn("Timed out obtaining contents", str(e.exception))
Simon Glass76f496d2021-07-06 10:36:37 -06004884
Simon Glass748a1d42021-07-06 10:36:41 -06004885 def testTiming(self):
4886 """Test output of timing information"""
4887 data = self._DoReadFile('055_sections.dts')
4888 with test_util.capture_sys_output() as (stdout, stderr):
4889 state.TimingShow()
4890 self.assertIn('read:', stdout.getvalue())
4891 self.assertIn('compress:', stdout.getvalue())
4892
Simon Glassadfb8492021-11-03 21:09:18 -06004893 def testUpdateFdtInElf(self):
4894 """Test that we can update the devicetree in an ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02004895 if not elf.ELF_TOOLS:
4896 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06004897 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4898 outfile = os.path.join(self._indir, 'u-boot.out')
4899 begin_sym = 'dtb_embed_begin'
4900 end_sym = 'dtb_embed_end'
4901 retcode = self._DoTestFile(
4902 '060_fdt_update.dts', update_dtb=True,
4903 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4904 self.assertEqual(0, retcode)
4905
4906 # Check that the output file does in fact contact a dtb with the binman
4907 # definition in the correct place
4908 syms = elf.GetSymbolFileOffset(infile,
4909 ['dtb_embed_begin', 'dtb_embed_end'])
Simon Glass80025522022-01-29 14:14:04 -07004910 data = tools.read_file(outfile)
Simon Glassadfb8492021-11-03 21:09:18 -06004911 dtb_data = data[syms['dtb_embed_begin'].offset:
4912 syms['dtb_embed_end'].offset]
4913
4914 dtb = fdt.Fdt.FromData(dtb_data)
4915 dtb.Scan()
4916 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4917 self.assertEqual({
4918 'image-pos': 0,
4919 'offset': 0,
4920 '_testing:offset': 32,
4921 '_testing:size': 2,
4922 '_testing:image-pos': 32,
4923 'section@0/u-boot:offset': 0,
4924 'section@0/u-boot:size': len(U_BOOT_DATA),
4925 'section@0/u-boot:image-pos': 0,
4926 'section@0:offset': 0,
4927 'section@0:size': 16,
4928 'section@0:image-pos': 0,
4929
4930 'section@1/u-boot:offset': 0,
4931 'section@1/u-boot:size': len(U_BOOT_DATA),
4932 'section@1/u-boot:image-pos': 16,
4933 'section@1:offset': 16,
4934 'section@1:size': 16,
4935 'section@1:image-pos': 16,
4936 'size': 40
4937 }, props)
4938
4939 def testUpdateFdtInElfInvalid(self):
4940 """Test that invalid args are detected with --update-fdt-in-elf"""
4941 with self.assertRaises(ValueError) as e:
4942 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
4943 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
4944 str(e.exception))
4945
4946 def testUpdateFdtInElfNoSyms(self):
4947 """Test that missing symbols are detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02004948 if not elf.ELF_TOOLS:
4949 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06004950 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4951 outfile = ''
4952 begin_sym = 'wrong_begin'
4953 end_sym = 'wrong_end'
4954 with self.assertRaises(ValueError) as e:
4955 self._DoTestFile(
4956 '060_fdt_update.dts',
4957 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4958 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
4959 str(e.exception))
4960
4961 def testUpdateFdtInElfTooSmall(self):
4962 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02004963 if not elf.ELF_TOOLS:
4964 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06004965 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
4966 outfile = os.path.join(self._indir, 'u-boot.out')
4967 begin_sym = 'dtb_embed_begin'
4968 end_sym = 'dtb_embed_end'
4969 with self.assertRaises(ValueError) as e:
4970 self._DoTestFile(
4971 '060_fdt_update.dts', update_dtb=True,
4972 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4973 self.assertRegex(
4974 str(e.exception),
4975 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
4976
Simon Glass88e04da2021-11-23 11:03:42 -07004977 def testVersion(self):
4978 """Test we can get the binman version"""
4979 version = '(unreleased)'
4980 self.assertEqual(version, state.GetVersion(self._indir))
4981
4982 with self.assertRaises(SystemExit):
4983 with test_util.capture_sys_output() as (_, stderr):
4984 self._DoBinman('-V')
4985 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
4986
4987 # Try running the tool too, just to be safe
4988 result = self._RunBinman('-V')
4989 self.assertEqual('Binman %s\n' % version, result.stderr)
4990
4991 # Set up a version file to make sure that works
4992 version = 'v2025.01-rc2'
Simon Glass80025522022-01-29 14:14:04 -07004993 tools.write_file(os.path.join(self._indir, 'version'), version,
Simon Glass88e04da2021-11-23 11:03:42 -07004994 binary=False)
4995 self.assertEqual(version, state.GetVersion(self._indir))
4996
Simon Glass637958f2021-11-23 21:09:50 -07004997 def testAltFormat(self):
4998 """Test that alternative formats can be used to extract"""
4999 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
5000
5001 try:
5002 tmpdir, updated_fname = self._SetupImageInTmpdir()
5003 with test_util.capture_sys_output() as (stdout, _):
5004 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
5005 self.assertEqual(
5006 '''Flag (-F) Entry type Description
5007fdt fdtmap Extract the devicetree blob from the fdtmap
5008''',
5009 stdout.getvalue())
5010
5011 dtb = os.path.join(tmpdir, 'fdt.dtb')
5012 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
5013 dtb, 'fdtmap')
5014
5015 # Check that we can read it and it can be scanning, meaning it does
5016 # not have a 16-byte fdtmap header
Simon Glass80025522022-01-29 14:14:04 -07005017 data = tools.read_file(dtb)
Simon Glass637958f2021-11-23 21:09:50 -07005018 dtb = fdt.Fdt.FromData(data)
5019 dtb.Scan()
5020
5021 # Now check u-boot which has no alt_format
5022 fname = os.path.join(tmpdir, 'fdt.dtb')
5023 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
5024 '-f', fname, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07005025 data = tools.read_file(fname)
Simon Glass637958f2021-11-23 21:09:50 -07005026 self.assertEqual(U_BOOT_DATA, data)
5027
5028 finally:
5029 shutil.rmtree(tmpdir)
5030
Simon Glass0b00ae62021-11-23 21:09:52 -07005031 def testExtblobList(self):
5032 """Test an image with an external blob list"""
5033 data = self._DoReadFile('215_blob_ext_list.dts')
5034 self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
5035
5036 def testExtblobListMissing(self):
5037 """Test an image with a missing external blob"""
5038 with self.assertRaises(ValueError) as e:
5039 self._DoReadFile('216_blob_ext_list_missing.dts')
5040 self.assertIn("Filename 'missing-file' not found in input path",
5041 str(e.exception))
5042
5043 def testExtblobListMissingOk(self):
5044 """Test an image with an missing external blob that is allowed"""
5045 with test_util.capture_sys_output() as (stdout, stderr):
5046 self._DoTestFile('216_blob_ext_list_missing.dts',
5047 allow_missing=True)
5048 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005049 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass0b00ae62021-11-23 21:09:52 -07005050
Simon Glass3efb2972021-11-23 21:08:59 -07005051 def testFip(self):
5052 """Basic test of generation of an ARM Firmware Image Package (FIP)"""
5053 data = self._DoReadFile('203_fip.dts')
5054 hdr, fents = fip_util.decode_fip(data)
5055 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5056 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5057 self.assertEqual(0x123, hdr.flags)
5058
5059 self.assertEqual(2, len(fents))
5060
5061 fent = fents[0]
5062 self.assertEqual(
5063 bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
5064 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
5065 self.assertEqual('soc-fw', fent.fip_type)
5066 self.assertEqual(0x88, fent.offset)
5067 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5068 self.assertEqual(0x123456789abcdef, fent.flags)
5069 self.assertEqual(ATF_BL31_DATA, fent.data)
5070 self.assertEqual(True, fent.valid)
5071
5072 fent = fents[1]
5073 self.assertEqual(
5074 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
5075 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
5076 self.assertEqual('scp-fwu-cfg', fent.fip_type)
5077 self.assertEqual(0x8c, fent.offset)
5078 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5079 self.assertEqual(0, fent.flags)
5080 self.assertEqual(ATF_BL2U_DATA, fent.data)
5081 self.assertEqual(True, fent.valid)
5082
5083 def testFipOther(self):
5084 """Basic FIP with something that isn't a external blob"""
5085 data = self._DoReadFile('204_fip_other.dts')
5086 hdr, fents = fip_util.decode_fip(data)
5087
5088 self.assertEqual(2, len(fents))
5089 fent = fents[1]
5090 self.assertEqual('rot-cert', fent.fip_type)
5091 self.assertEqual(b'aa', fent.data)
5092
Simon Glass3efb2972021-11-23 21:08:59 -07005093 def testFipNoType(self):
5094 """FIP with an entry of an unknown type"""
5095 with self.assertRaises(ValueError) as e:
5096 self._DoReadFile('205_fip_no_type.dts')
5097 self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
5098 str(e.exception))
5099
5100 def testFipUuid(self):
5101 """Basic FIP with a manual uuid"""
5102 data = self._DoReadFile('206_fip_uuid.dts')
5103 hdr, fents = fip_util.decode_fip(data)
5104
5105 self.assertEqual(2, len(fents))
5106 fent = fents[1]
5107 self.assertEqual(None, fent.fip_type)
5108 self.assertEqual(
5109 bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
5110 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
5111 fent.uuid)
5112 self.assertEqual(U_BOOT_DATA, fent.data)
5113
5114 def testFipLs(self):
5115 """Test listing a FIP"""
5116 data = self._DoReadFileRealDtb('207_fip_ls.dts')
5117 hdr, fents = fip_util.decode_fip(data)
5118
5119 try:
5120 tmpdir, updated_fname = self._SetupImageInTmpdir()
5121 with test_util.capture_sys_output() as (stdout, stderr):
5122 self._DoBinman('ls', '-i', updated_fname)
5123 finally:
5124 shutil.rmtree(tmpdir)
5125 lines = stdout.getvalue().splitlines()
5126 expected = [
Simon Glass49cd2b32023-02-07 14:34:18 -07005127'Name Image-pos Size Entry-type Offset Uncomp-size',
5128'--------------------------------------------------------------',
5129'image 0 2d3 section 0',
5130' atf-fip 0 90 atf-fip 0',
5131' soc-fw 88 4 blob-ext 88',
5132' u-boot 8c 4 u-boot 8c',
5133' fdtmap 90 243 fdtmap 90',
Simon Glass3efb2972021-11-23 21:08:59 -07005134]
5135 self.assertEqual(expected, lines)
5136
5137 image = control.images['image']
5138 entries = image.GetEntries()
5139 fdtmap = entries['fdtmap']
5140
5141 fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
5142 magic = fdtmap_data[:8]
5143 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07005144 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass3efb2972021-11-23 21:08:59 -07005145
5146 fdt_data = fdtmap_data[16:]
5147 dtb = fdt.Fdt.FromData(fdt_data)
5148 dtb.Scan()
5149 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
5150 self.assertEqual({
5151 'atf-fip/soc-fw:image-pos': 136,
5152 'atf-fip/soc-fw:offset': 136,
5153 'atf-fip/soc-fw:size': 4,
5154 'atf-fip/u-boot:image-pos': 140,
5155 'atf-fip/u-boot:offset': 140,
5156 'atf-fip/u-boot:size': 4,
5157 'atf-fip:image-pos': 0,
5158 'atf-fip:offset': 0,
5159 'atf-fip:size': 144,
5160 'image-pos': 0,
5161 'offset': 0,
5162 'fdtmap:image-pos': fdtmap.image_pos,
5163 'fdtmap:offset': fdtmap.offset,
5164 'fdtmap:size': len(fdtmap_data),
5165 'size': len(data),
5166 }, props)
5167
5168 def testFipExtractOneEntry(self):
5169 """Test extracting a single entry fron an FIP"""
5170 self._DoReadFileRealDtb('207_fip_ls.dts')
Simon Glass80025522022-01-29 14:14:04 -07005171 image_fname = tools.get_output_filename('image.bin')
Simon Glass3efb2972021-11-23 21:08:59 -07005172 fname = os.path.join(self._indir, 'output.extact')
5173 control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07005174 data = tools.read_file(fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005175 self.assertEqual(U_BOOT_DATA, data)
5176
5177 def testFipReplace(self):
5178 """Test replacing a single file in a FIP"""
Simon Glass80025522022-01-29 14:14:04 -07005179 expected = U_BOOT_DATA + tools.get_bytes(0x78, 50)
Simon Glass3efb2972021-11-23 21:08:59 -07005180 data = self._DoReadFileRealDtb('208_fip_replace.dts')
Simon Glass80025522022-01-29 14:14:04 -07005181 updated_fname = tools.get_output_filename('image-updated.bin')
5182 tools.write_file(updated_fname, data)
Simon Glass3efb2972021-11-23 21:08:59 -07005183 entry_name = 'atf-fip/u-boot'
5184 control.WriteEntry(updated_fname, entry_name, expected,
5185 allow_resize=True)
5186 actual = control.ReadEntry(updated_fname, entry_name)
5187 self.assertEqual(expected, actual)
5188
Simon Glass80025522022-01-29 14:14:04 -07005189 new_data = tools.read_file(updated_fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005190 hdr, fents = fip_util.decode_fip(new_data)
5191
5192 self.assertEqual(2, len(fents))
5193
5194 # Check that the FIP entry is updated
5195 fent = fents[1]
5196 self.assertEqual(0x8c, fent.offset)
5197 self.assertEqual(len(expected), fent.size)
5198 self.assertEqual(0, fent.flags)
5199 self.assertEqual(expected, fent.data)
5200 self.assertEqual(True, fent.valid)
5201
5202 def testFipMissing(self):
5203 with test_util.capture_sys_output() as (stdout, stderr):
5204 self._DoTestFile('209_fip_missing.dts', allow_missing=True)
5205 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005206 self.assertRegex(err, "Image 'image'.*missing.*: rmm-fw")
Simon Glass3efb2972021-11-23 21:08:59 -07005207
5208 def testFipSize(self):
5209 """Test a FIP with a size property"""
5210 data = self._DoReadFile('210_fip_size.dts')
5211 self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
5212 hdr, fents = fip_util.decode_fip(data)
5213 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5214 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5215
5216 self.assertEqual(1, len(fents))
5217
5218 fent = fents[0]
5219 self.assertEqual('soc-fw', fent.fip_type)
5220 self.assertEqual(0x60, fent.offset)
5221 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5222 self.assertEqual(ATF_BL31_DATA, fent.data)
5223 self.assertEqual(True, fent.valid)
5224
5225 rest = data[0x60 + len(ATF_BL31_DATA):0x100]
Simon Glass80025522022-01-29 14:14:04 -07005226 self.assertEqual(tools.get_bytes(0xff, len(rest)), rest)
Simon Glass3efb2972021-11-23 21:08:59 -07005227
5228 def testFipBadAlign(self):
5229 """Test that an invalid alignment value in a FIP is detected"""
5230 with self.assertRaises(ValueError) as e:
5231 self._DoTestFile('211_fip_bad_align.dts')
5232 self.assertIn(
5233 "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
5234 str(e.exception))
5235
5236 def testFipCollection(self):
5237 """Test using a FIP in a collection"""
5238 data = self._DoReadFile('212_fip_collection.dts')
5239 entry1 = control.images['image'].GetEntries()['collection']
5240 data1 = data[:entry1.size]
5241 hdr1, fents2 = fip_util.decode_fip(data1)
5242
5243 entry2 = control.images['image'].GetEntries()['atf-fip']
5244 data2 = data[entry2.offset:entry2.offset + entry2.size]
5245 hdr1, fents2 = fip_util.decode_fip(data2)
5246
5247 # The 'collection' entry should have U-Boot included at the end
5248 self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
5249 self.assertEqual(data1, data2 + U_BOOT_DATA)
5250 self.assertEqual(U_BOOT_DATA, data1[-4:])
5251
5252 # There should be a U-Boot after the final FIP
5253 self.assertEqual(U_BOOT_DATA, data[-4:])
Simon Glass76f496d2021-07-06 10:36:37 -06005254
Simon Glassccae6862022-01-12 13:10:35 -07005255 def testFakeBlob(self):
5256 """Test handling of faking an external blob"""
5257 with test_util.capture_sys_output() as (stdout, stderr):
5258 self._DoTestFile('217_fake_blob.dts', allow_missing=True,
5259 allow_fake_blobs=True)
5260 err = stderr.getvalue()
5261 self.assertRegex(
5262 err,
5263 "Image '.*' has faked external blobs and is non-functional: .*")
Simon Glassccae6862022-01-12 13:10:35 -07005264
Simon Glassceb5f912022-01-09 20:13:46 -07005265 def testExtblobListFaked(self):
5266 """Test an extblob with missing external blob that are faked"""
5267 with test_util.capture_sys_output() as (stdout, stderr):
5268 self._DoTestFile('216_blob_ext_list_missing.dts',
5269 allow_fake_blobs=True)
5270 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005271 self.assertRegex(err, "Image 'image'.*faked.*: blob-ext-list")
Simon Glassceb5f912022-01-09 20:13:46 -07005272
Simon Glass162017b2022-01-09 20:13:57 -07005273 def testListBintools(self):
5274 args = ['tool', '--list']
5275 with test_util.capture_sys_output() as (stdout, _):
5276 self._DoBinman(*args)
5277 out = stdout.getvalue().splitlines()
5278 self.assertTrue(len(out) >= 2)
5279
5280 def testFetchBintools(self):
5281 def fail_download(url):
Simon Glass80025522022-01-29 14:14:04 -07005282 """Take the tools.download() function by raising an exception"""
Simon Glass162017b2022-01-09 20:13:57 -07005283 raise urllib.error.URLError('my error')
5284
5285 args = ['tool']
5286 with self.assertRaises(ValueError) as e:
5287 self._DoBinman(*args)
5288 self.assertIn("Invalid arguments to 'tool' subcommand",
5289 str(e.exception))
5290
5291 args = ['tool', '--fetch']
5292 with self.assertRaises(ValueError) as e:
5293 self._DoBinman(*args)
5294 self.assertIn('Please specify bintools to fetch', str(e.exception))
5295
5296 args = ['tool', '--fetch', '_testing']
Simon Glass80025522022-01-29 14:14:04 -07005297 with unittest.mock.patch.object(tools, 'download',
Simon Glass162017b2022-01-09 20:13:57 -07005298 side_effect=fail_download):
5299 with test_util.capture_sys_output() as (stdout, _):
5300 self._DoBinman(*args)
5301 self.assertIn('failed to fetch with all methods', stdout.getvalue())
5302
Simon Glass620c4462022-01-09 20:14:11 -07005303 def testBintoolDocs(self):
5304 """Test for creation of bintool documentation"""
5305 with test_util.capture_sys_output() as (stdout, stderr):
5306 control.write_bintool_docs(control.bintool.Bintool.get_tool_list())
5307 self.assertTrue(len(stdout.getvalue()) > 0)
5308
5309 def testBintoolDocsMissing(self):
5310 """Test handling of missing bintool documentation"""
5311 with self.assertRaises(ValueError) as e:
5312 with test_util.capture_sys_output() as (stdout, stderr):
5313 control.write_bintool_docs(
5314 control.bintool.Bintool.get_tool_list(), 'mkimage')
5315 self.assertIn('Documentation is missing for modules: mkimage',
5316 str(e.exception))
5317
Jan Kiszka58c407f2022-01-28 20:37:53 +01005318 def testListWithGenNode(self):
5319 """Check handling of an FDT map when the section cannot be found"""
5320 entry_args = {
5321 'of-list': 'test-fdt1 test-fdt2',
5322 }
5323 data = self._DoReadFileDtb(
5324 '219_fit_gennode.dts',
5325 entry_args=entry_args,
5326 use_real_dtb=True,
5327 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])
5328
5329 try:
5330 tmpdir, updated_fname = self._SetupImageInTmpdir()
5331 with test_util.capture_sys_output() as (stdout, stderr):
5332 self._RunBinman('ls', '-i', updated_fname)
5333 finally:
5334 shutil.rmtree(tmpdir)
5335
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005336 def testFitSubentryUsesBintool(self):
5337 """Test that binman FIT subentries can use bintools"""
5338 command.test_result = self._HandleGbbCommand
5339 entry_args = {
5340 'keydir': 'devkeys',
5341 'bmpblk': 'bmpblk.bin',
5342 }
5343 data, _, _, _ = self._DoReadFileDtb('220_fit_subentry_bintool.dts',
5344 entry_args=entry_args)
5345
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03005346 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
5347 tools.get_bytes(0, 0x2180 - 16))
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005348 self.assertIn(expected, data)
5349
5350 def testFitSubentryMissingBintool(self):
5351 """Test that binman reports missing bintools for FIT subentries"""
5352 entry_args = {
5353 'keydir': 'devkeys',
5354 }
5355 with test_util.capture_sys_output() as (_, stderr):
5356 self._DoTestFile('220_fit_subentry_bintool.dts',
5357 force_missing_bintools='futility', entry_args=entry_args)
5358 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005359 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glassccae6862022-01-12 13:10:35 -07005360
Alper Nebi Yasak1e4ffd82022-02-09 22:02:35 +03005361 def testFitSubentryHashSubnode(self):
5362 """Test an image with a FIT inside"""
5363 data, _, _, out_dtb_name = self._DoReadFileDtb(
5364 '221_fit_subentry_hash.dts', use_real_dtb=True, update_dtb=True)
5365
5366 mkimage_dtb = fdt.Fdt.FromData(data)
5367 mkimage_dtb.Scan()
5368 binman_dtb = fdt.Fdt(out_dtb_name)
5369 binman_dtb.Scan()
5370
5371 # Check that binman didn't add hash values
5372 fnode = binman_dtb.GetNode('/binman/fit/images/kernel/hash')
5373 self.assertNotIn('value', fnode.props)
5374
5375 fnode = binman_dtb.GetNode('/binman/fit/images/fdt-1/hash')
5376 self.assertNotIn('value', fnode.props)
5377
5378 # Check that mkimage added hash values
5379 fnode = mkimage_dtb.GetNode('/images/kernel/hash')
5380 self.assertIn('value', fnode.props)
5381
5382 fnode = mkimage_dtb.GetNode('/images/fdt-1/hash')
5383 self.assertIn('value', fnode.props)
5384
Roger Quadros5cdcea02022-02-19 20:50:04 +02005385 def testPackTeeOs(self):
5386 """Test that an image with an TEE binary can be created"""
5387 data = self._DoReadFile('222_tee_os.dts')
5388 self.assertEqual(TEE_OS_DATA, data[:len(TEE_OS_DATA)])
5389
Simon Glass912339f2022-02-08 11:50:03 -07005390 def testFitFdtOper(self):
5391 """Check handling of a specified FIT operation"""
5392 entry_args = {
5393 'of-list': 'test-fdt1 test-fdt2',
5394 'default-dt': 'test-fdt2',
5395 }
5396 self._DoReadFileDtb(
5397 '223_fit_fdt_oper.dts',
5398 entry_args=entry_args,
5399 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
5400
5401 def testFitFdtBadOper(self):
5402 """Check handling of an FDT map when the section cannot be found"""
5403 with self.assertRaises(ValueError) as exc:
5404 self._DoReadFileDtb('224_fit_bad_oper.dts')
Simon Glass05f71dc2022-03-05 20:19:09 -07005405 self.assertIn("Node '/binman/fit': subnode 'images/@fdt-SEQ': Unknown operation 'unknown'",
Simon Glass912339f2022-02-08 11:50:03 -07005406 str(exc.exception))
5407
Simon Glassdd156a42022-03-05 20:18:59 -07005408 def test_uses_expand_size(self):
5409 """Test that the 'expand-size' property cannot be used anymore"""
5410 with self.assertRaises(ValueError) as e:
5411 data = self._DoReadFile('225_expand_size_bad.dts')
5412 self.assertIn(
5413 "Node '/binman/u-boot': Please use 'extend-size' instead of 'expand-size'",
5414 str(e.exception))
5415
Simon Glass5f423422022-03-05 20:19:12 -07005416 def testFitSplitElf(self):
5417 """Test an image with an FIT with an split-elf operation"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005418 if not elf.ELF_TOOLS:
5419 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005420 entry_args = {
5421 'of-list': 'test-fdt1 test-fdt2',
5422 'default-dt': 'test-fdt2',
5423 'atf-bl31-path': 'bl31.elf',
5424 'tee-os-path': 'tee.elf',
5425 }
5426 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5427 data = self._DoReadFileDtb(
5428 '226_fit_split_elf.dts',
5429 entry_args=entry_args,
5430 extra_indirs=[test_subdir])[0]
5431
5432 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
5433 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
5434
5435 base_keys = {'description', 'type', 'arch', 'os', 'compression',
5436 'data', 'load'}
5437 dtb = fdt.Fdt.FromData(fit_data)
5438 dtb.Scan()
5439
5440 elf_data = tools.read_file(os.path.join(self._indir, 'bl31.elf'))
5441 segments, entry = elf.read_loadable_segments(elf_data)
5442
5443 # We assume there are two segments
5444 self.assertEquals(2, len(segments))
5445
5446 atf1 = dtb.GetNode('/images/atf-1')
5447 _, start, data = segments[0]
5448 self.assertEqual(base_keys | {'entry'}, atf1.props.keys())
5449 self.assertEqual(entry,
5450 fdt_util.fdt32_to_cpu(atf1.props['entry'].value))
5451 self.assertEqual(start,
5452 fdt_util.fdt32_to_cpu(atf1.props['load'].value))
5453 self.assertEqual(data, atf1.props['data'].bytes)
5454
Jonas Karlmand2c7d902023-01-21 19:01:48 +00005455 hash_node = atf1.FindNode('hash')
5456 self.assertIsNotNone(hash_node)
5457 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5458
Simon Glass5f423422022-03-05 20:19:12 -07005459 atf2 = dtb.GetNode('/images/atf-2')
5460 self.assertEqual(base_keys, atf2.props.keys())
5461 _, start, data = segments[1]
5462 self.assertEqual(start,
5463 fdt_util.fdt32_to_cpu(atf2.props['load'].value))
5464 self.assertEqual(data, atf2.props['data'].bytes)
5465
Jonas Karlmand2c7d902023-01-21 19:01:48 +00005466 hash_node = atf2.FindNode('hash')
5467 self.assertIsNotNone(hash_node)
5468 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5469
5470 hash_node = dtb.GetNode('/images/tee-1/hash-1')
5471 self.assertIsNotNone(hash_node)
5472 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5473
Simon Glass5f423422022-03-05 20:19:12 -07005474 conf = dtb.GetNode('/configurations')
5475 self.assertEqual({'default'}, conf.props.keys())
5476
5477 for subnode in conf.subnodes:
5478 self.assertEqual({'description', 'fdt', 'loadables'},
5479 subnode.props.keys())
5480 self.assertEqual(
5481 ['atf-1', 'atf-2', 'tee-1', 'tee-2'],
5482 fdt_util.GetStringList(subnode, 'loadables'))
5483
5484 def _check_bad_fit(self, dts):
5485 """Check a bad FIT
5486
5487 This runs with the given dts and returns the assertion raised
5488
5489 Args:
5490 dts (str): dts filename to use
5491
5492 Returns:
5493 str: Assertion string raised
5494 """
5495 entry_args = {
5496 'of-list': 'test-fdt1 test-fdt2',
5497 'default-dt': 'test-fdt2',
5498 'atf-bl31-path': 'bl31.elf',
5499 'tee-os-path': 'tee.elf',
5500 }
5501 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5502 with self.assertRaises(ValueError) as exc:
5503 self._DoReadFileDtb(dts, entry_args=entry_args,
5504 extra_indirs=[test_subdir])[0]
5505 return str(exc.exception)
5506
5507 def testFitSplitElfBadElf(self):
5508 """Test a FIT split-elf operation with an invalid ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005509 if not elf.ELF_TOOLS:
5510 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005511 TestFunctional._MakeInputFile('bad.elf', tools.get_bytes(100, 100))
5512 entry_args = {
5513 'of-list': 'test-fdt1 test-fdt2',
5514 'default-dt': 'test-fdt2',
5515 'atf-bl31-path': 'bad.elf',
5516 'tee-os-path': 'tee.elf',
5517 }
5518 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5519 with self.assertRaises(ValueError) as exc:
5520 self._DoReadFileDtb(
5521 '226_fit_split_elf.dts',
5522 entry_args=entry_args,
5523 extra_indirs=[test_subdir])[0]
5524 self.assertIn(
5525 "Node '/binman/fit': subnode 'images/@atf-SEQ': Failed to read ELF file: Magic number does not match",
5526 str(exc.exception))
5527
Simon Glass5f423422022-03-05 20:19:12 -07005528 def checkFitSplitElf(self, **kwargs):
Simon Glass7d3e4072022-08-07 09:46:46 -06005529 """Test an split-elf FIT with a missing ELF file
5530
5531 Args:
5532 kwargs (dict of str): Arguments to pass to _DoTestFile()
5533
5534 Returns:
5535 tuple:
5536 str: stdout result
5537 str: stderr result
5538 """
Simon Glass5f423422022-03-05 20:19:12 -07005539 entry_args = {
5540 'of-list': 'test-fdt1 test-fdt2',
5541 'default-dt': 'test-fdt2',
5542 'atf-bl31-path': 'bl31.elf',
5543 'tee-os-path': 'missing.elf',
5544 }
5545 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5546 with test_util.capture_sys_output() as (stdout, stderr):
5547 self._DoTestFile(
5548 '226_fit_split_elf.dts', entry_args=entry_args,
Simon Glass7d3e4072022-08-07 09:46:46 -06005549 extra_indirs=[test_subdir], verbosity=3, **kwargs)
5550 out = stdout.getvalue()
5551 err = stderr.getvalue()
5552 return out, err
Simon Glass5f423422022-03-05 20:19:12 -07005553
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005554 def testFitSplitElfBadDirective(self):
5555 """Test a FIT split-elf invalid fit,xxx directive in an image node"""
5556 if not elf.ELF_TOOLS:
5557 self.skipTest('Python elftools not available')
5558 err = self._check_bad_fit('227_fit_bad_dir.dts')
5559 self.assertIn(
5560 "Node '/binman/fit': subnode 'images/@atf-SEQ': Unknown directive 'fit,something'",
5561 err)
5562
5563 def testFitSplitElfBadDirectiveConfig(self):
5564 """Test a FIT split-elf with invalid fit,xxx directive in config"""
5565 if not elf.ELF_TOOLS:
5566 self.skipTest('Python elftools not available')
5567 err = self._check_bad_fit('228_fit_bad_dir_config.dts')
5568 self.assertEqual(
5569 "Node '/binman/fit': subnode 'configurations/@config-SEQ': Unknown directive 'fit,config'",
5570 err)
5571
5572
Simon Glass5f423422022-03-05 20:19:12 -07005573 def testFitSplitElfMissing(self):
5574 """Test an split-elf FIT with a missing ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005575 if not elf.ELF_TOOLS:
5576 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005577 out, err = self.checkFitSplitElf(allow_missing=True)
Simon Glass5f423422022-03-05 20:19:12 -07005578 self.assertRegex(
5579 err,
5580 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005581 self.assertNotRegex(out, '.*Faked blob.*')
5582 fname = tools.get_output_filename('binman-fake/missing.elf')
5583 self.assertFalse(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005584
5585 def testFitSplitElfFaked(self):
5586 """Test an split-elf FIT with faked ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005587 if not elf.ELF_TOOLS:
5588 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005589 out, err = self.checkFitSplitElf(allow_missing=True, allow_fake_blobs=True)
Simon Glass5f423422022-03-05 20:19:12 -07005590 self.assertRegex(
5591 err,
5592 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005593 self.assertRegex(
5594 out,
5595 "Entry '/binman/fit/images/@tee-SEQ/tee-os': Faked blob '.*binman-fake/missing.elf")
5596 fname = tools.get_output_filename('binman-fake/missing.elf')
5597 self.assertTrue(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005598
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005599 def testMkimageMissingBlob(self):
5600 """Test using mkimage to build an image"""
5601 with test_util.capture_sys_output() as (stdout, stderr):
5602 self._DoTestFile('229_mkimage_missing.dts', allow_missing=True,
5603 allow_fake_blobs=True)
5604 err = stderr.getvalue()
5605 self.assertRegex(
5606 err,
5607 "Image '.*' has faked external blobs and is non-functional: .*")
5608
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005609 def testPreLoad(self):
5610 """Test an image with a pre-load header"""
5611 entry_args = {
5612 'pre-load-key-path': '.',
5613 }
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005614 data, _, _, _ = self._DoReadFileDtb('230_pre_load.dts',
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005615 entry_args=entry_args)
5616 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5617 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5618 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005619 data = self._DoReadFile('230_pre_load.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005620 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5621 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5622 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5623
5624 def testPreLoadPkcs(self):
5625 """Test an image with a pre-load header with padding pkcs"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005626 data = self._DoReadFile('231_pre_load_pkcs.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005627 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5628 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5629 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5630
5631 def testPreLoadPss(self):
5632 """Test an image with a pre-load header with padding pss"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005633 data = self._DoReadFile('232_pre_load_pss.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005634 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5635 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5636 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5637
5638 def testPreLoadInvalidPadding(self):
5639 """Test an image with a pre-load header with an invalid padding"""
5640 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005641 data = self._DoReadFile('233_pre_load_invalid_padding.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005642
5643 def testPreLoadInvalidSha(self):
5644 """Test an image with a pre-load header with an invalid hash"""
5645 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005646 data = self._DoReadFile('234_pre_load_invalid_sha.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005647
5648 def testPreLoadInvalidAlgo(self):
5649 """Test an image with a pre-load header with an invalid algo"""
5650 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005651 data = self._DoReadFile('235_pre_load_invalid_algo.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005652
5653 def testPreLoadInvalidKey(self):
5654 """Test an image with a pre-load header with an invalid key"""
5655 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005656 data = self._DoReadFile('236_pre_load_invalid_key.dts')
Roger Quadros5cdcea02022-02-19 20:50:04 +02005657
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005658 def _CheckSafeUniqueNames(self, *images):
5659 """Check all entries of given images for unsafe unique names"""
5660 for image in images:
5661 entries = {}
5662 image._CollectEntries(entries, {}, image)
5663 for entry in entries.values():
5664 uniq = entry.GetUniqueName()
5665
5666 # Used as part of a filename, so must not be absolute paths.
5667 self.assertFalse(os.path.isabs(uniq))
5668
5669 def testSafeUniqueNames(self):
5670 """Test entry unique names are safe in single image configuration"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005671 data = self._DoReadFileRealDtb('237_unique_names.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005672
5673 orig_image = control.images['image']
5674 image_fname = tools.get_output_filename('image.bin')
5675 image = Image.FromFile(image_fname)
5676
5677 self._CheckSafeUniqueNames(orig_image, image)
5678
5679 def testSafeUniqueNamesMulti(self):
5680 """Test entry unique names are safe with multiple images"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005681 data = self._DoReadFileRealDtb('238_unique_names_multi.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005682
5683 orig_image = control.images['image']
5684 image_fname = tools.get_output_filename('image.bin')
5685 image = Image.FromFile(image_fname)
5686
5687 self._CheckSafeUniqueNames(orig_image, image)
5688
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005689 def testReplaceCmdWithBintool(self):
5690 """Test replacing an entry that needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005691 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005692 expected = U_BOOT_DATA + b'aa'
5693 self.assertEqual(expected, data[:len(expected)])
5694
5695 try:
5696 tmpdir, updated_fname = self._SetupImageInTmpdir()
5697 fname = os.path.join(tmpdir, 'update-testing.bin')
5698 tools.write_file(fname, b'zz')
5699 self._DoBinman('replace', '-i', updated_fname,
5700 '_testing', '-f', fname)
5701
5702 data = tools.read_file(updated_fname)
5703 expected = U_BOOT_DATA + b'zz'
5704 self.assertEqual(expected, data[:len(expected)])
5705 finally:
5706 shutil.rmtree(tmpdir)
5707
5708 def testReplaceCmdOtherWithBintool(self):
5709 """Test replacing an entry when another needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005710 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005711 expected = U_BOOT_DATA + b'aa'
5712 self.assertEqual(expected, data[:len(expected)])
5713
5714 try:
5715 tmpdir, updated_fname = self._SetupImageInTmpdir()
5716 fname = os.path.join(tmpdir, 'update-u-boot.bin')
5717 tools.write_file(fname, b'x' * len(U_BOOT_DATA))
5718 self._DoBinman('replace', '-i', updated_fname,
5719 'u-boot', '-f', fname)
5720
5721 data = tools.read_file(updated_fname)
5722 expected = b'x' * len(U_BOOT_DATA) + b'aa'
5723 self.assertEqual(expected, data[:len(expected)])
5724 finally:
5725 shutil.rmtree(tmpdir)
5726
Alper Nebi Yasak00c68f12022-03-27 18:31:46 +03005727 def testReplaceResizeNoRepackSameSize(self):
5728 """Test replacing entries with same-size data without repacking"""
5729 expected = b'x' * len(U_BOOT_DATA)
5730 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected)
5731 self.assertEqual(expected, data)
5732
5733 path, fdtmap = state.GetFdtContents('fdtmap')
5734 self.assertIsNotNone(path)
5735 self.assertEqual(expected_fdtmap, fdtmap)
5736
5737 def testReplaceResizeNoRepackSmallerSize(self):
5738 """Test replacing entries with smaller-size data without repacking"""
5739 new_data = b'x'
5740 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', new_data)
5741 expected = new_data.ljust(len(U_BOOT_DATA), b'\0')
5742 self.assertEqual(expected, data)
5743
5744 path, fdtmap = state.GetFdtContents('fdtmap')
5745 self.assertIsNotNone(path)
5746 self.assertEqual(expected_fdtmap, fdtmap)
5747
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005748 def testExtractFit(self):
5749 """Test extracting a FIT section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005750 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005751 image_fname = tools.get_output_filename('image.bin')
5752
5753 fit_data = control.ReadEntry(image_fname, 'fit')
5754 fit = fdt.Fdt.FromData(fit_data)
5755 fit.Scan()
5756
5757 # Check subentry data inside the extracted fit
5758 for node_path, expected in [
5759 ('/images/kernel', U_BOOT_DATA),
5760 ('/images/fdt-1', U_BOOT_NODTB_DATA),
5761 ('/images/scr-1', COMPRESS_DATA),
5762 ]:
5763 node = fit.GetNode(node_path)
5764 data = fit.GetProps(node)['data'].bytes
5765 self.assertEqual(expected, data)
5766
5767 def testExtractFitSubentries(self):
5768 """Test extracting FIT section subentries"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005769 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005770 image_fname = tools.get_output_filename('image.bin')
5771
5772 for entry_path, expected in [
5773 ('fit/kernel', U_BOOT_DATA),
5774 ('fit/kernel/u-boot', U_BOOT_DATA),
5775 ('fit/fdt-1', U_BOOT_NODTB_DATA),
5776 ('fit/fdt-1/u-boot-nodtb', U_BOOT_NODTB_DATA),
5777 ('fit/scr-1', COMPRESS_DATA),
5778 ('fit/scr-1/blob', COMPRESS_DATA),
5779 ]:
5780 data = control.ReadEntry(image_fname, entry_path)
5781 self.assertEqual(expected, data)
5782
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005783 def testReplaceFitSubentryLeafSameSize(self):
5784 """Test replacing a FIT leaf subentry with same-size data"""
5785 new_data = b'x' * len(U_BOOT_DATA)
5786 data, expected_fdtmap, _ = self._RunReplaceCmd(
5787 'fit/kernel/u-boot', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005788 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005789 self.assertEqual(new_data, data)
5790
5791 path, fdtmap = state.GetFdtContents('fdtmap')
5792 self.assertIsNotNone(path)
5793 self.assertEqual(expected_fdtmap, fdtmap)
5794
5795 def testReplaceFitSubentryLeafBiggerSize(self):
5796 """Test replacing a FIT leaf subentry with bigger-size data"""
5797 new_data = b'ub' * len(U_BOOT_NODTB_DATA)
5798 data, expected_fdtmap, _ = self._RunReplaceCmd(
5799 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005800 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005801 self.assertEqual(new_data, data)
5802
5803 # Will be repacked, so fdtmap must change
5804 path, fdtmap = state.GetFdtContents('fdtmap')
5805 self.assertIsNotNone(path)
5806 self.assertNotEqual(expected_fdtmap, fdtmap)
5807
5808 def testReplaceFitSubentryLeafSmallerSize(self):
5809 """Test replacing a FIT leaf subentry with smaller-size data"""
5810 new_data = b'x'
5811 expected = new_data.ljust(len(U_BOOT_NODTB_DATA), b'\0')
5812 data, expected_fdtmap, _ = self._RunReplaceCmd(
5813 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005814 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005815 self.assertEqual(expected, data)
5816
5817 path, fdtmap = state.GetFdtContents('fdtmap')
5818 self.assertIsNotNone(path)
5819 self.assertEqual(expected_fdtmap, fdtmap)
5820
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03005821 def testReplaceSectionSimple(self):
5822 """Test replacing a simple section with arbitrary data"""
5823 new_data = b'w' * len(COMPRESS_DATA + U_BOOT_DATA)
Simon Glassc6b283f2022-08-13 11:40:46 -06005824 with self.assertRaises(ValueError) as exc:
5825 self._RunReplaceCmd('section', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005826 dts='241_replace_section_simple.dts')
Simon Glassc6b283f2022-08-13 11:40:46 -06005827 self.assertIn(
5828 "Node '/section': Replacing sections is not implemented yet",
5829 str(exc.exception))
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03005830
Simon Glass8fbca772022-08-13 11:40:48 -06005831 def testMkimageImagename(self):
5832 """Test using mkimage with -n holding the data too"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005833 data = self._DoReadFile('242_mkimage_name.dts')
Simon Glass8fbca772022-08-13 11:40:48 -06005834
5835 # Check that the data appears in the file somewhere
5836 self.assertIn(U_BOOT_SPL_DATA, data)
5837
Simon Glassbb7d3bb2022-09-06 20:26:52 -06005838 # Get struct legacy_img_hdr -> ih_name
Simon Glass8fbca772022-08-13 11:40:48 -06005839 name = data[0x20:0x40]
5840
5841 # Build the filename that we expect to be placed in there, by virtue of
5842 # the -n paraameter
5843 expect = os.path.join(tools.get_output_dir(), 'mkimage.mkimage')
5844
5845 # Check that the image name is set to the temporary filename used
5846 self.assertEqual(expect.encode('utf-8')[:0x20], name)
5847
Simon Glassb1669752022-08-13 11:40:49 -06005848 def testMkimageImage(self):
5849 """Test using mkimage with -n holding the data too"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005850 data = self._DoReadFile('243_mkimage_image.dts')
Simon Glassb1669752022-08-13 11:40:49 -06005851
5852 # Check that the data appears in the file somewhere
5853 self.assertIn(U_BOOT_SPL_DATA, data)
5854
Simon Glassbb7d3bb2022-09-06 20:26:52 -06005855 # Get struct legacy_img_hdr -> ih_name
Simon Glassb1669752022-08-13 11:40:49 -06005856 name = data[0x20:0x40]
5857
5858 # Build the filename that we expect to be placed in there, by virtue of
5859 # the -n paraameter
5860 expect = os.path.join(tools.get_output_dir(), 'mkimage-n.mkimage')
5861
5862 # Check that the image name is set to the temporary filename used
5863 self.assertEqual(expect.encode('utf-8')[:0x20], name)
5864
5865 # Check the corect data is in the imagename file
5866 self.assertEqual(U_BOOT_DATA, tools.read_file(expect))
5867
5868 def testMkimageImageNoContent(self):
5869 """Test using mkimage with -n and no data"""
5870 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005871 self._DoReadFile('244_mkimage_image_no_content.dts')
Simon Glassb1669752022-08-13 11:40:49 -06005872 self.assertIn('Could not complete processing of contents',
5873 str(exc.exception))
5874
5875 def testMkimageImageBad(self):
5876 """Test using mkimage with imagename node and data-to-imagename"""
5877 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005878 self._DoReadFile('245_mkimage_image_bad.dts')
Simon Glassb1669752022-08-13 11:40:49 -06005879 self.assertIn('Cannot use both imagename node and data-to-imagename',
5880 str(exc.exception))
5881
Simon Glassbd5cd882022-08-13 11:40:50 -06005882 def testCollectionOther(self):
5883 """Test a collection where the data comes from another section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005884 data = self._DoReadFile('246_collection_other.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06005885 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
5886 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
5887 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
5888 data)
5889
5890 def testMkimageCollection(self):
5891 """Test using a collection referring to an entry in a mkimage entry"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005892 data = self._DoReadFile('247_mkimage_coll.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06005893 expect = U_BOOT_SPL_DATA + U_BOOT_DATA
5894 self.assertEqual(expect, data[:len(expect)])
5895
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02005896 def testCompressDtbPrependInvalid(self):
5897 """Test that invalid header is detected"""
5898 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005899 self._DoReadFileDtb('248_compress_dtb_prepend_invalid.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02005900 self.assertIn("Node '/binman/u-boot-dtb': Invalid prepend in "
5901 "'u-boot-dtb': 'invalid'", str(e.exception))
5902
5903 def testCompressDtbPrependLength(self):
5904 """Test that compress with length header works as expected"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005905 data = self._DoReadFileRealDtb('249_compress_dtb_prepend_length.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02005906 image = control.images['image']
5907 entries = image.GetEntries()
5908 self.assertIn('u-boot-dtb', entries)
5909 u_boot_dtb = entries['u-boot-dtb']
5910 self.assertIn('fdtmap', entries)
5911 fdtmap = entries['fdtmap']
5912
5913 image_fname = tools.get_output_filename('image.bin')
5914 orig = control.ReadEntry(image_fname, 'u-boot-dtb')
5915 dtb = fdt.Fdt.FromData(orig)
5916 dtb.Scan()
5917 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
5918 expected = {
5919 'u-boot:size': len(U_BOOT_DATA),
5920 'u-boot-dtb:uncomp-size': len(orig),
5921 'u-boot-dtb:size': u_boot_dtb.size,
5922 'fdtmap:size': fdtmap.size,
5923 'size': len(data),
5924 }
5925 self.assertEqual(expected, props)
5926
5927 # Check implementation
5928 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
5929 rest = data[len(U_BOOT_DATA):]
5930 comp_data_len = struct.unpack('<I', rest[:4])[0]
5931 comp_data = rest[4:4 + comp_data_len]
5932 orig2 = self._decompress(comp_data)
5933 self.assertEqual(orig, orig2)
5934
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02005935 def testInvalidCompress(self):
5936 """Test that invalid compress algorithm is detected"""
5937 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005938 self._DoTestFile('250_compress_dtb_invalid.dts')
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02005939 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
5940
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02005941 def testCompUtilCompressions(self):
5942 """Test compression algorithms"""
5943 for bintool in self.comp_bintools.values():
5944 self._CheckBintool(bintool)
5945 data = bintool.compress(COMPRESS_DATA)
5946 self.assertNotEqual(COMPRESS_DATA, data)
5947 orig = bintool.decompress(data)
5948 self.assertEquals(COMPRESS_DATA, orig)
5949
5950 def testCompUtilVersions(self):
5951 """Test tool version of compression algorithms"""
5952 for bintool in self.comp_bintools.values():
5953 self._CheckBintool(bintool)
5954 version = bintool.version()
5955 self.assertRegex(version, '^v?[0-9]+[0-9.]*')
5956
5957 def testCompUtilPadding(self):
5958 """Test padding of compression algorithms"""
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02005959 # Skip zstd because it doesn't support padding
5960 for bintool in [v for k,v in self.comp_bintools.items() if k != 'zstd']:
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02005961 self._CheckBintool(bintool)
5962 data = bintool.compress(COMPRESS_DATA)
5963 self.assertNotEqual(COMPRESS_DATA, data)
5964 data += tools.get_bytes(0, 64)
5965 orig = bintool.decompress(data)
5966 self.assertEquals(COMPRESS_DATA, orig)
5967
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02005968 def testCompressDtbZstd(self):
5969 """Test that zstd compress of device-tree files failed"""
5970 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005971 self._DoTestFile('251_compress_dtb_zstd.dts')
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02005972 self.assertIn("Node '/binman/u-boot-dtb': The zstd compression "
5973 "requires a length header", str(e.exception))
5974
Quentin Schulz9b5c6482022-09-02 15:10:48 +02005975 def testMkimageMultipleDataFiles(self):
5976 """Test passing multiple files to mkimage in a mkimage entry"""
5977 data = self._DoReadFile('252_mkimage_mult_data.dts')
5978 # Size of files are packed in their 4B big-endian format
5979 expect = struct.pack('>I', len(U_BOOT_TPL_DATA))
5980 expect += struct.pack('>I', len(U_BOOT_SPL_DATA))
5981 # Size info is always followed by a 4B zero value.
5982 expect += tools.get_bytes(0, 4)
5983 expect += U_BOOT_TPL_DATA
5984 # All but last files are 4B-aligned
5985 align_pad = len(U_BOOT_TPL_DATA) % 4
5986 if align_pad:
5987 expect += tools.get_bytes(0, align_pad)
5988 expect += U_BOOT_SPL_DATA
5989 self.assertEqual(expect, data[-len(expect):])
5990
5991 def testMkimageMultipleNoContent(self):
5992 """Test passing multiple data files to mkimage with one data file having no content"""
5993 with self.assertRaises(ValueError) as exc:
5994 self._DoReadFile('253_mkimage_mult_no_content.dts')
5995 self.assertIn('Could not complete processing of contents',
5996 str(exc.exception))
5997
Quentin Schulz0d3a9262022-09-02 15:10:49 +02005998 def testMkimageFilename(self):
5999 """Test using mkimage to build a binary with a filename"""
6000 retcode = self._DoTestFile('254_mkimage_filename.dts')
6001 self.assertEqual(0, retcode)
6002 fname = tools.get_output_filename('mkimage-test.bin')
6003 self.assertTrue(os.path.exists(fname))
6004
Simon Glass56d05412022-02-28 07:16:54 -07006005 def testVpl(self):
6006 """Test that an image with VPL and its device tree can be created"""
6007 # ELF file with a '__bss_size' symbol
6008 self._SetupVplElf()
6009 data = self._DoReadFile('255_u_boot_vpl.dts')
6010 self.assertEqual(U_BOOT_VPL_DATA + U_BOOT_VPL_DTB_DATA, data)
6011
6012 def testVplNoDtb(self):
6013 """Test that an image with vpl/u-boot-vpl-nodtb.bin can be created"""
6014 self._SetupVplElf()
6015 data = self._DoReadFile('256_u_boot_vpl_nodtb.dts')
6016 self.assertEqual(U_BOOT_VPL_NODTB_DATA,
6017 data[:len(U_BOOT_VPL_NODTB_DATA)])
6018
6019 def testExpandedVpl(self):
6020 """Test that an expanded entry type is selected for TPL when needed"""
6021 self._SetupVplElf()
6022
6023 entry_args = {
6024 'vpl-bss-pad': 'y',
6025 'vpl-dtb': 'y',
6026 }
6027 self._DoReadFileDtb('257_fdt_incl_vpl.dts', use_expanded=True,
6028 entry_args=entry_args)
6029 image = control.images['image']
6030 entries = image.GetEntries()
6031 self.assertEqual(1, len(entries))
6032
6033 # We only have u-boot-vpl, which be expanded
6034 self.assertIn('u-boot-vpl', entries)
6035 entry = entries['u-boot-vpl']
6036 self.assertEqual('u-boot-vpl-expanded', entry.etype)
6037 subent = entry.GetEntries()
6038 self.assertEqual(3, len(subent))
6039 self.assertIn('u-boot-vpl-nodtb', subent)
6040 self.assertIn('u-boot-vpl-bss-pad', subent)
6041 self.assertIn('u-boot-vpl-dtb', subent)
6042
6043 def testVplBssPadMissing(self):
6044 """Test that a missing symbol is detected"""
6045 self._SetupVplElf('u_boot_ucode_ptr')
6046 with self.assertRaises(ValueError) as e:
6047 self._DoReadFile('258_vpl_bss_pad.dts')
6048 self.assertIn('Expected __bss_size symbol in vpl/u-boot-vpl',
6049 str(e.exception))
6050
Neha Malcom Francis3eb4be32022-10-17 16:36:25 +05306051 def testSymlink(self):
6052 """Test that image files can be named"""
6053 retcode = self._DoTestFile('259_symlink.dts', debug=True, map=True)
6054 self.assertEqual(0, retcode)
6055 image = control.images['test_image']
6056 fname = tools.get_output_filename('test_image.bin')
6057 sname = tools.get_output_filename('symlink_to_test.bin')
6058 self.assertTrue(os.path.islink(sname))
6059 self.assertEqual(os.readlink(sname), fname)
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03006060
Simon Glass37f85de2022-10-20 18:22:47 -06006061 def testSymbolsElf(self):
6062 """Test binman can assign symbols embedded in an ELF file"""
6063 if not elf.ELF_TOOLS:
6064 self.skipTest('Python elftools not available')
6065 self._SetupTplElf('u_boot_binman_syms')
6066 self._SetupVplElf('u_boot_binman_syms')
6067 self._SetupSplElf('u_boot_binman_syms')
6068 data = self._DoReadFileDtb('260_symbols_elf.dts')[0]
6069 image_fname = tools.get_output_filename('image.bin')
6070
6071 image = control.images['image']
6072 entries = image.GetEntries()
6073
6074 for entry in entries.values():
6075 # No symbols in u-boot and it has faked contents anyway
6076 if entry.name == 'u-boot':
6077 continue
6078 edata = data[entry.image_pos:entry.image_pos + entry.size]
6079 efname = tools.get_output_filename(f'edata-{entry.name}')
6080 tools.write_file(efname, edata)
6081
6082 syms = elf.GetSymbolFileOffset(efname, ['_binman_u_boot'])
6083 re_name = re.compile('_binman_(u_boot_(.*))_prop_(.*)')
6084 for name, sym in syms.items():
6085 msg = 'test'
6086 val = elf.GetSymbolValue(sym, edata, msg)
6087 entry_m = re_name.match(name)
6088 if entry_m:
6089 ename, prop = entry_m.group(1), entry_m.group(3)
6090 entry, entry_name, prop_name = image.LookupEntry(entries,
6091 name, msg)
6092 if prop_name == 'offset':
6093 expect_val = entry.offset
6094 elif prop_name == 'image_pos':
6095 expect_val = entry.image_pos
6096 elif prop_name == 'size':
6097 expect_val = entry.size
6098 self.assertEqual(expect_val, val)
6099
6100 def testSymbolsElfBad(self):
6101 """Check error when trying to write symbols without the elftools lib"""
6102 if not elf.ELF_TOOLS:
6103 self.skipTest('Python elftools not available')
6104 self._SetupTplElf('u_boot_binman_syms')
6105 self._SetupVplElf('u_boot_binman_syms')
6106 self._SetupSplElf('u_boot_binman_syms')
6107 try:
6108 elf.ELF_TOOLS = False
6109 with self.assertRaises(ValueError) as exc:
6110 self._DoReadFileDtb('260_symbols_elf.dts')
6111 finally:
6112 elf.ELF_TOOLS = True
6113 self.assertIn(
6114 "Section '/binman': entry '/binman/u-boot-spl-elf': "
6115 'Cannot write symbols to an ELF file without Python elftools',
6116 str(exc.exception))
6117
Simon Glassde244162023-01-07 14:07:08 -07006118 def testSectionFilename(self):
6119 """Check writing of section contents to a file"""
6120 data = self._DoReadFile('261_section_fname.dts')
6121 expected = (b'&&' + U_BOOT_DATA + b'&&&' +
6122 tools.get_bytes(ord('!'), 7) +
6123 U_BOOT_DATA + tools.get_bytes(ord('&'), 12))
6124 self.assertEqual(expected, data)
6125
6126 sect_fname = tools.get_output_filename('outfile.bin')
6127 self.assertTrue(os.path.exists(sect_fname))
6128 sect_data = tools.read_file(sect_fname)
6129 self.assertEqual(U_BOOT_DATA, sect_data)
6130
Simon Glass1e9e61c2023-01-07 14:07:12 -07006131 def testAbsent(self):
6132 """Check handling of absent entries"""
6133 data = self._DoReadFile('262_absent.dts')
6134 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6135
Simon Glassad5cfe12023-01-07 14:07:14 -07006136 def testPackTeeOsOptional(self):
6137 """Test that an image with an optional TEE binary can be created"""
6138 entry_args = {
6139 'tee-os-path': 'tee.elf',
6140 }
6141 data = self._DoReadFileDtb('263_tee_os_opt.dts',
6142 entry_args=entry_args)[0]
6143 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6144
6145 def checkFitTee(self, dts, tee_fname):
6146 """Check that a tee-os entry works and returns data
6147
6148 Args:
6149 dts (str): Device tree filename to use
6150 tee_fname (str): filename containing tee-os
6151
6152 Returns:
6153 bytes: Image contents
6154 """
6155 if not elf.ELF_TOOLS:
6156 self.skipTest('Python elftools not available')
6157 entry_args = {
6158 'of-list': 'test-fdt1 test-fdt2',
6159 'default-dt': 'test-fdt2',
6160 'tee-os-path': tee_fname,
6161 }
6162 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
6163 data = self._DoReadFileDtb(dts, entry_args=entry_args,
6164 extra_indirs=[test_subdir])[0]
6165 return data
6166
6167 def testFitTeeOsOptionalFit(self):
6168 """Test an image with a FIT with an optional OP-TEE binary"""
6169 data = self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bin')
6170
6171 # There should be only one node, holding the data set up in SetUpClass()
6172 # for tee.bin
6173 dtb = fdt.Fdt.FromData(data)
6174 dtb.Scan()
6175 node = dtb.GetNode('/images/tee-1')
6176 self.assertEqual(TEE_ADDR,
6177 fdt_util.fdt32_to_cpu(node.props['load'].value))
6178 self.assertEqual(TEE_ADDR,
6179 fdt_util.fdt32_to_cpu(node.props['entry'].value))
6180 self.assertEqual(U_BOOT_DATA, node.props['data'].bytes)
6181
6182 def testFitTeeOsOptionalFitBad(self):
6183 """Test an image with a FIT with an optional OP-TEE binary"""
6184 with self.assertRaises(ValueError) as exc:
6185 self.checkFitTee('265_tee_os_opt_fit_bad.dts', 'tee.bin')
6186 self.assertIn(
6187 "Node '/binman/fit': subnode 'images/@tee-SEQ': Failed to read ELF file: Magic number does not match",
6188 str(exc.exception))
6189
6190 def testFitTeeOsBad(self):
6191 """Test an OP-TEE binary with wrong formats"""
6192 self.make_tee_bin('tee.bad1', 123)
6193 with self.assertRaises(ValueError) as exc:
6194 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad1')
6195 self.assertIn(
6196 "Node '/binman/fit/images/@tee-SEQ/tee-os': OP-TEE paged mode not supported",
6197 str(exc.exception))
6198
6199 self.make_tee_bin('tee.bad2', 0, b'extra data')
6200 with self.assertRaises(ValueError) as exc:
6201 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad2')
6202 self.assertIn(
6203 "Node '/binman/fit/images/@tee-SEQ/tee-os': Invalid OP-TEE file: size mismatch (expected 0x4, have 0xe)",
6204 str(exc.exception))
6205
Simon Glass63328f12023-01-07 14:07:15 -07006206 def testExtblobOptional(self):
6207 """Test an image with an external blob that is optional"""
6208 with test_util.capture_sys_output() as (stdout, stderr):
6209 data = self._DoReadFile('266_blob_ext_opt.dts')
6210 self.assertEqual(REFCODE_DATA, data)
6211 err = stderr.getvalue()
6212 self.assertRegex(
6213 err,
6214 "Image '.*' is missing external blobs but is still functional: missing")
6215
Simon Glass7447a9d2023-01-11 16:10:12 -07006216 def testSectionInner(self):
6217 """Test an inner section with a size"""
6218 data = self._DoReadFile('267_section_inner.dts')
6219 expected = U_BOOT_DATA + tools.get_bytes(0, 12)
6220 self.assertEqual(expected, data)
6221
Simon Glassa4948b22023-01-11 16:10:14 -07006222 def testNull(self):
6223 """Test an image with a null entry"""
6224 data = self._DoReadFile('268_null.dts')
6225 self.assertEqual(U_BOOT_DATA + b'\xff\xff\xff\xff' + U_BOOT_IMG_DATA, data)
6226
Simon Glassf1ee03b2023-01-11 16:10:16 -07006227 def testOverlap(self):
6228 """Test an image with a overlapping entry"""
6229 data = self._DoReadFile('269_overlap.dts')
6230 self.assertEqual(U_BOOT_DATA[:1] + b'aa' + U_BOOT_DATA[3:], data)
6231
6232 image = control.images['image']
6233 entries = image.GetEntries()
6234
6235 self.assertIn('inset', entries)
6236 inset = entries['inset']
6237 self.assertEqual(1, inset.offset);
6238 self.assertEqual(1, inset.image_pos);
6239 self.assertEqual(2, inset.size);
6240
6241 def testOverlapNull(self):
6242 """Test an image with a null overlap"""
6243 data = self._DoReadFile('270_overlap_null.dts')
6244 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6245
6246 # Check the FMAP
6247 fhdr, fentries = fmap_util.DecodeFmap(data[len(U_BOOT_DATA):])
6248 self.assertEqual(4, fhdr.nareas)
6249 fiter = iter(fentries)
6250
6251 fentry = next(fiter)
6252 self.assertEqual(b'SECTION', fentry.name)
6253 self.assertEqual(0, fentry.offset)
6254 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6255 self.assertEqual(0, fentry.flags)
6256
6257 fentry = next(fiter)
6258 self.assertEqual(b'U_BOOT', fentry.name)
6259 self.assertEqual(0, fentry.offset)
6260 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6261 self.assertEqual(0, fentry.flags)
6262
6263 # Make sure that the NULL entry appears in the FMAP
6264 fentry = next(fiter)
6265 self.assertEqual(b'NULL', fentry.name)
6266 self.assertEqual(1, fentry.offset)
6267 self.assertEqual(2, fentry.size)
6268 self.assertEqual(0, fentry.flags)
6269
6270 fentry = next(fiter)
6271 self.assertEqual(b'FMAP', fentry.name)
6272 self.assertEqual(len(U_BOOT_DATA), fentry.offset)
6273
6274 def testOverlapBad(self):
6275 """Test an image with a bad overlapping entry"""
6276 with self.assertRaises(ValueError) as exc:
6277 self._DoReadFile('271_overlap_bad.dts')
6278 self.assertIn(
6279 "Node '/binman/inset': Offset 0x10 (16) ending at 0x12 (18) must overlap with existing entries",
6280 str(exc.exception))
6281
6282 def testOverlapNoOffset(self):
6283 """Test an image with a bad overlapping entry"""
6284 with self.assertRaises(ValueError) as exc:
6285 self._DoReadFile('272_overlap_no_size.dts')
6286 self.assertIn(
6287 "Node '/binman/inset': 'fill' entry is missing properties: size",
6288 str(exc.exception))
6289
Simon Glasse0035c92023-01-11 16:10:17 -07006290 def testBlobSymbol(self):
6291 """Test a blob with symbols read from an ELF file"""
6292 elf_fname = self.ElfTestFile('blob_syms')
6293 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6294 TestFunctional._MakeInputFile('blob_syms.bin',
6295 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6296
6297 data = self._DoReadFile('273_blob_symbol.dts')
6298
6299 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6300 addr = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6301 self.assertEqual(syms['_binman_sym_magic'].address, addr)
6302 self.assertEqual(syms['_binman_inset_prop_offset'].address, addr + 4)
6303 self.assertEqual(syms['_binman_inset_prop_size'].address, addr + 8)
6304
6305 sym_values = struct.pack('<LLL', elf.BINMAN_SYM_MAGIC_VALUE, 4, 8)
6306 expected = sym_values
6307 self.assertEqual(expected, data[:len(expected)])
6308
Simon Glass49e9c002023-01-11 16:10:19 -07006309 def testOffsetFromElf(self):
6310 """Test a blob with symbols read from an ELF file"""
6311 elf_fname = self.ElfTestFile('blob_syms')
6312 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6313 TestFunctional._MakeInputFile('blob_syms.bin',
6314 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6315
6316 data = self._DoReadFile('274_offset_from_elf.dts')
6317
6318 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6319 base = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6320
6321 image = control.images['image']
6322 entries = image.GetEntries()
6323
6324 self.assertIn('inset', entries)
6325 inset = entries['inset']
6326
6327 self.assertEqual(base + 4, inset.offset);
6328 self.assertEqual(base + 4, inset.image_pos);
6329 self.assertEqual(4, inset.size);
6330
6331 self.assertIn('inset2', entries)
6332 inset = entries['inset2']
6333 self.assertEqual(base + 8, inset.offset);
6334 self.assertEqual(base + 8, inset.image_pos);
6335 self.assertEqual(4, inset.size);
6336
Jonas Karlmanc59ea892023-01-21 19:01:39 +00006337 def testFitAlign(self):
6338 """Test an image with an FIT with aligned external data"""
6339 data = self._DoReadFile('275_fit_align.dts')
6340 self.assertEqual(4096, len(data))
6341
6342 dtb = fdt.Fdt.FromData(data)
6343 dtb.Scan()
6344
6345 props = self._GetPropTree(dtb, ['data-position'])
6346 expected = {
6347 'u-boot:data-position': 1024,
6348 'fdt-1:data-position': 2048,
6349 'fdt-2:data-position': 3072,
6350 }
6351 self.assertEqual(expected, props)
6352
Jonas Karlman490f73c2023-01-21 19:02:12 +00006353 def testFitFirmwareLoadables(self):
6354 """Test an image with an FIT that use fit,firmware"""
6355 if not elf.ELF_TOOLS:
6356 self.skipTest('Python elftools not available')
6357 entry_args = {
6358 'of-list': 'test-fdt1',
6359 'default-dt': 'test-fdt1',
6360 'atf-bl31-path': 'bl31.elf',
6361 'tee-os-path': 'missing.bin',
6362 }
6363 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
Simon Glass62f85902023-02-23 18:18:01 -07006364 with test_util.capture_sys_output() as (stdout, stderr):
6365 data = self._DoReadFileDtb(
6366 '276_fit_firmware_loadables.dts',
6367 entry_args=entry_args,
6368 extra_indirs=[test_subdir])[0]
Jonas Karlman490f73c2023-01-21 19:02:12 +00006369
6370 dtb = fdt.Fdt.FromData(data)
6371 dtb.Scan()
6372
6373 node = dtb.GetNode('/configurations/conf-uboot-1')
6374 self.assertEqual('u-boot', node.props['firmware'].value)
6375 self.assertEqual(['atf-1', 'atf-2'],
6376 fdt_util.GetStringList(node, 'loadables'))
6377
6378 node = dtb.GetNode('/configurations/conf-atf-1')
6379 self.assertEqual('atf-1', node.props['firmware'].value)
6380 self.assertEqual(['u-boot', 'atf-2'],
6381 fdt_util.GetStringList(node, 'loadables'))
6382
6383 node = dtb.GetNode('/configurations/conf-missing-uboot-1')
6384 self.assertEqual('u-boot', node.props['firmware'].value)
6385 self.assertEqual(['atf-1', 'atf-2'],
6386 fdt_util.GetStringList(node, 'loadables'))
6387
6388 node = dtb.GetNode('/configurations/conf-missing-atf-1')
6389 self.assertEqual('atf-1', node.props['firmware'].value)
6390 self.assertEqual(['u-boot', 'atf-2'],
6391 fdt_util.GetStringList(node, 'loadables'))
6392
6393 node = dtb.GetNode('/configurations/conf-missing-tee-1')
6394 self.assertEqual('atf-1', node.props['firmware'].value)
6395 self.assertEqual(['u-boot', 'atf-2'],
6396 fdt_util.GetStringList(node, 'loadables'))
6397
Simon Glass9a1c7262023-02-22 12:14:49 -07006398 def testTooldir(self):
6399 """Test that we can specify the tooldir"""
6400 with test_util.capture_sys_output() as (stdout, stderr):
6401 self.assertEqual(0, self._DoBinman('--tooldir', 'fred',
6402 'tool', '-l'))
6403 self.assertEqual('fred', bintool.Bintool.tooldir)
6404
6405 # Check that the toolpath is updated correctly
6406 self.assertEqual(['fred'], tools.tool_search_paths)
6407
6408 # Try with a few toolpaths; the tooldir should be at the end
6409 with test_util.capture_sys_output() as (stdout, stderr):
6410 self.assertEqual(0, self._DoBinman(
6411 '--toolpath', 'mary', '--toolpath', 'anna', '--tooldir', 'fred',
6412 'tool', '-l'))
6413 self.assertEqual(['mary', 'anna', 'fred'], tools.tool_search_paths)
6414
Simon Glassde244162023-01-07 14:07:08 -07006415
Simon Glassac599912017-11-12 21:52:22 -07006416if __name__ == "__main__":
6417 unittest.main()