blob: 0b3bca90c8c42b052bdc00a8fe8da2cd63080c7b [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 Glassa997ea52020-04-17 18:09:04 -060037from patman import command
38from patman import test_util
39from patman import tools
40from patman 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):
4002 """Test that binman still produces a FIT image if mkimage is missing"""
4003 with test_util.capture_sys_output() as (_, stderr):
4004 self._DoTestFile('162_fit_external.dts',
4005 force_missing_bintools='mkimage')
4006 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004007 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass66152ce2022-01-09 20:14:09 -07004008
Alper Nebi Yasak6aae2392020-08-31 12:58:18 +03004009 def testSectionIgnoreHashSignature(self):
4010 """Test that sections ignore hash, signature nodes for its data"""
4011 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
4012 expected = (U_BOOT_DATA + U_BOOT_DATA)
4013 self.assertEqual(expected, data)
4014
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03004015 def testPadInSections(self):
4016 """Test pad-before, pad-after for entries in sections"""
Simon Glassd12599d2020-10-26 17:40:09 -06004017 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4018 '166_pad_in_sections.dts', update_dtb=True)
Simon Glass80025522022-01-29 14:14:04 -07004019 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4020 U_BOOT_DATA + tools.get_bytes(ord('!'), 6) +
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03004021 U_BOOT_DATA)
4022 self.assertEqual(expected, data)
4023
Simon Glassd12599d2020-10-26 17:40:09 -06004024 dtb = fdt.Fdt(out_dtb_fname)
4025 dtb.Scan()
4026 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
4027 expected = {
4028 'image-pos': 0,
4029 'offset': 0,
4030 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
4031
4032 'section:image-pos': 0,
4033 'section:offset': 0,
4034 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
4035
4036 'section/before:image-pos': 0,
4037 'section/before:offset': 0,
4038 'section/before:size': len(U_BOOT_DATA),
4039
4040 'section/u-boot:image-pos': 4,
4041 'section/u-boot:offset': 4,
4042 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
4043
4044 'section/after:image-pos': 26,
4045 'section/after:offset': 26,
4046 'section/after:size': len(U_BOOT_DATA),
4047 }
4048 self.assertEqual(expected, props)
4049
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004050 def testFitImageSubentryAlignment(self):
4051 """Test relative alignability of FIT image subentries"""
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03004052 self._SetupSplElf()
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004053 entry_args = {
4054 'test-id': TEXT_DATA,
4055 }
4056 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
4057 entry_args=entry_args)
4058 dtb = fdt.Fdt.FromData(data)
4059 dtb.Scan()
4060
4061 node = dtb.GetNode('/images/kernel')
4062 data = dtb.GetProps(node)["data"].bytes
4063 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
Simon Glass80025522022-01-29 14:14:04 -07004064 expected = (tools.get_bytes(0, 0x20) + U_BOOT_SPL_DATA +
4065 tools.get_bytes(0, align_pad) + U_BOOT_DATA)
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004066 self.assertEqual(expected, data)
4067
4068 node = dtb.GetNode('/images/fdt-1')
4069 data = dtb.GetProps(node)["data"].bytes
Simon Glass80025522022-01-29 14:14:04 -07004070 expected = (U_BOOT_SPL_DTB_DATA + tools.get_bytes(0, 20) +
4071 tools.to_bytes(TEXT_DATA) + tools.get_bytes(0, 30) +
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004072 U_BOOT_DTB_DATA)
4073 self.assertEqual(expected, data)
4074
4075 def testFitExtblobMissingOk(self):
4076 """Test a FIT with a missing external blob that is allowed"""
4077 with test_util.capture_sys_output() as (stdout, stderr):
4078 self._DoTestFile('168_fit_missing_blob.dts',
4079 allow_missing=True)
4080 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004081 self.assertRegex(err, "Image 'image'.*missing.*: atf-bl31")
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004082
Simon Glass21db0ff2020-09-01 05:13:54 -06004083 def testBlobNamedByArgMissing(self):
4084 """Test handling of a missing entry arg"""
4085 with self.assertRaises(ValueError) as e:
4086 self._DoReadFile('068_blob_named_by_arg.dts')
4087 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
4088 str(e.exception))
4089
Simon Glass559c4de2020-09-01 05:13:58 -06004090 def testPackBl31(self):
4091 """Test that an image with an ATF BL31 binary can be created"""
4092 data = self._DoReadFile('169_atf_bl31.dts')
4093 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
4094
Samuel Holland9d8cc632020-10-21 21:12:15 -05004095 def testPackScp(self):
4096 """Test that an image with an SCP binary can be created"""
4097 data = self._DoReadFile('172_scp.dts')
4098 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
4099
Simon Glassa435cd12020-09-01 05:13:59 -06004100 def testFitFdt(self):
4101 """Test an image with an FIT with multiple FDT images"""
4102 def _CheckFdt(seq, expected_data):
4103 """Check the FDT nodes
4104
4105 Args:
4106 seq: Sequence number to check (0 or 1)
4107 expected_data: Expected contents of 'data' property
4108 """
4109 name = 'fdt-%d' % seq
4110 fnode = dtb.GetNode('/images/%s' % name)
4111 self.assertIsNotNone(fnode)
4112 self.assertEqual({'description','type', 'compression', 'data'},
4113 set(fnode.props.keys()))
4114 self.assertEqual(expected_data, fnode.props['data'].bytes)
4115 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
4116 fnode.props['description'].value)
Jan Kiszkaa1419df2022-02-28 17:06:20 +01004117 self.assertEqual(fnode.subnodes[0].name, 'hash')
Simon Glassa435cd12020-09-01 05:13:59 -06004118
4119 def _CheckConfig(seq, expected_data):
4120 """Check the configuration nodes
4121
4122 Args:
4123 seq: Sequence number to check (0 or 1)
4124 expected_data: Expected contents of 'data' property
4125 """
4126 cnode = dtb.GetNode('/configurations')
4127 self.assertIn('default', cnode.props)
Simon Glass1032acc2020-09-06 10:39:08 -06004128 self.assertEqual('config-2', cnode.props['default'].value)
Simon Glassa435cd12020-09-01 05:13:59 -06004129
4130 name = 'config-%d' % seq
4131 fnode = dtb.GetNode('/configurations/%s' % name)
4132 self.assertIsNotNone(fnode)
4133 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
4134 set(fnode.props.keys()))
4135 self.assertEqual('conf-test-fdt%d.dtb' % seq,
4136 fnode.props['description'].value)
4137 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
4138
4139 entry_args = {
4140 'of-list': 'test-fdt1 test-fdt2',
Simon Glass1032acc2020-09-06 10:39:08 -06004141 'default-dt': 'test-fdt2',
Simon Glassa435cd12020-09-01 05:13:59 -06004142 }
4143 data = self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004144 '170_fit_fdt.dts',
Simon Glassa435cd12020-09-01 05:13:59 -06004145 entry_args=entry_args,
4146 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4147 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4148 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4149
4150 dtb = fdt.Fdt.FromData(fit_data)
4151 dtb.Scan()
4152 fnode = dtb.GetNode('/images/kernel')
4153 self.assertIn('data', fnode.props)
4154
4155 # Check all the properties in fdt-1 and fdt-2
4156 _CheckFdt(1, TEST_FDT1_DATA)
4157 _CheckFdt(2, TEST_FDT2_DATA)
4158
4159 # Check configurations
4160 _CheckConfig(1, TEST_FDT1_DATA)
4161 _CheckConfig(2, TEST_FDT2_DATA)
4162
4163 def testFitFdtMissingList(self):
4164 """Test handling of a missing 'of-list' entry arg"""
4165 with self.assertRaises(ValueError) as e:
Bin Meng16cf5662021-05-10 20:23:32 +08004166 self._DoReadFile('170_fit_fdt.dts')
Simon Glassa435cd12020-09-01 05:13:59 -06004167 self.assertIn("Generator node requires 'of-list' entry argument",
4168 str(e.exception))
4169
4170 def testFitFdtEmptyList(self):
4171 """Test handling of an empty 'of-list' entry arg"""
4172 entry_args = {
4173 'of-list': '',
4174 }
4175 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
4176
4177 def testFitFdtMissingProp(self):
4178 """Test handling of a missing 'fit,fdt-list' property"""
4179 with self.assertRaises(ValueError) as e:
4180 self._DoReadFile('171_fit_fdt_missing_prop.dts')
4181 self.assertIn("Generator node requires 'fit,fdt-list' property",
4182 str(e.exception))
Simon Glass559c4de2020-09-01 05:13:58 -06004183
Simon Glass1032acc2020-09-06 10:39:08 -06004184 def testFitFdtMissing(self):
4185 """Test handling of a missing 'default-dt' entry arg"""
4186 entry_args = {
4187 'of-list': 'test-fdt1 test-fdt2',
4188 }
4189 with self.assertRaises(ValueError) as e:
4190 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004191 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004192 entry_args=entry_args,
4193 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4194 self.assertIn("Generated 'default' node requires default-dt entry argument",
4195 str(e.exception))
4196
4197 def testFitFdtNotInList(self):
4198 """Test handling of a default-dt that is not in the of-list"""
4199 entry_args = {
4200 'of-list': 'test-fdt1 test-fdt2',
4201 'default-dt': 'test-fdt3',
4202 }
4203 with self.assertRaises(ValueError) as e:
4204 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004205 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004206 entry_args=entry_args,
4207 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4208 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
4209 str(e.exception))
4210
Simon Glassa820af72020-09-06 10:39:09 -06004211 def testFitExtblobMissingHelp(self):
4212 """Test display of help messages when an external blob is missing"""
4213 control.missing_blob_help = control._ReadMissingBlobHelp()
4214 control.missing_blob_help['wibble'] = 'Wibble test'
4215 control.missing_blob_help['another'] = 'Another test'
4216 with test_util.capture_sys_output() as (stdout, stderr):
4217 self._DoTestFile('168_fit_missing_blob.dts',
4218 allow_missing=True)
4219 err = stderr.getvalue()
4220
4221 # We can get the tag from the name, the type or the missing-msg
4222 # property. Check all three.
4223 self.assertIn('You may need to build ARM Trusted', err)
4224 self.assertIn('Wibble test', err)
4225 self.assertIn('Another test', err)
4226
Simon Glass6f1f4d42020-09-06 10:35:32 -06004227 def testMissingBlob(self):
4228 """Test handling of a blob containing a missing file"""
4229 with self.assertRaises(ValueError) as e:
4230 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
4231 self.assertIn("Filename 'missing' not found in input path",
4232 str(e.exception))
4233
Simon Glassa0729502020-09-06 10:35:33 -06004234 def testEnvironment(self):
4235 """Test adding a U-Boot environment"""
4236 data = self._DoReadFile('174_env.dts')
4237 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
4238 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4239 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4240 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
4241 env)
4242
4243 def testEnvironmentNoSize(self):
4244 """Test that a missing 'size' property is detected"""
4245 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004246 self._DoTestFile('175_env_no_size.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004247 self.assertIn("'u-boot-env' entry must have a size property",
4248 str(e.exception))
4249
4250 def testEnvironmentTooSmall(self):
4251 """Test handling of an environment that does not fit"""
4252 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004253 self._DoTestFile('176_env_too_small.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004254
4255 # checksum, start byte, environment with \0 terminator, final \0
4256 need = 4 + 1 + len(ENV_DATA) + 1 + 1
4257 short = need - 0x8
4258 self.assertIn("too small to hold data (need %#x more bytes)" % short,
4259 str(e.exception))
4260
Simon Glassd1fdf752020-10-26 17:40:01 -06004261 def testSkipAtStart(self):
4262 """Test handling of skip-at-start section"""
4263 data = self._DoReadFile('177_skip_at_start.dts')
4264 self.assertEqual(U_BOOT_DATA, data)
4265
4266 image = control.images['image']
4267 entries = image.GetEntries()
4268 section = entries['section']
4269 self.assertEqual(0, section.offset)
4270 self.assertEqual(len(U_BOOT_DATA), section.size)
4271 self.assertEqual(U_BOOT_DATA, section.GetData())
4272
4273 entry = section.GetEntries()['u-boot']
4274 self.assertEqual(16, entry.offset)
4275 self.assertEqual(len(U_BOOT_DATA), entry.size)
4276 self.assertEqual(U_BOOT_DATA, entry.data)
4277
4278 def testSkipAtStartPad(self):
4279 """Test handling of skip-at-start section with padded entry"""
4280 data = self._DoReadFile('178_skip_at_start_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004281 before = tools.get_bytes(0, 8)
4282 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004283 all = before + U_BOOT_DATA + after
4284 self.assertEqual(all, data)
4285
4286 image = control.images['image']
4287 entries = image.GetEntries()
4288 section = entries['section']
4289 self.assertEqual(0, section.offset)
4290 self.assertEqual(len(all), section.size)
4291 self.assertEqual(all, section.GetData())
4292
4293 entry = section.GetEntries()['u-boot']
4294 self.assertEqual(16, entry.offset)
4295 self.assertEqual(len(all), entry.size)
4296 self.assertEqual(U_BOOT_DATA, entry.data)
4297
4298 def testSkipAtStartSectionPad(self):
4299 """Test handling of skip-at-start section with padding"""
4300 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004301 before = tools.get_bytes(0, 8)
4302 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004303 all = before + U_BOOT_DATA + after
Simon Glass510ef0f2020-10-26 17:40:13 -06004304 self.assertEqual(all, data)
Simon Glassd1fdf752020-10-26 17:40:01 -06004305
4306 image = control.images['image']
4307 entries = image.GetEntries()
4308 section = entries['section']
4309 self.assertEqual(0, section.offset)
4310 self.assertEqual(len(all), section.size)
Simon Glass72eeff12020-10-26 17:40:16 -06004311 self.assertEqual(U_BOOT_DATA, section.data)
Simon Glass510ef0f2020-10-26 17:40:13 -06004312 self.assertEqual(all, section.GetPaddedData())
Simon Glassd1fdf752020-10-26 17:40:01 -06004313
4314 entry = section.GetEntries()['u-boot']
4315 self.assertEqual(16, entry.offset)
4316 self.assertEqual(len(U_BOOT_DATA), entry.size)
4317 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassa0729502020-09-06 10:35:33 -06004318
Simon Glassbb395742020-10-26 17:40:14 -06004319 def testSectionPad(self):
4320 """Testing padding with sections"""
4321 data = self._DoReadFile('180_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004322 expected = (tools.get_bytes(ord('&'), 3) +
4323 tools.get_bytes(ord('!'), 5) +
Simon Glassbb395742020-10-26 17:40:14 -06004324 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004325 tools.get_bytes(ord('!'), 1) +
4326 tools.get_bytes(ord('&'), 2))
Simon Glassbb395742020-10-26 17:40:14 -06004327 self.assertEqual(expected, data)
4328
4329 def testSectionAlign(self):
4330 """Testing alignment with sections"""
4331 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4332 expected = (b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004333 tools.get_bytes(ord('&'), 1) + # padding to section align
Simon Glassbb395742020-10-26 17:40:14 -06004334 b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004335 tools.get_bytes(ord('!'), 3) + # padding to u-boot align
Simon Glassbb395742020-10-26 17:40:14 -06004336 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004337 tools.get_bytes(ord('!'), 4) + # padding to u-boot size
4338 tools.get_bytes(ord('!'), 4)) # padding to section size
Simon Glassbb395742020-10-26 17:40:14 -06004339 self.assertEqual(expected, data)
4340
Simon Glassd92c8362020-10-26 17:40:25 -06004341 def testCompressImage(self):
4342 """Test compression of the entire image"""
4343 self._CheckLz4()
4344 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4345 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4346 dtb = fdt.Fdt(out_dtb_fname)
4347 dtb.Scan()
4348 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4349 'uncomp-size'])
4350 orig = self._decompress(data)
4351 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4352
4353 # Do a sanity check on various fields
4354 image = control.images['image']
4355 entries = image.GetEntries()
4356 self.assertEqual(2, len(entries))
4357
4358 entry = entries['blob']
4359 self.assertEqual(COMPRESS_DATA, entry.data)
4360 self.assertEqual(len(COMPRESS_DATA), entry.size)
4361
4362 entry = entries['u-boot']
4363 self.assertEqual(U_BOOT_DATA, entry.data)
4364 self.assertEqual(len(U_BOOT_DATA), entry.size)
4365
4366 self.assertEqual(len(data), image.size)
4367 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4368 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4369 orig = self._decompress(image.data)
4370 self.assertEqual(orig, image.uncomp_data)
4371
4372 expected = {
4373 'blob:offset': 0,
4374 'blob:size': len(COMPRESS_DATA),
4375 'u-boot:offset': len(COMPRESS_DATA),
4376 'u-boot:size': len(U_BOOT_DATA),
4377 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4378 'offset': 0,
4379 'image-pos': 0,
4380 'size': len(data),
4381 }
4382 self.assertEqual(expected, props)
4383
4384 def testCompressImageLess(self):
4385 """Test compression where compression reduces the image size"""
4386 self._CheckLz4()
4387 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4388 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4389 dtb = fdt.Fdt(out_dtb_fname)
4390 dtb.Scan()
4391 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4392 'uncomp-size'])
4393 orig = self._decompress(data)
4394
4395 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
4396
4397 # Do a sanity check on various fields
4398 image = control.images['image']
4399 entries = image.GetEntries()
4400 self.assertEqual(2, len(entries))
4401
4402 entry = entries['blob']
4403 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4404 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4405
4406 entry = entries['u-boot']
4407 self.assertEqual(U_BOOT_DATA, entry.data)
4408 self.assertEqual(len(U_BOOT_DATA), entry.size)
4409
4410 self.assertEqual(len(data), image.size)
4411 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4412 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4413 image.uncomp_size)
4414 orig = self._decompress(image.data)
4415 self.assertEqual(orig, image.uncomp_data)
4416
4417 expected = {
4418 'blob:offset': 0,
4419 'blob:size': len(COMPRESS_DATA_BIG),
4420 'u-boot:offset': len(COMPRESS_DATA_BIG),
4421 'u-boot:size': len(U_BOOT_DATA),
4422 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4423 'offset': 0,
4424 'image-pos': 0,
4425 'size': len(data),
4426 }
4427 self.assertEqual(expected, props)
4428
4429 def testCompressSectionSize(self):
4430 """Test compression of a section with a fixed size"""
4431 self._CheckLz4()
4432 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4433 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4434 dtb = fdt.Fdt(out_dtb_fname)
4435 dtb.Scan()
4436 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4437 'uncomp-size'])
4438 orig = self._decompress(data)
4439 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4440 expected = {
4441 'section/blob:offset': 0,
4442 'section/blob:size': len(COMPRESS_DATA),
4443 'section/u-boot:offset': len(COMPRESS_DATA),
4444 'section/u-boot:size': len(U_BOOT_DATA),
4445 'section:offset': 0,
4446 'section:image-pos': 0,
4447 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4448 'section:size': 0x30,
4449 'offset': 0,
4450 'image-pos': 0,
4451 'size': 0x30,
4452 }
4453 self.assertEqual(expected, props)
4454
4455 def testCompressSection(self):
4456 """Test compression of a section with no fixed size"""
4457 self._CheckLz4()
4458 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4459 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4460 dtb = fdt.Fdt(out_dtb_fname)
4461 dtb.Scan()
4462 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4463 'uncomp-size'])
4464 orig = self._decompress(data)
4465 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4466 expected = {
4467 'section/blob:offset': 0,
4468 'section/blob:size': len(COMPRESS_DATA),
4469 'section/u-boot:offset': len(COMPRESS_DATA),
4470 'section/u-boot:size': len(U_BOOT_DATA),
4471 'section:offset': 0,
4472 'section:image-pos': 0,
4473 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4474 'section:size': len(data),
4475 'offset': 0,
4476 'image-pos': 0,
4477 'size': len(data),
4478 }
4479 self.assertEqual(expected, props)
4480
Stefan Herbrechtsmeier94813a02022-08-19 16:25:31 +02004481 def testLz4Missing(self):
4482 """Test that binman still produces an image if lz4 is missing"""
4483 with test_util.capture_sys_output() as (_, stderr):
4484 self._DoTestFile('185_compress_section.dts',
4485 force_missing_bintools='lz4')
4486 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004487 self.assertRegex(err, "Image 'image'.*missing bintools.*: lz4")
Stefan Herbrechtsmeier94813a02022-08-19 16:25:31 +02004488
Simon Glassd92c8362020-10-26 17:40:25 -06004489 def testCompressExtra(self):
4490 """Test compression of a section with no fixed size"""
4491 self._CheckLz4()
4492 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4493 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4494 dtb = fdt.Fdt(out_dtb_fname)
4495 dtb.Scan()
4496 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4497 'uncomp-size'])
4498
4499 base = data[len(U_BOOT_DATA):]
4500 self.assertEquals(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
4501 rest = base[len(U_BOOT_DATA):]
4502
4503 # Check compressed data
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02004504 bintool = self.comp_bintools['lz4']
4505 expect1 = bintool.compress(COMPRESS_DATA + U_BOOT_DATA)
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004506 data1 = rest[:len(expect1)]
4507 section1 = self._decompress(data1)
4508 self.assertEquals(expect1, data1)
Simon Glassd92c8362020-10-26 17:40:25 -06004509 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, section1)
4510 rest1 = rest[len(expect1):]
4511
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02004512 expect2 = bintool.compress(COMPRESS_DATA + COMPRESS_DATA)
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004513 data2 = rest1[:len(expect2)]
4514 section2 = self._decompress(data2)
4515 self.assertEquals(expect2, data2)
Simon Glassd92c8362020-10-26 17:40:25 -06004516 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA, section2)
4517 rest2 = rest1[len(expect2):]
4518
4519 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4520 len(expect2) + len(U_BOOT_DATA))
4521 #self.assertEquals(expect_size, len(data))
4522
4523 #self.assertEquals(U_BOOT_DATA, rest2)
4524
4525 self.maxDiff = None
4526 expected = {
4527 'u-boot:offset': 0,
4528 'u-boot:image-pos': 0,
4529 'u-boot:size': len(U_BOOT_DATA),
4530
4531 'base:offset': len(U_BOOT_DATA),
4532 'base:image-pos': len(U_BOOT_DATA),
4533 'base:size': len(data) - len(U_BOOT_DATA),
4534 'base/u-boot:offset': 0,
4535 'base/u-boot:image-pos': len(U_BOOT_DATA),
4536 'base/u-boot:size': len(U_BOOT_DATA),
4537 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4538 len(expect2),
4539 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4540 len(expect2),
4541 'base/u-boot2:size': len(U_BOOT_DATA),
4542
4543 'base/section:offset': len(U_BOOT_DATA),
4544 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4545 'base/section:size': len(expect1),
4546 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4547 'base/section/blob:offset': 0,
4548 'base/section/blob:size': len(COMPRESS_DATA),
4549 'base/section/u-boot:offset': len(COMPRESS_DATA),
4550 'base/section/u-boot:size': len(U_BOOT_DATA),
4551
4552 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4553 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4554 'base/section2:size': len(expect2),
4555 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4556 'base/section2/blob:offset': 0,
4557 'base/section2/blob:size': len(COMPRESS_DATA),
4558 'base/section2/blob2:offset': len(COMPRESS_DATA),
4559 'base/section2/blob2:size': len(COMPRESS_DATA),
4560
4561 'offset': 0,
4562 'image-pos': 0,
4563 'size': len(data),
4564 }
4565 self.assertEqual(expected, props)
4566
Simon Glassecbe4732021-01-06 21:35:15 -07004567 def testSymbolsSubsection(self):
4568 """Test binman can assign symbols from a subsection"""
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03004569 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glassecbe4732021-01-06 21:35:15 -07004570
Simon Glass3fb25402021-01-06 21:35:16 -07004571 def testReadImageEntryArg(self):
4572 """Test reading an image that would need an entry arg to generate"""
4573 entry_args = {
4574 'cros-ec-rw-path': 'ecrw.bin',
4575 }
4576 data = self.data = self._DoReadFileDtb(
4577 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4578 entry_args=entry_args)
4579
Simon Glass80025522022-01-29 14:14:04 -07004580 image_fname = tools.get_output_filename('image.bin')
Simon Glass3fb25402021-01-06 21:35:16 -07004581 orig_image = control.images['image']
4582
4583 # This should not generate an error about the missing 'cros-ec-rw-path'
4584 # since we are reading the image from a file. Compare with
4585 # testEntryArgsRequired()
4586 image = Image.FromFile(image_fname)
4587 self.assertEqual(orig_image.GetEntries().keys(),
4588 image.GetEntries().keys())
4589
Simon Glassa2af7302021-01-06 21:35:18 -07004590 def testFilesAlign(self):
4591 """Test alignment with files"""
4592 data = self._DoReadFile('190_files_align.dts')
4593
4594 # The first string is 15 bytes so will align to 16
4595 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4596 self.assertEqual(expect, data)
4597
Simon Glassdb84b562021-01-06 21:35:19 -07004598 def testReadImageSkip(self):
4599 """Test reading an image and accessing its FDT map"""
4600 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
Simon Glass80025522022-01-29 14:14:04 -07004601 image_fname = tools.get_output_filename('image.bin')
Simon Glassdb84b562021-01-06 21:35:19 -07004602 orig_image = control.images['image']
4603 image = Image.FromFile(image_fname)
4604 self.assertEqual(orig_image.GetEntries().keys(),
4605 image.GetEntries().keys())
4606
4607 orig_entry = orig_image.GetEntries()['fdtmap']
4608 entry = image.GetEntries()['fdtmap']
4609 self.assertEqual(orig_entry.offset, entry.offset)
4610 self.assertEqual(orig_entry.size, entry.size)
4611 self.assertEqual(16, entry.image_pos)
4612
4613 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4614
4615 self.assertEquals(U_BOOT_DATA, u_boot.ReadData())
4616
Simon Glassc98de972021-03-18 20:24:57 +13004617 def testTplNoDtb(self):
4618 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12004619 self._SetupTplElf()
Simon Glassc98de972021-03-18 20:24:57 +13004620 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4621 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4622 data[:len(U_BOOT_TPL_NODTB_DATA)])
4623
Simon Glass63f41d42021-03-18 20:24:58 +13004624 def testTplBssPad(self):
4625 """Test that we can pad TPL's BSS with zeros"""
4626 # ELF file with a '__bss_size' symbol
4627 self._SetupTplElf()
4628 data = self._DoReadFile('193_tpl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004629 self.assertEqual(U_BOOT_TPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glass63f41d42021-03-18 20:24:58 +13004630 data)
4631
4632 def testTplBssPadMissing(self):
4633 """Test that a missing symbol is detected"""
4634 self._SetupTplElf('u_boot_ucode_ptr')
4635 with self.assertRaises(ValueError) as e:
4636 self._DoReadFile('193_tpl_bss_pad.dts')
4637 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4638 str(e.exception))
4639
Simon Glass718b5292021-03-18 20:25:07 +13004640 def checkDtbSizes(self, data, pad_len, start):
4641 """Check the size arguments in a dtb embedded in an image
4642
4643 Args:
4644 data: The image data
4645 pad_len: Length of the pad section in the image, in bytes
4646 start: Start offset of the devicetree to examine, within the image
4647
4648 Returns:
4649 Size of the devicetree in bytes
4650 """
4651 dtb_data = data[start:]
4652 dtb = fdt.Fdt.FromData(dtb_data)
4653 fdt_size = dtb.GetFdtObj().totalsize()
4654 dtb.Scan()
4655 props = self._GetPropTree(dtb, 'size')
4656 self.assertEqual({
4657 'size': len(data),
4658 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4659 'u-boot-spl/u-boot-spl-dtb:size': 801,
4660 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4661 'u-boot-spl:size': 860,
4662 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4663 'u-boot/u-boot-dtb:size': 781,
4664 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4665 'u-boot:size': 827,
4666 }, props)
4667 return fdt_size
4668
4669 def testExpanded(self):
4670 """Test that an expanded entry type is selected when needed"""
4671 self._SetupSplElf()
4672 self._SetupTplElf()
4673
4674 # SPL has a devicetree, TPL does not
4675 entry_args = {
4676 'spl-dtb': '1',
4677 'spl-bss-pad': 'y',
4678 'tpl-dtb': '',
4679 }
4680 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4681 entry_args=entry_args)
4682 image = control.images['image']
4683 entries = image.GetEntries()
4684 self.assertEqual(3, len(entries))
4685
4686 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4687 self.assertIn('u-boot', entries)
4688 entry = entries['u-boot']
4689 self.assertEqual('u-boot-expanded', entry.etype)
4690 subent = entry.GetEntries()
4691 self.assertEqual(2, len(subent))
4692 self.assertIn('u-boot-nodtb', subent)
4693 self.assertIn('u-boot-dtb', subent)
4694
4695 # Second, u-boot-spl, which should be expanded into three parts
4696 self.assertIn('u-boot-spl', entries)
4697 entry = entries['u-boot-spl']
4698 self.assertEqual('u-boot-spl-expanded', entry.etype)
4699 subent = entry.GetEntries()
4700 self.assertEqual(3, len(subent))
4701 self.assertIn('u-boot-spl-nodtb', subent)
4702 self.assertIn('u-boot-spl-bss-pad', subent)
4703 self.assertIn('u-boot-spl-dtb', subent)
4704
4705 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4706 # devicetree
4707 self.assertIn('u-boot-tpl', entries)
4708 entry = entries['u-boot-tpl']
4709 self.assertEqual('u-boot-tpl', entry.etype)
4710 self.assertEqual(None, entry.GetEntries())
4711
4712 def testExpandedTpl(self):
4713 """Test that an expanded entry type is selected for TPL when needed"""
4714 self._SetupTplElf()
4715
4716 entry_args = {
4717 'tpl-bss-pad': 'y',
4718 'tpl-dtb': 'y',
4719 }
4720 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4721 entry_args=entry_args)
4722 image = control.images['image']
4723 entries = image.GetEntries()
4724 self.assertEqual(1, len(entries))
4725
4726 # We only have u-boot-tpl, which be expanded
4727 self.assertIn('u-boot-tpl', entries)
4728 entry = entries['u-boot-tpl']
4729 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4730 subent = entry.GetEntries()
4731 self.assertEqual(3, len(subent))
4732 self.assertIn('u-boot-tpl-nodtb', subent)
4733 self.assertIn('u-boot-tpl-bss-pad', subent)
4734 self.assertIn('u-boot-tpl-dtb', subent)
4735
4736 def testExpandedNoPad(self):
4737 """Test an expanded entry without BSS pad enabled"""
4738 self._SetupSplElf()
4739 self._SetupTplElf()
4740
4741 # SPL has a devicetree, TPL does not
4742 entry_args = {
4743 'spl-dtb': 'something',
4744 'spl-bss-pad': 'n',
4745 'tpl-dtb': '',
4746 }
4747 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4748 entry_args=entry_args)
4749 image = control.images['image']
4750 entries = image.GetEntries()
4751
4752 # Just check u-boot-spl, which should be expanded into two parts
4753 self.assertIn('u-boot-spl', entries)
4754 entry = entries['u-boot-spl']
4755 self.assertEqual('u-boot-spl-expanded', entry.etype)
4756 subent = entry.GetEntries()
4757 self.assertEqual(2, len(subent))
4758 self.assertIn('u-boot-spl-nodtb', subent)
4759 self.assertIn('u-boot-spl-dtb', subent)
4760
4761 def testExpandedTplNoPad(self):
4762 """Test that an expanded entry type with padding disabled in TPL"""
4763 self._SetupTplElf()
4764
4765 entry_args = {
4766 'tpl-bss-pad': '',
4767 'tpl-dtb': 'y',
4768 }
4769 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4770 entry_args=entry_args)
4771 image = control.images['image']
4772 entries = image.GetEntries()
4773 self.assertEqual(1, len(entries))
4774
4775 # We only have u-boot-tpl, which be expanded
4776 self.assertIn('u-boot-tpl', entries)
4777 entry = entries['u-boot-tpl']
4778 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4779 subent = entry.GetEntries()
4780 self.assertEqual(2, len(subent))
4781 self.assertIn('u-boot-tpl-nodtb', subent)
4782 self.assertIn('u-boot-tpl-dtb', subent)
4783
4784 def testFdtInclude(self):
4785 """Test that an Fdt is update within all binaries"""
4786 self._SetupSplElf()
4787 self._SetupTplElf()
4788
4789 # SPL has a devicetree, TPL does not
4790 self.maxDiff = None
4791 entry_args = {
4792 'spl-dtb': '1',
4793 'spl-bss-pad': 'y',
4794 'tpl-dtb': '',
4795 }
4796 # Build the image. It includes two separate devicetree binaries, each
4797 # with their own contents, but all contain the binman definition.
4798 data = self._DoReadFileDtb(
4799 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4800 update_dtb=True, entry_args=entry_args)[0]
4801 pad_len = 10
4802
4803 # Check the U-Boot dtb
4804 start = len(U_BOOT_NODTB_DATA)
4805 fdt_size = self.checkDtbSizes(data, pad_len, start)
4806
4807 # Now check SPL
4808 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4809 fdt_size = self.checkDtbSizes(data, pad_len, start)
4810
4811 # TPL has no devicetree
4812 start += fdt_size + len(U_BOOT_TPL_DATA)
4813 self.assertEqual(len(data), start)
Simon Glassbb395742020-10-26 17:40:14 -06004814
Simon Glass7098b7f2021-03-21 18:24:30 +13004815 def testSymbolsExpanded(self):
4816 """Test binman can assign symbols in expanded entries"""
4817 entry_args = {
4818 'spl-dtb': '1',
4819 }
4820 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4821 U_BOOT_SPL_DTB_DATA, 0x38,
4822 entry_args=entry_args, use_expanded=True)
4823
Simon Glasse1915782021-03-21 18:24:31 +13004824 def testCollection(self):
4825 """Test a collection"""
4826 data = self._DoReadFile('198_collection.dts')
4827 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004828 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
4829 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
Simon Glasse1915782021-03-21 18:24:31 +13004830 data)
4831
Simon Glass27a7f772021-03-21 18:24:32 +13004832 def testCollectionSection(self):
4833 """Test a collection where a section must be built first"""
4834 # Sections never have their contents when GetData() is called, but when
Simon Glass7e3f89f2021-11-23 11:03:47 -07004835 # BuildSectionData() is called with required=True, a section will force
Simon Glass27a7f772021-03-21 18:24:32 +13004836 # building the contents, producing an error is anything is still
4837 # missing.
4838 data = self._DoReadFile('199_collection_section.dts')
4839 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
Simon Glass80025522022-01-29 14:14:04 -07004840 self.assertEqual(section + U_BOOT_DATA + tools.get_bytes(0xff, 2) +
4841 section + tools.get_bytes(0xfe, 3) + U_BOOT_DATA,
Simon Glass27a7f772021-03-21 18:24:32 +13004842 data)
4843
Simon Glassf427c5f2021-03-21 18:24:33 +13004844 def testAlignDefault(self):
4845 """Test that default alignment works on sections"""
4846 data = self._DoReadFile('200_align_default.dts')
Simon Glass80025522022-01-29 14:14:04 -07004847 expected = (U_BOOT_DATA + tools.get_bytes(0, 8 - len(U_BOOT_DATA)) +
Simon Glassf427c5f2021-03-21 18:24:33 +13004848 U_BOOT_DATA)
4849 # Special alignment for section
Simon Glass80025522022-01-29 14:14:04 -07004850 expected += tools.get_bytes(0, 32 - len(expected))
Simon Glassf427c5f2021-03-21 18:24:33 +13004851 # No alignment within the nested section
4852 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
4853 # Now the final piece, which should be default-aligned
Simon Glass80025522022-01-29 14:14:04 -07004854 expected += tools.get_bytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
Simon Glassf427c5f2021-03-21 18:24:33 +13004855 self.assertEqual(expected, data)
Simon Glass27a7f772021-03-21 18:24:32 +13004856
Bin Mengc0b15742021-05-10 20:23:33 +08004857 def testPackOpenSBI(self):
4858 """Test that an image with an OpenSBI binary can be created"""
4859 data = self._DoReadFile('201_opensbi.dts')
4860 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
4861
Simon Glass76f496d2021-07-06 10:36:37 -06004862 def testSectionsSingleThread(self):
4863 """Test sections without multithreading"""
4864 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
Simon Glass80025522022-01-29 14:14:04 -07004865 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4866 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
4867 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glass76f496d2021-07-06 10:36:37 -06004868 self.assertEqual(expected, data)
4869
4870 def testThreadTimeout(self):
4871 """Test handling a thread that takes too long"""
4872 with self.assertRaises(ValueError) as e:
4873 self._DoTestFile('202_section_timeout.dts',
4874 test_section_timeout=True)
Simon Glass2d59d152021-10-18 12:13:15 -06004875 self.assertIn("Timed out obtaining contents", str(e.exception))
Simon Glass76f496d2021-07-06 10:36:37 -06004876
Simon Glass748a1d42021-07-06 10:36:41 -06004877 def testTiming(self):
4878 """Test output of timing information"""
4879 data = self._DoReadFile('055_sections.dts')
4880 with test_util.capture_sys_output() as (stdout, stderr):
4881 state.TimingShow()
4882 self.assertIn('read:', stdout.getvalue())
4883 self.assertIn('compress:', stdout.getvalue())
4884
Simon Glassadfb8492021-11-03 21:09:18 -06004885 def testUpdateFdtInElf(self):
4886 """Test that we can update the devicetree in an ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02004887 if not elf.ELF_TOOLS:
4888 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06004889 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4890 outfile = os.path.join(self._indir, 'u-boot.out')
4891 begin_sym = 'dtb_embed_begin'
4892 end_sym = 'dtb_embed_end'
4893 retcode = self._DoTestFile(
4894 '060_fdt_update.dts', update_dtb=True,
4895 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4896 self.assertEqual(0, retcode)
4897
4898 # Check that the output file does in fact contact a dtb with the binman
4899 # definition in the correct place
4900 syms = elf.GetSymbolFileOffset(infile,
4901 ['dtb_embed_begin', 'dtb_embed_end'])
Simon Glass80025522022-01-29 14:14:04 -07004902 data = tools.read_file(outfile)
Simon Glassadfb8492021-11-03 21:09:18 -06004903 dtb_data = data[syms['dtb_embed_begin'].offset:
4904 syms['dtb_embed_end'].offset]
4905
4906 dtb = fdt.Fdt.FromData(dtb_data)
4907 dtb.Scan()
4908 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4909 self.assertEqual({
4910 'image-pos': 0,
4911 'offset': 0,
4912 '_testing:offset': 32,
4913 '_testing:size': 2,
4914 '_testing:image-pos': 32,
4915 'section@0/u-boot:offset': 0,
4916 'section@0/u-boot:size': len(U_BOOT_DATA),
4917 'section@0/u-boot:image-pos': 0,
4918 'section@0:offset': 0,
4919 'section@0:size': 16,
4920 'section@0:image-pos': 0,
4921
4922 'section@1/u-boot:offset': 0,
4923 'section@1/u-boot:size': len(U_BOOT_DATA),
4924 'section@1/u-boot:image-pos': 16,
4925 'section@1:offset': 16,
4926 'section@1:size': 16,
4927 'section@1:image-pos': 16,
4928 'size': 40
4929 }, props)
4930
4931 def testUpdateFdtInElfInvalid(self):
4932 """Test that invalid args are detected with --update-fdt-in-elf"""
4933 with self.assertRaises(ValueError) as e:
4934 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
4935 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
4936 str(e.exception))
4937
4938 def testUpdateFdtInElfNoSyms(self):
4939 """Test that missing symbols are detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02004940 if not elf.ELF_TOOLS:
4941 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06004942 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4943 outfile = ''
4944 begin_sym = 'wrong_begin'
4945 end_sym = 'wrong_end'
4946 with self.assertRaises(ValueError) as e:
4947 self._DoTestFile(
4948 '060_fdt_update.dts',
4949 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4950 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
4951 str(e.exception))
4952
4953 def testUpdateFdtInElfTooSmall(self):
4954 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02004955 if not elf.ELF_TOOLS:
4956 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06004957 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
4958 outfile = os.path.join(self._indir, 'u-boot.out')
4959 begin_sym = 'dtb_embed_begin'
4960 end_sym = 'dtb_embed_end'
4961 with self.assertRaises(ValueError) as e:
4962 self._DoTestFile(
4963 '060_fdt_update.dts', update_dtb=True,
4964 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4965 self.assertRegex(
4966 str(e.exception),
4967 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
4968
Simon Glass88e04da2021-11-23 11:03:42 -07004969 def testVersion(self):
4970 """Test we can get the binman version"""
4971 version = '(unreleased)'
4972 self.assertEqual(version, state.GetVersion(self._indir))
4973
4974 with self.assertRaises(SystemExit):
4975 with test_util.capture_sys_output() as (_, stderr):
4976 self._DoBinman('-V')
4977 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
4978
4979 # Try running the tool too, just to be safe
4980 result = self._RunBinman('-V')
4981 self.assertEqual('Binman %s\n' % version, result.stderr)
4982
4983 # Set up a version file to make sure that works
4984 version = 'v2025.01-rc2'
Simon Glass80025522022-01-29 14:14:04 -07004985 tools.write_file(os.path.join(self._indir, 'version'), version,
Simon Glass88e04da2021-11-23 11:03:42 -07004986 binary=False)
4987 self.assertEqual(version, state.GetVersion(self._indir))
4988
Simon Glass637958f2021-11-23 21:09:50 -07004989 def testAltFormat(self):
4990 """Test that alternative formats can be used to extract"""
4991 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
4992
4993 try:
4994 tmpdir, updated_fname = self._SetupImageInTmpdir()
4995 with test_util.capture_sys_output() as (stdout, _):
4996 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
4997 self.assertEqual(
4998 '''Flag (-F) Entry type Description
4999fdt fdtmap Extract the devicetree blob from the fdtmap
5000''',
5001 stdout.getvalue())
5002
5003 dtb = os.path.join(tmpdir, 'fdt.dtb')
5004 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
5005 dtb, 'fdtmap')
5006
5007 # Check that we can read it and it can be scanning, meaning it does
5008 # not have a 16-byte fdtmap header
Simon Glass80025522022-01-29 14:14:04 -07005009 data = tools.read_file(dtb)
Simon Glass637958f2021-11-23 21:09:50 -07005010 dtb = fdt.Fdt.FromData(data)
5011 dtb.Scan()
5012
5013 # Now check u-boot which has no alt_format
5014 fname = os.path.join(tmpdir, 'fdt.dtb')
5015 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
5016 '-f', fname, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07005017 data = tools.read_file(fname)
Simon Glass637958f2021-11-23 21:09:50 -07005018 self.assertEqual(U_BOOT_DATA, data)
5019
5020 finally:
5021 shutil.rmtree(tmpdir)
5022
Simon Glass0b00ae62021-11-23 21:09:52 -07005023 def testExtblobList(self):
5024 """Test an image with an external blob list"""
5025 data = self._DoReadFile('215_blob_ext_list.dts')
5026 self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
5027
5028 def testExtblobListMissing(self):
5029 """Test an image with a missing external blob"""
5030 with self.assertRaises(ValueError) as e:
5031 self._DoReadFile('216_blob_ext_list_missing.dts')
5032 self.assertIn("Filename 'missing-file' not found in input path",
5033 str(e.exception))
5034
5035 def testExtblobListMissingOk(self):
5036 """Test an image with an missing external blob that is allowed"""
5037 with test_util.capture_sys_output() as (stdout, stderr):
5038 self._DoTestFile('216_blob_ext_list_missing.dts',
5039 allow_missing=True)
5040 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005041 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass0b00ae62021-11-23 21:09:52 -07005042
Simon Glass3efb2972021-11-23 21:08:59 -07005043 def testFip(self):
5044 """Basic test of generation of an ARM Firmware Image Package (FIP)"""
5045 data = self._DoReadFile('203_fip.dts')
5046 hdr, fents = fip_util.decode_fip(data)
5047 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5048 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5049 self.assertEqual(0x123, hdr.flags)
5050
5051 self.assertEqual(2, len(fents))
5052
5053 fent = fents[0]
5054 self.assertEqual(
5055 bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
5056 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
5057 self.assertEqual('soc-fw', fent.fip_type)
5058 self.assertEqual(0x88, fent.offset)
5059 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5060 self.assertEqual(0x123456789abcdef, fent.flags)
5061 self.assertEqual(ATF_BL31_DATA, fent.data)
5062 self.assertEqual(True, fent.valid)
5063
5064 fent = fents[1]
5065 self.assertEqual(
5066 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
5067 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
5068 self.assertEqual('scp-fwu-cfg', fent.fip_type)
5069 self.assertEqual(0x8c, fent.offset)
5070 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5071 self.assertEqual(0, fent.flags)
5072 self.assertEqual(ATF_BL2U_DATA, fent.data)
5073 self.assertEqual(True, fent.valid)
5074
5075 def testFipOther(self):
5076 """Basic FIP with something that isn't a external blob"""
5077 data = self._DoReadFile('204_fip_other.dts')
5078 hdr, fents = fip_util.decode_fip(data)
5079
5080 self.assertEqual(2, len(fents))
5081 fent = fents[1]
5082 self.assertEqual('rot-cert', fent.fip_type)
5083 self.assertEqual(b'aa', fent.data)
5084
Simon Glass3efb2972021-11-23 21:08:59 -07005085 def testFipNoType(self):
5086 """FIP with an entry of an unknown type"""
5087 with self.assertRaises(ValueError) as e:
5088 self._DoReadFile('205_fip_no_type.dts')
5089 self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
5090 str(e.exception))
5091
5092 def testFipUuid(self):
5093 """Basic FIP with a manual uuid"""
5094 data = self._DoReadFile('206_fip_uuid.dts')
5095 hdr, fents = fip_util.decode_fip(data)
5096
5097 self.assertEqual(2, len(fents))
5098 fent = fents[1]
5099 self.assertEqual(None, fent.fip_type)
5100 self.assertEqual(
5101 bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
5102 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
5103 fent.uuid)
5104 self.assertEqual(U_BOOT_DATA, fent.data)
5105
5106 def testFipLs(self):
5107 """Test listing a FIP"""
5108 data = self._DoReadFileRealDtb('207_fip_ls.dts')
5109 hdr, fents = fip_util.decode_fip(data)
5110
5111 try:
5112 tmpdir, updated_fname = self._SetupImageInTmpdir()
5113 with test_util.capture_sys_output() as (stdout, stderr):
5114 self._DoBinman('ls', '-i', updated_fname)
5115 finally:
5116 shutil.rmtree(tmpdir)
5117 lines = stdout.getvalue().splitlines()
5118 expected = [
Simon Glass49cd2b32023-02-07 14:34:18 -07005119'Name Image-pos Size Entry-type Offset Uncomp-size',
5120'--------------------------------------------------------------',
5121'image 0 2d3 section 0',
5122' atf-fip 0 90 atf-fip 0',
5123' soc-fw 88 4 blob-ext 88',
5124' u-boot 8c 4 u-boot 8c',
5125' fdtmap 90 243 fdtmap 90',
Simon Glass3efb2972021-11-23 21:08:59 -07005126]
5127 self.assertEqual(expected, lines)
5128
5129 image = control.images['image']
5130 entries = image.GetEntries()
5131 fdtmap = entries['fdtmap']
5132
5133 fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
5134 magic = fdtmap_data[:8]
5135 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07005136 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass3efb2972021-11-23 21:08:59 -07005137
5138 fdt_data = fdtmap_data[16:]
5139 dtb = fdt.Fdt.FromData(fdt_data)
5140 dtb.Scan()
5141 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
5142 self.assertEqual({
5143 'atf-fip/soc-fw:image-pos': 136,
5144 'atf-fip/soc-fw:offset': 136,
5145 'atf-fip/soc-fw:size': 4,
5146 'atf-fip/u-boot:image-pos': 140,
5147 'atf-fip/u-boot:offset': 140,
5148 'atf-fip/u-boot:size': 4,
5149 'atf-fip:image-pos': 0,
5150 'atf-fip:offset': 0,
5151 'atf-fip:size': 144,
5152 'image-pos': 0,
5153 'offset': 0,
5154 'fdtmap:image-pos': fdtmap.image_pos,
5155 'fdtmap:offset': fdtmap.offset,
5156 'fdtmap:size': len(fdtmap_data),
5157 'size': len(data),
5158 }, props)
5159
5160 def testFipExtractOneEntry(self):
5161 """Test extracting a single entry fron an FIP"""
5162 self._DoReadFileRealDtb('207_fip_ls.dts')
Simon Glass80025522022-01-29 14:14:04 -07005163 image_fname = tools.get_output_filename('image.bin')
Simon Glass3efb2972021-11-23 21:08:59 -07005164 fname = os.path.join(self._indir, 'output.extact')
5165 control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07005166 data = tools.read_file(fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005167 self.assertEqual(U_BOOT_DATA, data)
5168
5169 def testFipReplace(self):
5170 """Test replacing a single file in a FIP"""
Simon Glass80025522022-01-29 14:14:04 -07005171 expected = U_BOOT_DATA + tools.get_bytes(0x78, 50)
Simon Glass3efb2972021-11-23 21:08:59 -07005172 data = self._DoReadFileRealDtb('208_fip_replace.dts')
Simon Glass80025522022-01-29 14:14:04 -07005173 updated_fname = tools.get_output_filename('image-updated.bin')
5174 tools.write_file(updated_fname, data)
Simon Glass3efb2972021-11-23 21:08:59 -07005175 entry_name = 'atf-fip/u-boot'
5176 control.WriteEntry(updated_fname, entry_name, expected,
5177 allow_resize=True)
5178 actual = control.ReadEntry(updated_fname, entry_name)
5179 self.assertEqual(expected, actual)
5180
Simon Glass80025522022-01-29 14:14:04 -07005181 new_data = tools.read_file(updated_fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005182 hdr, fents = fip_util.decode_fip(new_data)
5183
5184 self.assertEqual(2, len(fents))
5185
5186 # Check that the FIP entry is updated
5187 fent = fents[1]
5188 self.assertEqual(0x8c, fent.offset)
5189 self.assertEqual(len(expected), fent.size)
5190 self.assertEqual(0, fent.flags)
5191 self.assertEqual(expected, fent.data)
5192 self.assertEqual(True, fent.valid)
5193
5194 def testFipMissing(self):
5195 with test_util.capture_sys_output() as (stdout, stderr):
5196 self._DoTestFile('209_fip_missing.dts', allow_missing=True)
5197 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005198 self.assertRegex(err, "Image 'image'.*missing.*: rmm-fw")
Simon Glass3efb2972021-11-23 21:08:59 -07005199
5200 def testFipSize(self):
5201 """Test a FIP with a size property"""
5202 data = self._DoReadFile('210_fip_size.dts')
5203 self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
5204 hdr, fents = fip_util.decode_fip(data)
5205 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5206 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5207
5208 self.assertEqual(1, len(fents))
5209
5210 fent = fents[0]
5211 self.assertEqual('soc-fw', fent.fip_type)
5212 self.assertEqual(0x60, fent.offset)
5213 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5214 self.assertEqual(ATF_BL31_DATA, fent.data)
5215 self.assertEqual(True, fent.valid)
5216
5217 rest = data[0x60 + len(ATF_BL31_DATA):0x100]
Simon Glass80025522022-01-29 14:14:04 -07005218 self.assertEqual(tools.get_bytes(0xff, len(rest)), rest)
Simon Glass3efb2972021-11-23 21:08:59 -07005219
5220 def testFipBadAlign(self):
5221 """Test that an invalid alignment value in a FIP is detected"""
5222 with self.assertRaises(ValueError) as e:
5223 self._DoTestFile('211_fip_bad_align.dts')
5224 self.assertIn(
5225 "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
5226 str(e.exception))
5227
5228 def testFipCollection(self):
5229 """Test using a FIP in a collection"""
5230 data = self._DoReadFile('212_fip_collection.dts')
5231 entry1 = control.images['image'].GetEntries()['collection']
5232 data1 = data[:entry1.size]
5233 hdr1, fents2 = fip_util.decode_fip(data1)
5234
5235 entry2 = control.images['image'].GetEntries()['atf-fip']
5236 data2 = data[entry2.offset:entry2.offset + entry2.size]
5237 hdr1, fents2 = fip_util.decode_fip(data2)
5238
5239 # The 'collection' entry should have U-Boot included at the end
5240 self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
5241 self.assertEqual(data1, data2 + U_BOOT_DATA)
5242 self.assertEqual(U_BOOT_DATA, data1[-4:])
5243
5244 # There should be a U-Boot after the final FIP
5245 self.assertEqual(U_BOOT_DATA, data[-4:])
Simon Glass76f496d2021-07-06 10:36:37 -06005246
Simon Glassccae6862022-01-12 13:10:35 -07005247 def testFakeBlob(self):
5248 """Test handling of faking an external blob"""
5249 with test_util.capture_sys_output() as (stdout, stderr):
5250 self._DoTestFile('217_fake_blob.dts', allow_missing=True,
5251 allow_fake_blobs=True)
5252 err = stderr.getvalue()
5253 self.assertRegex(
5254 err,
5255 "Image '.*' has faked external blobs and is non-functional: .*")
Simon Glassccae6862022-01-12 13:10:35 -07005256
Simon Glassceb5f912022-01-09 20:13:46 -07005257 def testExtblobListFaked(self):
5258 """Test an extblob with missing external blob that are faked"""
5259 with test_util.capture_sys_output() as (stdout, stderr):
5260 self._DoTestFile('216_blob_ext_list_missing.dts',
5261 allow_fake_blobs=True)
5262 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005263 self.assertRegex(err, "Image 'image'.*faked.*: blob-ext-list")
Simon Glassceb5f912022-01-09 20:13:46 -07005264
Simon Glass162017b2022-01-09 20:13:57 -07005265 def testListBintools(self):
5266 args = ['tool', '--list']
5267 with test_util.capture_sys_output() as (stdout, _):
5268 self._DoBinman(*args)
5269 out = stdout.getvalue().splitlines()
5270 self.assertTrue(len(out) >= 2)
5271
5272 def testFetchBintools(self):
5273 def fail_download(url):
Simon Glass80025522022-01-29 14:14:04 -07005274 """Take the tools.download() function by raising an exception"""
Simon Glass162017b2022-01-09 20:13:57 -07005275 raise urllib.error.URLError('my error')
5276
5277 args = ['tool']
5278 with self.assertRaises(ValueError) as e:
5279 self._DoBinman(*args)
5280 self.assertIn("Invalid arguments to 'tool' subcommand",
5281 str(e.exception))
5282
5283 args = ['tool', '--fetch']
5284 with self.assertRaises(ValueError) as e:
5285 self._DoBinman(*args)
5286 self.assertIn('Please specify bintools to fetch', str(e.exception))
5287
5288 args = ['tool', '--fetch', '_testing']
Simon Glass80025522022-01-29 14:14:04 -07005289 with unittest.mock.patch.object(tools, 'download',
Simon Glass162017b2022-01-09 20:13:57 -07005290 side_effect=fail_download):
5291 with test_util.capture_sys_output() as (stdout, _):
5292 self._DoBinman(*args)
5293 self.assertIn('failed to fetch with all methods', stdout.getvalue())
5294
Simon Glass620c4462022-01-09 20:14:11 -07005295 def testBintoolDocs(self):
5296 """Test for creation of bintool documentation"""
5297 with test_util.capture_sys_output() as (stdout, stderr):
5298 control.write_bintool_docs(control.bintool.Bintool.get_tool_list())
5299 self.assertTrue(len(stdout.getvalue()) > 0)
5300
5301 def testBintoolDocsMissing(self):
5302 """Test handling of missing bintool documentation"""
5303 with self.assertRaises(ValueError) as e:
5304 with test_util.capture_sys_output() as (stdout, stderr):
5305 control.write_bintool_docs(
5306 control.bintool.Bintool.get_tool_list(), 'mkimage')
5307 self.assertIn('Documentation is missing for modules: mkimage',
5308 str(e.exception))
5309
Jan Kiszka58c407f2022-01-28 20:37:53 +01005310 def testListWithGenNode(self):
5311 """Check handling of an FDT map when the section cannot be found"""
5312 entry_args = {
5313 'of-list': 'test-fdt1 test-fdt2',
5314 }
5315 data = self._DoReadFileDtb(
5316 '219_fit_gennode.dts',
5317 entry_args=entry_args,
5318 use_real_dtb=True,
5319 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])
5320
5321 try:
5322 tmpdir, updated_fname = self._SetupImageInTmpdir()
5323 with test_util.capture_sys_output() as (stdout, stderr):
5324 self._RunBinman('ls', '-i', updated_fname)
5325 finally:
5326 shutil.rmtree(tmpdir)
5327
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005328 def testFitSubentryUsesBintool(self):
5329 """Test that binman FIT subentries can use bintools"""
5330 command.test_result = self._HandleGbbCommand
5331 entry_args = {
5332 'keydir': 'devkeys',
5333 'bmpblk': 'bmpblk.bin',
5334 }
5335 data, _, _, _ = self._DoReadFileDtb('220_fit_subentry_bintool.dts',
5336 entry_args=entry_args)
5337
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03005338 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
5339 tools.get_bytes(0, 0x2180 - 16))
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005340 self.assertIn(expected, data)
5341
5342 def testFitSubentryMissingBintool(self):
5343 """Test that binman reports missing bintools for FIT subentries"""
5344 entry_args = {
5345 'keydir': 'devkeys',
5346 }
5347 with test_util.capture_sys_output() as (_, stderr):
5348 self._DoTestFile('220_fit_subentry_bintool.dts',
5349 force_missing_bintools='futility', entry_args=entry_args)
5350 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005351 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glassccae6862022-01-12 13:10:35 -07005352
Alper Nebi Yasak1e4ffd82022-02-09 22:02:35 +03005353 def testFitSubentryHashSubnode(self):
5354 """Test an image with a FIT inside"""
5355 data, _, _, out_dtb_name = self._DoReadFileDtb(
5356 '221_fit_subentry_hash.dts', use_real_dtb=True, update_dtb=True)
5357
5358 mkimage_dtb = fdt.Fdt.FromData(data)
5359 mkimage_dtb.Scan()
5360 binman_dtb = fdt.Fdt(out_dtb_name)
5361 binman_dtb.Scan()
5362
5363 # Check that binman didn't add hash values
5364 fnode = binman_dtb.GetNode('/binman/fit/images/kernel/hash')
5365 self.assertNotIn('value', fnode.props)
5366
5367 fnode = binman_dtb.GetNode('/binman/fit/images/fdt-1/hash')
5368 self.assertNotIn('value', fnode.props)
5369
5370 # Check that mkimage added hash values
5371 fnode = mkimage_dtb.GetNode('/images/kernel/hash')
5372 self.assertIn('value', fnode.props)
5373
5374 fnode = mkimage_dtb.GetNode('/images/fdt-1/hash')
5375 self.assertIn('value', fnode.props)
5376
Roger Quadros5cdcea02022-02-19 20:50:04 +02005377 def testPackTeeOs(self):
5378 """Test that an image with an TEE binary can be created"""
5379 data = self._DoReadFile('222_tee_os.dts')
5380 self.assertEqual(TEE_OS_DATA, data[:len(TEE_OS_DATA)])
5381
Simon Glass912339f2022-02-08 11:50:03 -07005382 def testFitFdtOper(self):
5383 """Check handling of a specified FIT operation"""
5384 entry_args = {
5385 'of-list': 'test-fdt1 test-fdt2',
5386 'default-dt': 'test-fdt2',
5387 }
5388 self._DoReadFileDtb(
5389 '223_fit_fdt_oper.dts',
5390 entry_args=entry_args,
5391 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
5392
5393 def testFitFdtBadOper(self):
5394 """Check handling of an FDT map when the section cannot be found"""
5395 with self.assertRaises(ValueError) as exc:
5396 self._DoReadFileDtb('224_fit_bad_oper.dts')
Simon Glass05f71dc2022-03-05 20:19:09 -07005397 self.assertIn("Node '/binman/fit': subnode 'images/@fdt-SEQ': Unknown operation 'unknown'",
Simon Glass912339f2022-02-08 11:50:03 -07005398 str(exc.exception))
5399
Simon Glassdd156a42022-03-05 20:18:59 -07005400 def test_uses_expand_size(self):
5401 """Test that the 'expand-size' property cannot be used anymore"""
5402 with self.assertRaises(ValueError) as e:
5403 data = self._DoReadFile('225_expand_size_bad.dts')
5404 self.assertIn(
5405 "Node '/binman/u-boot': Please use 'extend-size' instead of 'expand-size'",
5406 str(e.exception))
5407
Simon Glass5f423422022-03-05 20:19:12 -07005408 def testFitSplitElf(self):
5409 """Test an image with an FIT with an split-elf operation"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005410 if not elf.ELF_TOOLS:
5411 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005412 entry_args = {
5413 'of-list': 'test-fdt1 test-fdt2',
5414 'default-dt': 'test-fdt2',
5415 'atf-bl31-path': 'bl31.elf',
5416 'tee-os-path': 'tee.elf',
5417 }
5418 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5419 data = self._DoReadFileDtb(
5420 '226_fit_split_elf.dts',
5421 entry_args=entry_args,
5422 extra_indirs=[test_subdir])[0]
5423
5424 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
5425 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
5426
5427 base_keys = {'description', 'type', 'arch', 'os', 'compression',
5428 'data', 'load'}
5429 dtb = fdt.Fdt.FromData(fit_data)
5430 dtb.Scan()
5431
5432 elf_data = tools.read_file(os.path.join(self._indir, 'bl31.elf'))
5433 segments, entry = elf.read_loadable_segments(elf_data)
5434
5435 # We assume there are two segments
5436 self.assertEquals(2, len(segments))
5437
5438 atf1 = dtb.GetNode('/images/atf-1')
5439 _, start, data = segments[0]
5440 self.assertEqual(base_keys | {'entry'}, atf1.props.keys())
5441 self.assertEqual(entry,
5442 fdt_util.fdt32_to_cpu(atf1.props['entry'].value))
5443 self.assertEqual(start,
5444 fdt_util.fdt32_to_cpu(atf1.props['load'].value))
5445 self.assertEqual(data, atf1.props['data'].bytes)
5446
Jonas Karlmand2c7d902023-01-21 19:01:48 +00005447 hash_node = atf1.FindNode('hash')
5448 self.assertIsNotNone(hash_node)
5449 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5450
Simon Glass5f423422022-03-05 20:19:12 -07005451 atf2 = dtb.GetNode('/images/atf-2')
5452 self.assertEqual(base_keys, atf2.props.keys())
5453 _, start, data = segments[1]
5454 self.assertEqual(start,
5455 fdt_util.fdt32_to_cpu(atf2.props['load'].value))
5456 self.assertEqual(data, atf2.props['data'].bytes)
5457
Jonas Karlmand2c7d902023-01-21 19:01:48 +00005458 hash_node = atf2.FindNode('hash')
5459 self.assertIsNotNone(hash_node)
5460 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5461
5462 hash_node = dtb.GetNode('/images/tee-1/hash-1')
5463 self.assertIsNotNone(hash_node)
5464 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5465
Simon Glass5f423422022-03-05 20:19:12 -07005466 conf = dtb.GetNode('/configurations')
5467 self.assertEqual({'default'}, conf.props.keys())
5468
5469 for subnode in conf.subnodes:
5470 self.assertEqual({'description', 'fdt', 'loadables'},
5471 subnode.props.keys())
5472 self.assertEqual(
5473 ['atf-1', 'atf-2', 'tee-1', 'tee-2'],
5474 fdt_util.GetStringList(subnode, 'loadables'))
5475
5476 def _check_bad_fit(self, dts):
5477 """Check a bad FIT
5478
5479 This runs with the given dts and returns the assertion raised
5480
5481 Args:
5482 dts (str): dts filename to use
5483
5484 Returns:
5485 str: Assertion string raised
5486 """
5487 entry_args = {
5488 'of-list': 'test-fdt1 test-fdt2',
5489 'default-dt': 'test-fdt2',
5490 'atf-bl31-path': 'bl31.elf',
5491 'tee-os-path': 'tee.elf',
5492 }
5493 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5494 with self.assertRaises(ValueError) as exc:
5495 self._DoReadFileDtb(dts, entry_args=entry_args,
5496 extra_indirs=[test_subdir])[0]
5497 return str(exc.exception)
5498
5499 def testFitSplitElfBadElf(self):
5500 """Test a FIT split-elf operation with an invalid ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005501 if not elf.ELF_TOOLS:
5502 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005503 TestFunctional._MakeInputFile('bad.elf', tools.get_bytes(100, 100))
5504 entry_args = {
5505 'of-list': 'test-fdt1 test-fdt2',
5506 'default-dt': 'test-fdt2',
5507 'atf-bl31-path': 'bad.elf',
5508 'tee-os-path': 'tee.elf',
5509 }
5510 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5511 with self.assertRaises(ValueError) as exc:
5512 self._DoReadFileDtb(
5513 '226_fit_split_elf.dts',
5514 entry_args=entry_args,
5515 extra_indirs=[test_subdir])[0]
5516 self.assertIn(
5517 "Node '/binman/fit': subnode 'images/@atf-SEQ': Failed to read ELF file: Magic number does not match",
5518 str(exc.exception))
5519
Simon Glass5f423422022-03-05 20:19:12 -07005520 def checkFitSplitElf(self, **kwargs):
Simon Glass7d3e4072022-08-07 09:46:46 -06005521 """Test an split-elf FIT with a missing ELF file
5522
5523 Args:
5524 kwargs (dict of str): Arguments to pass to _DoTestFile()
5525
5526 Returns:
5527 tuple:
5528 str: stdout result
5529 str: stderr result
5530 """
Simon Glass5f423422022-03-05 20:19:12 -07005531 entry_args = {
5532 'of-list': 'test-fdt1 test-fdt2',
5533 'default-dt': 'test-fdt2',
5534 'atf-bl31-path': 'bl31.elf',
5535 'tee-os-path': 'missing.elf',
5536 }
5537 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5538 with test_util.capture_sys_output() as (stdout, stderr):
5539 self._DoTestFile(
5540 '226_fit_split_elf.dts', entry_args=entry_args,
Simon Glass7d3e4072022-08-07 09:46:46 -06005541 extra_indirs=[test_subdir], verbosity=3, **kwargs)
5542 out = stdout.getvalue()
5543 err = stderr.getvalue()
5544 return out, err
Simon Glass5f423422022-03-05 20:19:12 -07005545
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005546 def testFitSplitElfBadDirective(self):
5547 """Test a FIT split-elf invalid fit,xxx directive in an image node"""
5548 if not elf.ELF_TOOLS:
5549 self.skipTest('Python elftools not available')
5550 err = self._check_bad_fit('227_fit_bad_dir.dts')
5551 self.assertIn(
5552 "Node '/binman/fit': subnode 'images/@atf-SEQ': Unknown directive 'fit,something'",
5553 err)
5554
5555 def testFitSplitElfBadDirectiveConfig(self):
5556 """Test a FIT split-elf with invalid fit,xxx directive in config"""
5557 if not elf.ELF_TOOLS:
5558 self.skipTest('Python elftools not available')
5559 err = self._check_bad_fit('228_fit_bad_dir_config.dts')
5560 self.assertEqual(
5561 "Node '/binman/fit': subnode 'configurations/@config-SEQ': Unknown directive 'fit,config'",
5562 err)
5563
5564
Simon Glass5f423422022-03-05 20:19:12 -07005565 def testFitSplitElfMissing(self):
5566 """Test an split-elf FIT with a missing ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005567 if not elf.ELF_TOOLS:
5568 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005569 out, err = self.checkFitSplitElf(allow_missing=True)
Simon Glass5f423422022-03-05 20:19:12 -07005570 self.assertRegex(
5571 err,
5572 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005573 self.assertNotRegex(out, '.*Faked blob.*')
5574 fname = tools.get_output_filename('binman-fake/missing.elf')
5575 self.assertFalse(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005576
5577 def testFitSplitElfFaked(self):
5578 """Test an split-elf FIT with faked ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005579 if not elf.ELF_TOOLS:
5580 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005581 out, err = self.checkFitSplitElf(allow_missing=True, allow_fake_blobs=True)
Simon Glass5f423422022-03-05 20:19:12 -07005582 self.assertRegex(
5583 err,
5584 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005585 self.assertRegex(
5586 out,
5587 "Entry '/binman/fit/images/@tee-SEQ/tee-os': Faked blob '.*binman-fake/missing.elf")
5588 fname = tools.get_output_filename('binman-fake/missing.elf')
5589 self.assertTrue(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005590
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005591 def testMkimageMissingBlob(self):
5592 """Test using mkimage to build an image"""
5593 with test_util.capture_sys_output() as (stdout, stderr):
5594 self._DoTestFile('229_mkimage_missing.dts', allow_missing=True,
5595 allow_fake_blobs=True)
5596 err = stderr.getvalue()
5597 self.assertRegex(
5598 err,
5599 "Image '.*' has faked external blobs and is non-functional: .*")
5600
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005601 def testPreLoad(self):
5602 """Test an image with a pre-load header"""
5603 entry_args = {
5604 'pre-load-key-path': '.',
5605 }
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005606 data, _, _, _ = self._DoReadFileDtb('230_pre_load.dts',
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005607 entry_args=entry_args)
5608 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5609 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5610 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005611 data = self._DoReadFile('230_pre_load.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005612 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5613 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5614 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5615
5616 def testPreLoadPkcs(self):
5617 """Test an image with a pre-load header with padding pkcs"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005618 data = self._DoReadFile('231_pre_load_pkcs.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005619 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5620 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5621 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5622
5623 def testPreLoadPss(self):
5624 """Test an image with a pre-load header with padding pss"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005625 data = self._DoReadFile('232_pre_load_pss.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005626 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5627 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5628 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5629
5630 def testPreLoadInvalidPadding(self):
5631 """Test an image with a pre-load header with an invalid padding"""
5632 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005633 data = self._DoReadFile('233_pre_load_invalid_padding.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005634
5635 def testPreLoadInvalidSha(self):
5636 """Test an image with a pre-load header with an invalid hash"""
5637 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005638 data = self._DoReadFile('234_pre_load_invalid_sha.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005639
5640 def testPreLoadInvalidAlgo(self):
5641 """Test an image with a pre-load header with an invalid algo"""
5642 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005643 data = self._DoReadFile('235_pre_load_invalid_algo.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005644
5645 def testPreLoadInvalidKey(self):
5646 """Test an image with a pre-load header with an invalid key"""
5647 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005648 data = self._DoReadFile('236_pre_load_invalid_key.dts')
Roger Quadros5cdcea02022-02-19 20:50:04 +02005649
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005650 def _CheckSafeUniqueNames(self, *images):
5651 """Check all entries of given images for unsafe unique names"""
5652 for image in images:
5653 entries = {}
5654 image._CollectEntries(entries, {}, image)
5655 for entry in entries.values():
5656 uniq = entry.GetUniqueName()
5657
5658 # Used as part of a filename, so must not be absolute paths.
5659 self.assertFalse(os.path.isabs(uniq))
5660
5661 def testSafeUniqueNames(self):
5662 """Test entry unique names are safe in single image configuration"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005663 data = self._DoReadFileRealDtb('237_unique_names.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005664
5665 orig_image = control.images['image']
5666 image_fname = tools.get_output_filename('image.bin')
5667 image = Image.FromFile(image_fname)
5668
5669 self._CheckSafeUniqueNames(orig_image, image)
5670
5671 def testSafeUniqueNamesMulti(self):
5672 """Test entry unique names are safe with multiple images"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005673 data = self._DoReadFileRealDtb('238_unique_names_multi.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005674
5675 orig_image = control.images['image']
5676 image_fname = tools.get_output_filename('image.bin')
5677 image = Image.FromFile(image_fname)
5678
5679 self._CheckSafeUniqueNames(orig_image, image)
5680
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005681 def testReplaceCmdWithBintool(self):
5682 """Test replacing an entry that needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005683 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005684 expected = U_BOOT_DATA + b'aa'
5685 self.assertEqual(expected, data[:len(expected)])
5686
5687 try:
5688 tmpdir, updated_fname = self._SetupImageInTmpdir()
5689 fname = os.path.join(tmpdir, 'update-testing.bin')
5690 tools.write_file(fname, b'zz')
5691 self._DoBinman('replace', '-i', updated_fname,
5692 '_testing', '-f', fname)
5693
5694 data = tools.read_file(updated_fname)
5695 expected = U_BOOT_DATA + b'zz'
5696 self.assertEqual(expected, data[:len(expected)])
5697 finally:
5698 shutil.rmtree(tmpdir)
5699
5700 def testReplaceCmdOtherWithBintool(self):
5701 """Test replacing an entry when another needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005702 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005703 expected = U_BOOT_DATA + b'aa'
5704 self.assertEqual(expected, data[:len(expected)])
5705
5706 try:
5707 tmpdir, updated_fname = self._SetupImageInTmpdir()
5708 fname = os.path.join(tmpdir, 'update-u-boot.bin')
5709 tools.write_file(fname, b'x' * len(U_BOOT_DATA))
5710 self._DoBinman('replace', '-i', updated_fname,
5711 'u-boot', '-f', fname)
5712
5713 data = tools.read_file(updated_fname)
5714 expected = b'x' * len(U_BOOT_DATA) + b'aa'
5715 self.assertEqual(expected, data[:len(expected)])
5716 finally:
5717 shutil.rmtree(tmpdir)
5718
Alper Nebi Yasak00c68f12022-03-27 18:31:46 +03005719 def testReplaceResizeNoRepackSameSize(self):
5720 """Test replacing entries with same-size data without repacking"""
5721 expected = b'x' * len(U_BOOT_DATA)
5722 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected)
5723 self.assertEqual(expected, data)
5724
5725 path, fdtmap = state.GetFdtContents('fdtmap')
5726 self.assertIsNotNone(path)
5727 self.assertEqual(expected_fdtmap, fdtmap)
5728
5729 def testReplaceResizeNoRepackSmallerSize(self):
5730 """Test replacing entries with smaller-size data without repacking"""
5731 new_data = b'x'
5732 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', new_data)
5733 expected = new_data.ljust(len(U_BOOT_DATA), b'\0')
5734 self.assertEqual(expected, data)
5735
5736 path, fdtmap = state.GetFdtContents('fdtmap')
5737 self.assertIsNotNone(path)
5738 self.assertEqual(expected_fdtmap, fdtmap)
5739
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005740 def testExtractFit(self):
5741 """Test extracting a FIT section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005742 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005743 image_fname = tools.get_output_filename('image.bin')
5744
5745 fit_data = control.ReadEntry(image_fname, 'fit')
5746 fit = fdt.Fdt.FromData(fit_data)
5747 fit.Scan()
5748
5749 # Check subentry data inside the extracted fit
5750 for node_path, expected in [
5751 ('/images/kernel', U_BOOT_DATA),
5752 ('/images/fdt-1', U_BOOT_NODTB_DATA),
5753 ('/images/scr-1', COMPRESS_DATA),
5754 ]:
5755 node = fit.GetNode(node_path)
5756 data = fit.GetProps(node)['data'].bytes
5757 self.assertEqual(expected, data)
5758
5759 def testExtractFitSubentries(self):
5760 """Test extracting FIT section subentries"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005761 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005762 image_fname = tools.get_output_filename('image.bin')
5763
5764 for entry_path, expected in [
5765 ('fit/kernel', U_BOOT_DATA),
5766 ('fit/kernel/u-boot', U_BOOT_DATA),
5767 ('fit/fdt-1', U_BOOT_NODTB_DATA),
5768 ('fit/fdt-1/u-boot-nodtb', U_BOOT_NODTB_DATA),
5769 ('fit/scr-1', COMPRESS_DATA),
5770 ('fit/scr-1/blob', COMPRESS_DATA),
5771 ]:
5772 data = control.ReadEntry(image_fname, entry_path)
5773 self.assertEqual(expected, data)
5774
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005775 def testReplaceFitSubentryLeafSameSize(self):
5776 """Test replacing a FIT leaf subentry with same-size data"""
5777 new_data = b'x' * len(U_BOOT_DATA)
5778 data, expected_fdtmap, _ = self._RunReplaceCmd(
5779 'fit/kernel/u-boot', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005780 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005781 self.assertEqual(new_data, data)
5782
5783 path, fdtmap = state.GetFdtContents('fdtmap')
5784 self.assertIsNotNone(path)
5785 self.assertEqual(expected_fdtmap, fdtmap)
5786
5787 def testReplaceFitSubentryLeafBiggerSize(self):
5788 """Test replacing a FIT leaf subentry with bigger-size data"""
5789 new_data = b'ub' * len(U_BOOT_NODTB_DATA)
5790 data, expected_fdtmap, _ = self._RunReplaceCmd(
5791 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005792 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005793 self.assertEqual(new_data, data)
5794
5795 # Will be repacked, so fdtmap must change
5796 path, fdtmap = state.GetFdtContents('fdtmap')
5797 self.assertIsNotNone(path)
5798 self.assertNotEqual(expected_fdtmap, fdtmap)
5799
5800 def testReplaceFitSubentryLeafSmallerSize(self):
5801 """Test replacing a FIT leaf subentry with smaller-size data"""
5802 new_data = b'x'
5803 expected = new_data.ljust(len(U_BOOT_NODTB_DATA), b'\0')
5804 data, expected_fdtmap, _ = self._RunReplaceCmd(
5805 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005806 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005807 self.assertEqual(expected, data)
5808
5809 path, fdtmap = state.GetFdtContents('fdtmap')
5810 self.assertIsNotNone(path)
5811 self.assertEqual(expected_fdtmap, fdtmap)
5812
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03005813 def testReplaceSectionSimple(self):
5814 """Test replacing a simple section with arbitrary data"""
5815 new_data = b'w' * len(COMPRESS_DATA + U_BOOT_DATA)
Simon Glassc6b283f2022-08-13 11:40:46 -06005816 with self.assertRaises(ValueError) as exc:
5817 self._RunReplaceCmd('section', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005818 dts='241_replace_section_simple.dts')
Simon Glassc6b283f2022-08-13 11:40:46 -06005819 self.assertIn(
5820 "Node '/section': Replacing sections is not implemented yet",
5821 str(exc.exception))
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03005822
Simon Glass8fbca772022-08-13 11:40:48 -06005823 def testMkimageImagename(self):
5824 """Test using mkimage with -n holding the data too"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005825 data = self._DoReadFile('242_mkimage_name.dts')
Simon Glass8fbca772022-08-13 11:40:48 -06005826
5827 # Check that the data appears in the file somewhere
5828 self.assertIn(U_BOOT_SPL_DATA, data)
5829
Simon Glassbb7d3bb2022-09-06 20:26:52 -06005830 # Get struct legacy_img_hdr -> ih_name
Simon Glass8fbca772022-08-13 11:40:48 -06005831 name = data[0x20:0x40]
5832
5833 # Build the filename that we expect to be placed in there, by virtue of
5834 # the -n paraameter
5835 expect = os.path.join(tools.get_output_dir(), 'mkimage.mkimage')
5836
5837 # Check that the image name is set to the temporary filename used
5838 self.assertEqual(expect.encode('utf-8')[:0x20], name)
5839
Simon Glassb1669752022-08-13 11:40:49 -06005840 def testMkimageImage(self):
5841 """Test using mkimage with -n holding the data too"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005842 data = self._DoReadFile('243_mkimage_image.dts')
Simon Glassb1669752022-08-13 11:40:49 -06005843
5844 # Check that the data appears in the file somewhere
5845 self.assertIn(U_BOOT_SPL_DATA, data)
5846
Simon Glassbb7d3bb2022-09-06 20:26:52 -06005847 # Get struct legacy_img_hdr -> ih_name
Simon Glassb1669752022-08-13 11:40:49 -06005848 name = data[0x20:0x40]
5849
5850 # Build the filename that we expect to be placed in there, by virtue of
5851 # the -n paraameter
5852 expect = os.path.join(tools.get_output_dir(), 'mkimage-n.mkimage')
5853
5854 # Check that the image name is set to the temporary filename used
5855 self.assertEqual(expect.encode('utf-8')[:0x20], name)
5856
5857 # Check the corect data is in the imagename file
5858 self.assertEqual(U_BOOT_DATA, tools.read_file(expect))
5859
5860 def testMkimageImageNoContent(self):
5861 """Test using mkimage with -n and no data"""
5862 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005863 self._DoReadFile('244_mkimage_image_no_content.dts')
Simon Glassb1669752022-08-13 11:40:49 -06005864 self.assertIn('Could not complete processing of contents',
5865 str(exc.exception))
5866
5867 def testMkimageImageBad(self):
5868 """Test using mkimage with imagename node and data-to-imagename"""
5869 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005870 self._DoReadFile('245_mkimage_image_bad.dts')
Simon Glassb1669752022-08-13 11:40:49 -06005871 self.assertIn('Cannot use both imagename node and data-to-imagename',
5872 str(exc.exception))
5873
Simon Glassbd5cd882022-08-13 11:40:50 -06005874 def testCollectionOther(self):
5875 """Test a collection where the data comes from another section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005876 data = self._DoReadFile('246_collection_other.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06005877 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
5878 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
5879 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
5880 data)
5881
5882 def testMkimageCollection(self):
5883 """Test using a collection referring to an entry in a mkimage entry"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005884 data = self._DoReadFile('247_mkimage_coll.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06005885 expect = U_BOOT_SPL_DATA + U_BOOT_DATA
5886 self.assertEqual(expect, data[:len(expect)])
5887
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02005888 def testCompressDtbPrependInvalid(self):
5889 """Test that invalid header is detected"""
5890 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005891 self._DoReadFileDtb('248_compress_dtb_prepend_invalid.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02005892 self.assertIn("Node '/binman/u-boot-dtb': Invalid prepend in "
5893 "'u-boot-dtb': 'invalid'", str(e.exception))
5894
5895 def testCompressDtbPrependLength(self):
5896 """Test that compress with length header works as expected"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005897 data = self._DoReadFileRealDtb('249_compress_dtb_prepend_length.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02005898 image = control.images['image']
5899 entries = image.GetEntries()
5900 self.assertIn('u-boot-dtb', entries)
5901 u_boot_dtb = entries['u-boot-dtb']
5902 self.assertIn('fdtmap', entries)
5903 fdtmap = entries['fdtmap']
5904
5905 image_fname = tools.get_output_filename('image.bin')
5906 orig = control.ReadEntry(image_fname, 'u-boot-dtb')
5907 dtb = fdt.Fdt.FromData(orig)
5908 dtb.Scan()
5909 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
5910 expected = {
5911 'u-boot:size': len(U_BOOT_DATA),
5912 'u-boot-dtb:uncomp-size': len(orig),
5913 'u-boot-dtb:size': u_boot_dtb.size,
5914 'fdtmap:size': fdtmap.size,
5915 'size': len(data),
5916 }
5917 self.assertEqual(expected, props)
5918
5919 # Check implementation
5920 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
5921 rest = data[len(U_BOOT_DATA):]
5922 comp_data_len = struct.unpack('<I', rest[:4])[0]
5923 comp_data = rest[4:4 + comp_data_len]
5924 orig2 = self._decompress(comp_data)
5925 self.assertEqual(orig, orig2)
5926
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02005927 def testInvalidCompress(self):
5928 """Test that invalid compress algorithm is detected"""
5929 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005930 self._DoTestFile('250_compress_dtb_invalid.dts')
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02005931 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
5932
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02005933 def testCompUtilCompressions(self):
5934 """Test compression algorithms"""
5935 for bintool in self.comp_bintools.values():
5936 self._CheckBintool(bintool)
5937 data = bintool.compress(COMPRESS_DATA)
5938 self.assertNotEqual(COMPRESS_DATA, data)
5939 orig = bintool.decompress(data)
5940 self.assertEquals(COMPRESS_DATA, orig)
5941
5942 def testCompUtilVersions(self):
5943 """Test tool version of compression algorithms"""
5944 for bintool in self.comp_bintools.values():
5945 self._CheckBintool(bintool)
5946 version = bintool.version()
5947 self.assertRegex(version, '^v?[0-9]+[0-9.]*')
5948
5949 def testCompUtilPadding(self):
5950 """Test padding of compression algorithms"""
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02005951 # Skip zstd because it doesn't support padding
5952 for bintool in [v for k,v in self.comp_bintools.items() if k != 'zstd']:
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02005953 self._CheckBintool(bintool)
5954 data = bintool.compress(COMPRESS_DATA)
5955 self.assertNotEqual(COMPRESS_DATA, data)
5956 data += tools.get_bytes(0, 64)
5957 orig = bintool.decompress(data)
5958 self.assertEquals(COMPRESS_DATA, orig)
5959
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02005960 def testCompressDtbZstd(self):
5961 """Test that zstd compress of device-tree files failed"""
5962 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005963 self._DoTestFile('251_compress_dtb_zstd.dts')
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02005964 self.assertIn("Node '/binman/u-boot-dtb': The zstd compression "
5965 "requires a length header", str(e.exception))
5966
Quentin Schulz9b5c6482022-09-02 15:10:48 +02005967 def testMkimageMultipleDataFiles(self):
5968 """Test passing multiple files to mkimage in a mkimage entry"""
5969 data = self._DoReadFile('252_mkimage_mult_data.dts')
5970 # Size of files are packed in their 4B big-endian format
5971 expect = struct.pack('>I', len(U_BOOT_TPL_DATA))
5972 expect += struct.pack('>I', len(U_BOOT_SPL_DATA))
5973 # Size info is always followed by a 4B zero value.
5974 expect += tools.get_bytes(0, 4)
5975 expect += U_BOOT_TPL_DATA
5976 # All but last files are 4B-aligned
5977 align_pad = len(U_BOOT_TPL_DATA) % 4
5978 if align_pad:
5979 expect += tools.get_bytes(0, align_pad)
5980 expect += U_BOOT_SPL_DATA
5981 self.assertEqual(expect, data[-len(expect):])
5982
5983 def testMkimageMultipleNoContent(self):
5984 """Test passing multiple data files to mkimage with one data file having no content"""
5985 with self.assertRaises(ValueError) as exc:
5986 self._DoReadFile('253_mkimage_mult_no_content.dts')
5987 self.assertIn('Could not complete processing of contents',
5988 str(exc.exception))
5989
Quentin Schulz0d3a9262022-09-02 15:10:49 +02005990 def testMkimageFilename(self):
5991 """Test using mkimage to build a binary with a filename"""
5992 retcode = self._DoTestFile('254_mkimage_filename.dts')
5993 self.assertEqual(0, retcode)
5994 fname = tools.get_output_filename('mkimage-test.bin')
5995 self.assertTrue(os.path.exists(fname))
5996
Simon Glass56d05412022-02-28 07:16:54 -07005997 def testVpl(self):
5998 """Test that an image with VPL and its device tree can be created"""
5999 # ELF file with a '__bss_size' symbol
6000 self._SetupVplElf()
6001 data = self._DoReadFile('255_u_boot_vpl.dts')
6002 self.assertEqual(U_BOOT_VPL_DATA + U_BOOT_VPL_DTB_DATA, data)
6003
6004 def testVplNoDtb(self):
6005 """Test that an image with vpl/u-boot-vpl-nodtb.bin can be created"""
6006 self._SetupVplElf()
6007 data = self._DoReadFile('256_u_boot_vpl_nodtb.dts')
6008 self.assertEqual(U_BOOT_VPL_NODTB_DATA,
6009 data[:len(U_BOOT_VPL_NODTB_DATA)])
6010
6011 def testExpandedVpl(self):
6012 """Test that an expanded entry type is selected for TPL when needed"""
6013 self._SetupVplElf()
6014
6015 entry_args = {
6016 'vpl-bss-pad': 'y',
6017 'vpl-dtb': 'y',
6018 }
6019 self._DoReadFileDtb('257_fdt_incl_vpl.dts', use_expanded=True,
6020 entry_args=entry_args)
6021 image = control.images['image']
6022 entries = image.GetEntries()
6023 self.assertEqual(1, len(entries))
6024
6025 # We only have u-boot-vpl, which be expanded
6026 self.assertIn('u-boot-vpl', entries)
6027 entry = entries['u-boot-vpl']
6028 self.assertEqual('u-boot-vpl-expanded', entry.etype)
6029 subent = entry.GetEntries()
6030 self.assertEqual(3, len(subent))
6031 self.assertIn('u-boot-vpl-nodtb', subent)
6032 self.assertIn('u-boot-vpl-bss-pad', subent)
6033 self.assertIn('u-boot-vpl-dtb', subent)
6034
6035 def testVplBssPadMissing(self):
6036 """Test that a missing symbol is detected"""
6037 self._SetupVplElf('u_boot_ucode_ptr')
6038 with self.assertRaises(ValueError) as e:
6039 self._DoReadFile('258_vpl_bss_pad.dts')
6040 self.assertIn('Expected __bss_size symbol in vpl/u-boot-vpl',
6041 str(e.exception))
6042
Neha Malcom Francis3eb4be32022-10-17 16:36:25 +05306043 def testSymlink(self):
6044 """Test that image files can be named"""
6045 retcode = self._DoTestFile('259_symlink.dts', debug=True, map=True)
6046 self.assertEqual(0, retcode)
6047 image = control.images['test_image']
6048 fname = tools.get_output_filename('test_image.bin')
6049 sname = tools.get_output_filename('symlink_to_test.bin')
6050 self.assertTrue(os.path.islink(sname))
6051 self.assertEqual(os.readlink(sname), fname)
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03006052
Simon Glass37f85de2022-10-20 18:22:47 -06006053 def testSymbolsElf(self):
6054 """Test binman can assign symbols embedded in an ELF file"""
6055 if not elf.ELF_TOOLS:
6056 self.skipTest('Python elftools not available')
6057 self._SetupTplElf('u_boot_binman_syms')
6058 self._SetupVplElf('u_boot_binman_syms')
6059 self._SetupSplElf('u_boot_binman_syms')
6060 data = self._DoReadFileDtb('260_symbols_elf.dts')[0]
6061 image_fname = tools.get_output_filename('image.bin')
6062
6063 image = control.images['image']
6064 entries = image.GetEntries()
6065
6066 for entry in entries.values():
6067 # No symbols in u-boot and it has faked contents anyway
6068 if entry.name == 'u-boot':
6069 continue
6070 edata = data[entry.image_pos:entry.image_pos + entry.size]
6071 efname = tools.get_output_filename(f'edata-{entry.name}')
6072 tools.write_file(efname, edata)
6073
6074 syms = elf.GetSymbolFileOffset(efname, ['_binman_u_boot'])
6075 re_name = re.compile('_binman_(u_boot_(.*))_prop_(.*)')
6076 for name, sym in syms.items():
6077 msg = 'test'
6078 val = elf.GetSymbolValue(sym, edata, msg)
6079 entry_m = re_name.match(name)
6080 if entry_m:
6081 ename, prop = entry_m.group(1), entry_m.group(3)
6082 entry, entry_name, prop_name = image.LookupEntry(entries,
6083 name, msg)
6084 if prop_name == 'offset':
6085 expect_val = entry.offset
6086 elif prop_name == 'image_pos':
6087 expect_val = entry.image_pos
6088 elif prop_name == 'size':
6089 expect_val = entry.size
6090 self.assertEqual(expect_val, val)
6091
6092 def testSymbolsElfBad(self):
6093 """Check error when trying to write symbols without the elftools lib"""
6094 if not elf.ELF_TOOLS:
6095 self.skipTest('Python elftools not available')
6096 self._SetupTplElf('u_boot_binman_syms')
6097 self._SetupVplElf('u_boot_binman_syms')
6098 self._SetupSplElf('u_boot_binman_syms')
6099 try:
6100 elf.ELF_TOOLS = False
6101 with self.assertRaises(ValueError) as exc:
6102 self._DoReadFileDtb('260_symbols_elf.dts')
6103 finally:
6104 elf.ELF_TOOLS = True
6105 self.assertIn(
6106 "Section '/binman': entry '/binman/u-boot-spl-elf': "
6107 'Cannot write symbols to an ELF file without Python elftools',
6108 str(exc.exception))
6109
Simon Glassde244162023-01-07 14:07:08 -07006110 def testSectionFilename(self):
6111 """Check writing of section contents to a file"""
6112 data = self._DoReadFile('261_section_fname.dts')
6113 expected = (b'&&' + U_BOOT_DATA + b'&&&' +
6114 tools.get_bytes(ord('!'), 7) +
6115 U_BOOT_DATA + tools.get_bytes(ord('&'), 12))
6116 self.assertEqual(expected, data)
6117
6118 sect_fname = tools.get_output_filename('outfile.bin')
6119 self.assertTrue(os.path.exists(sect_fname))
6120 sect_data = tools.read_file(sect_fname)
6121 self.assertEqual(U_BOOT_DATA, sect_data)
6122
Simon Glass1e9e61c2023-01-07 14:07:12 -07006123 def testAbsent(self):
6124 """Check handling of absent entries"""
6125 data = self._DoReadFile('262_absent.dts')
6126 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6127
Simon Glassad5cfe12023-01-07 14:07:14 -07006128 def testPackTeeOsOptional(self):
6129 """Test that an image with an optional TEE binary can be created"""
6130 entry_args = {
6131 'tee-os-path': 'tee.elf',
6132 }
6133 data = self._DoReadFileDtb('263_tee_os_opt.dts',
6134 entry_args=entry_args)[0]
6135 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6136
6137 def checkFitTee(self, dts, tee_fname):
6138 """Check that a tee-os entry works and returns data
6139
6140 Args:
6141 dts (str): Device tree filename to use
6142 tee_fname (str): filename containing tee-os
6143
6144 Returns:
6145 bytes: Image contents
6146 """
6147 if not elf.ELF_TOOLS:
6148 self.skipTest('Python elftools not available')
6149 entry_args = {
6150 'of-list': 'test-fdt1 test-fdt2',
6151 'default-dt': 'test-fdt2',
6152 'tee-os-path': tee_fname,
6153 }
6154 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
6155 data = self._DoReadFileDtb(dts, entry_args=entry_args,
6156 extra_indirs=[test_subdir])[0]
6157 return data
6158
6159 def testFitTeeOsOptionalFit(self):
6160 """Test an image with a FIT with an optional OP-TEE binary"""
6161 data = self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bin')
6162
6163 # There should be only one node, holding the data set up in SetUpClass()
6164 # for tee.bin
6165 dtb = fdt.Fdt.FromData(data)
6166 dtb.Scan()
6167 node = dtb.GetNode('/images/tee-1')
6168 self.assertEqual(TEE_ADDR,
6169 fdt_util.fdt32_to_cpu(node.props['load'].value))
6170 self.assertEqual(TEE_ADDR,
6171 fdt_util.fdt32_to_cpu(node.props['entry'].value))
6172 self.assertEqual(U_BOOT_DATA, node.props['data'].bytes)
6173
6174 def testFitTeeOsOptionalFitBad(self):
6175 """Test an image with a FIT with an optional OP-TEE binary"""
6176 with self.assertRaises(ValueError) as exc:
6177 self.checkFitTee('265_tee_os_opt_fit_bad.dts', 'tee.bin')
6178 self.assertIn(
6179 "Node '/binman/fit': subnode 'images/@tee-SEQ': Failed to read ELF file: Magic number does not match",
6180 str(exc.exception))
6181
6182 def testFitTeeOsBad(self):
6183 """Test an OP-TEE binary with wrong formats"""
6184 self.make_tee_bin('tee.bad1', 123)
6185 with self.assertRaises(ValueError) as exc:
6186 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad1')
6187 self.assertIn(
6188 "Node '/binman/fit/images/@tee-SEQ/tee-os': OP-TEE paged mode not supported",
6189 str(exc.exception))
6190
6191 self.make_tee_bin('tee.bad2', 0, b'extra data')
6192 with self.assertRaises(ValueError) as exc:
6193 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad2')
6194 self.assertIn(
6195 "Node '/binman/fit/images/@tee-SEQ/tee-os': Invalid OP-TEE file: size mismatch (expected 0x4, have 0xe)",
6196 str(exc.exception))
6197
Simon Glass63328f12023-01-07 14:07:15 -07006198 def testExtblobOptional(self):
6199 """Test an image with an external blob that is optional"""
6200 with test_util.capture_sys_output() as (stdout, stderr):
6201 data = self._DoReadFile('266_blob_ext_opt.dts')
6202 self.assertEqual(REFCODE_DATA, data)
6203 err = stderr.getvalue()
6204 self.assertRegex(
6205 err,
6206 "Image '.*' is missing external blobs but is still functional: missing")
6207
Simon Glass7447a9d2023-01-11 16:10:12 -07006208 def testSectionInner(self):
6209 """Test an inner section with a size"""
6210 data = self._DoReadFile('267_section_inner.dts')
6211 expected = U_BOOT_DATA + tools.get_bytes(0, 12)
6212 self.assertEqual(expected, data)
6213
Simon Glassa4948b22023-01-11 16:10:14 -07006214 def testNull(self):
6215 """Test an image with a null entry"""
6216 data = self._DoReadFile('268_null.dts')
6217 self.assertEqual(U_BOOT_DATA + b'\xff\xff\xff\xff' + U_BOOT_IMG_DATA, data)
6218
Simon Glassf1ee03b2023-01-11 16:10:16 -07006219 def testOverlap(self):
6220 """Test an image with a overlapping entry"""
6221 data = self._DoReadFile('269_overlap.dts')
6222 self.assertEqual(U_BOOT_DATA[:1] + b'aa' + U_BOOT_DATA[3:], data)
6223
6224 image = control.images['image']
6225 entries = image.GetEntries()
6226
6227 self.assertIn('inset', entries)
6228 inset = entries['inset']
6229 self.assertEqual(1, inset.offset);
6230 self.assertEqual(1, inset.image_pos);
6231 self.assertEqual(2, inset.size);
6232
6233 def testOverlapNull(self):
6234 """Test an image with a null overlap"""
6235 data = self._DoReadFile('270_overlap_null.dts')
6236 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6237
6238 # Check the FMAP
6239 fhdr, fentries = fmap_util.DecodeFmap(data[len(U_BOOT_DATA):])
6240 self.assertEqual(4, fhdr.nareas)
6241 fiter = iter(fentries)
6242
6243 fentry = next(fiter)
6244 self.assertEqual(b'SECTION', fentry.name)
6245 self.assertEqual(0, fentry.offset)
6246 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6247 self.assertEqual(0, fentry.flags)
6248
6249 fentry = next(fiter)
6250 self.assertEqual(b'U_BOOT', fentry.name)
6251 self.assertEqual(0, fentry.offset)
6252 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6253 self.assertEqual(0, fentry.flags)
6254
6255 # Make sure that the NULL entry appears in the FMAP
6256 fentry = next(fiter)
6257 self.assertEqual(b'NULL', fentry.name)
6258 self.assertEqual(1, fentry.offset)
6259 self.assertEqual(2, fentry.size)
6260 self.assertEqual(0, fentry.flags)
6261
6262 fentry = next(fiter)
6263 self.assertEqual(b'FMAP', fentry.name)
6264 self.assertEqual(len(U_BOOT_DATA), fentry.offset)
6265
6266 def testOverlapBad(self):
6267 """Test an image with a bad overlapping entry"""
6268 with self.assertRaises(ValueError) as exc:
6269 self._DoReadFile('271_overlap_bad.dts')
6270 self.assertIn(
6271 "Node '/binman/inset': Offset 0x10 (16) ending at 0x12 (18) must overlap with existing entries",
6272 str(exc.exception))
6273
6274 def testOverlapNoOffset(self):
6275 """Test an image with a bad overlapping entry"""
6276 with self.assertRaises(ValueError) as exc:
6277 self._DoReadFile('272_overlap_no_size.dts')
6278 self.assertIn(
6279 "Node '/binman/inset': 'fill' entry is missing properties: size",
6280 str(exc.exception))
6281
Simon Glasse0035c92023-01-11 16:10:17 -07006282 def testBlobSymbol(self):
6283 """Test a blob with symbols read from an ELF file"""
6284 elf_fname = self.ElfTestFile('blob_syms')
6285 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6286 TestFunctional._MakeInputFile('blob_syms.bin',
6287 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6288
6289 data = self._DoReadFile('273_blob_symbol.dts')
6290
6291 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6292 addr = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6293 self.assertEqual(syms['_binman_sym_magic'].address, addr)
6294 self.assertEqual(syms['_binman_inset_prop_offset'].address, addr + 4)
6295 self.assertEqual(syms['_binman_inset_prop_size'].address, addr + 8)
6296
6297 sym_values = struct.pack('<LLL', elf.BINMAN_SYM_MAGIC_VALUE, 4, 8)
6298 expected = sym_values
6299 self.assertEqual(expected, data[:len(expected)])
6300
Simon Glass49e9c002023-01-11 16:10:19 -07006301 def testOffsetFromElf(self):
6302 """Test a blob with symbols read from an ELF file"""
6303 elf_fname = self.ElfTestFile('blob_syms')
6304 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6305 TestFunctional._MakeInputFile('blob_syms.bin',
6306 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6307
6308 data = self._DoReadFile('274_offset_from_elf.dts')
6309
6310 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6311 base = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6312
6313 image = control.images['image']
6314 entries = image.GetEntries()
6315
6316 self.assertIn('inset', entries)
6317 inset = entries['inset']
6318
6319 self.assertEqual(base + 4, inset.offset);
6320 self.assertEqual(base + 4, inset.image_pos);
6321 self.assertEqual(4, inset.size);
6322
6323 self.assertIn('inset2', entries)
6324 inset = entries['inset2']
6325 self.assertEqual(base + 8, inset.offset);
6326 self.assertEqual(base + 8, inset.image_pos);
6327 self.assertEqual(4, inset.size);
6328
Jonas Karlmanc59ea892023-01-21 19:01:39 +00006329 def testFitAlign(self):
6330 """Test an image with an FIT with aligned external data"""
6331 data = self._DoReadFile('275_fit_align.dts')
6332 self.assertEqual(4096, len(data))
6333
6334 dtb = fdt.Fdt.FromData(data)
6335 dtb.Scan()
6336
6337 props = self._GetPropTree(dtb, ['data-position'])
6338 expected = {
6339 'u-boot:data-position': 1024,
6340 'fdt-1:data-position': 2048,
6341 'fdt-2:data-position': 3072,
6342 }
6343 self.assertEqual(expected, props)
6344
Jonas Karlman490f73c2023-01-21 19:02:12 +00006345 def testFitFirmwareLoadables(self):
6346 """Test an image with an FIT that use fit,firmware"""
6347 if not elf.ELF_TOOLS:
6348 self.skipTest('Python elftools not available')
6349 entry_args = {
6350 'of-list': 'test-fdt1',
6351 'default-dt': 'test-fdt1',
6352 'atf-bl31-path': 'bl31.elf',
6353 'tee-os-path': 'missing.bin',
6354 }
6355 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
6356 data = self._DoReadFileDtb(
6357 '276_fit_firmware_loadables.dts',
6358 entry_args=entry_args,
6359 extra_indirs=[test_subdir])[0]
6360
6361 dtb = fdt.Fdt.FromData(data)
6362 dtb.Scan()
6363
6364 node = dtb.GetNode('/configurations/conf-uboot-1')
6365 self.assertEqual('u-boot', node.props['firmware'].value)
6366 self.assertEqual(['atf-1', 'atf-2'],
6367 fdt_util.GetStringList(node, 'loadables'))
6368
6369 node = dtb.GetNode('/configurations/conf-atf-1')
6370 self.assertEqual('atf-1', node.props['firmware'].value)
6371 self.assertEqual(['u-boot', 'atf-2'],
6372 fdt_util.GetStringList(node, 'loadables'))
6373
6374 node = dtb.GetNode('/configurations/conf-missing-uboot-1')
6375 self.assertEqual('u-boot', node.props['firmware'].value)
6376 self.assertEqual(['atf-1', 'atf-2'],
6377 fdt_util.GetStringList(node, 'loadables'))
6378
6379 node = dtb.GetNode('/configurations/conf-missing-atf-1')
6380 self.assertEqual('atf-1', node.props['firmware'].value)
6381 self.assertEqual(['u-boot', 'atf-2'],
6382 fdt_util.GetStringList(node, 'loadables'))
6383
6384 node = dtb.GetNode('/configurations/conf-missing-tee-1')
6385 self.assertEqual('atf-1', node.props['firmware'].value)
6386 self.assertEqual(['u-boot', 'atf-2'],
6387 fdt_util.GetStringList(node, 'loadables'))
6388
Simon Glass9a1c7262023-02-22 12:14:49 -07006389 def testTooldir(self):
6390 """Test that we can specify the tooldir"""
6391 with test_util.capture_sys_output() as (stdout, stderr):
6392 self.assertEqual(0, self._DoBinman('--tooldir', 'fred',
6393 'tool', '-l'))
6394 self.assertEqual('fred', bintool.Bintool.tooldir)
6395
6396 # Check that the toolpath is updated correctly
6397 self.assertEqual(['fred'], tools.tool_search_paths)
6398
6399 # Try with a few toolpaths; the tooldir should be at the end
6400 with test_util.capture_sys_output() as (stdout, stderr):
6401 self.assertEqual(0, self._DoBinman(
6402 '--toolpath', 'mary', '--toolpath', 'anna', '--tooldir', 'fred',
6403 'tool', '-l'))
6404 self.assertEqual(['mary', 'anna', 'fred'], tools.tool_search_paths)
6405
Simon Glassde244162023-01-07 14:07:08 -07006406
Simon Glassac599912017-11-12 21:52:22 -07006407if __name__ == "__main__":
6408 unittest.main()