blob: be0aea49ce9b738be8341fdde49b65a5e2d57759 [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()
Simon Glass57454f42016-11-25 20:15:52 -0700886 self.assertEqual(5, len(entries))
887
888 # First u-boot with padding before and after
889 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
937 self.CheckNoGaps(entries)
Simon Glass39dd2152019-07-08 14:25:47 -0600938 self.assertEqual(128, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700939
Simon Glassafb9caa2020-10-26 17:40:10 -0600940 dtb = fdt.Fdt(out_dtb_fname)
941 dtb.Scan()
942 props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
943 expected = {
944 'image-pos': 0,
945 'offset': 0,
946 'size': 128,
947
948 'u-boot:image-pos': 0,
949 'u-boot:offset': 0,
950 'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
951
952 'u-boot-align-size-nop:image-pos': 12,
953 'u-boot-align-size-nop:offset': 12,
954 'u-boot-align-size-nop:size': 4,
955
956 'u-boot-align-size:image-pos': 16,
957 'u-boot-align-size:offset': 16,
958 'u-boot-align-size:size': 32,
959
960 'u-boot-align-end:image-pos': 48,
961 'u-boot-align-end:offset': 48,
962 'u-boot-align-end:size': 16,
963
964 'u-boot-align-both:image-pos': 64,
965 'u-boot-align-both:offset': 64,
966 'u-boot-align-both:size': 64,
967 }
968 self.assertEqual(expected, props)
969
Simon Glass57454f42016-11-25 20:15:52 -0700970 def testPackAlignPowerOf2(self):
971 """Test that invalid entry alignment is detected"""
972 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600973 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700974 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
975 "of two", str(e.exception))
976
977 def testPackAlignSizePowerOf2(self):
978 """Test that invalid entry size alignment is detected"""
979 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600980 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700981 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
982 "power of two", str(e.exception))
983
984 def testPackInvalidAlign(self):
Simon Glasse8561af2018-08-01 15:22:37 -0600985 """Test detection of an offset that does not match its alignment"""
Simon Glass57454f42016-11-25 20:15:52 -0700986 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600987 self._DoTestFile('012_pack_inv_align.dts')
Simon Glasse8561af2018-08-01 15:22:37 -0600988 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass57454f42016-11-25 20:15:52 -0700989 "align 0x4 (4)", str(e.exception))
990
991 def testPackInvalidSizeAlign(self):
992 """Test that invalid entry size alignment is detected"""
993 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600994 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700995 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
996 "align-size 0x4 (4)", str(e.exception))
997
998 def testPackOverlap(self):
999 """Test that overlapping regions are detected"""
1000 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001001 self._DoTestFile('014_pack_overlap.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001002 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -07001003 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1004 str(e.exception))
1005
1006 def testPackEntryOverflow(self):
1007 """Test that entries that overflow their size are detected"""
1008 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001009 self._DoTestFile('015_pack_overflow.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001010 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
1011 "but entry size is 0x3 (3)", str(e.exception))
1012
1013 def testPackImageOverflow(self):
1014 """Test that entries which overflow the image size are detected"""
1015 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001016 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glasseca32212018-06-01 09:38:12 -06001017 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass57454f42016-11-25 20:15:52 -07001018 "size 0x3 (3)", str(e.exception))
1019
1020 def testPackImageSize(self):
1021 """Test that the image size can be set"""
Simon Glass511f6582018-10-01 12:22:30 -06001022 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001023 self.assertEqual(0, retcode)
1024 self.assertIn('image', control.images)
1025 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -06001026 self.assertEqual(7, image.size)
Simon Glass57454f42016-11-25 20:15:52 -07001027
1028 def testPackImageSizeAlign(self):
1029 """Test that image size alignemnt works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -06001030 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001031 self.assertEqual(0, retcode)
1032 self.assertIn('image', control.images)
1033 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -06001034 self.assertEqual(16, image.size)
Simon Glass57454f42016-11-25 20:15:52 -07001035
1036 def testPackInvalidImageAlign(self):
1037 """Test that invalid image alignment is detected"""
1038 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001039 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glasseca32212018-06-01 09:38:12 -06001040 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass57454f42016-11-25 20:15:52 -07001041 "align-size 0x8 (8)", str(e.exception))
1042
Simon Glass2a0fa982022-02-11 13:23:21 -07001043 def testPackAlignPowerOf2Inv(self):
Simon Glass57454f42016-11-25 20:15:52 -07001044 """Test that invalid image alignment is detected"""
1045 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001046 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001047 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass57454f42016-11-25 20:15:52 -07001048 "two", str(e.exception))
1049
1050 def testImagePadByte(self):
1051 """Test that the image pad byte can be specified"""
Simon Glass7057d022018-10-01 21:12:47 -06001052 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001053 data = self._DoReadFile('021_image_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07001054 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0xff, 1) +
Simon Glassac0d4952019-05-14 15:53:47 -06001055 U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -07001056
1057 def testImageName(self):
1058 """Test that image files can be named"""
Simon Glass511f6582018-10-01 12:22:30 -06001059 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001060 self.assertEqual(0, retcode)
1061 image = control.images['image1']
Simon Glass80025522022-01-29 14:14:04 -07001062 fname = tools.get_output_filename('test-name')
Simon Glass57454f42016-11-25 20:15:52 -07001063 self.assertTrue(os.path.exists(fname))
1064
1065 image = control.images['image2']
Simon Glass80025522022-01-29 14:14:04 -07001066 fname = tools.get_output_filename('test-name.xx')
Simon Glass57454f42016-11-25 20:15:52 -07001067 self.assertTrue(os.path.exists(fname))
1068
1069 def testBlobFilename(self):
1070 """Test that generic blobs can be provided by filename"""
Simon Glass511f6582018-10-01 12:22:30 -06001071 data = self._DoReadFile('023_blob.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001072 self.assertEqual(BLOB_DATA, data)
1073
1074 def testPackSorted(self):
1075 """Test that entries can be sorted"""
Simon Glass7057d022018-10-01 21:12:47 -06001076 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001077 data = self._DoReadFile('024_sorted.dts')
Simon Glass80025522022-01-29 14:14:04 -07001078 self.assertEqual(tools.get_bytes(0, 1) + U_BOOT_SPL_DATA +
1079 tools.get_bytes(0, 2) + U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -07001080
Simon Glasse8561af2018-08-01 15:22:37 -06001081 def testPackZeroOffset(self):
1082 """Test that an entry at offset 0 is not given a new offset"""
Simon Glass57454f42016-11-25 20:15:52 -07001083 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001084 self._DoTestFile('025_pack_zero_size.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001085 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -07001086 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1087 str(e.exception))
1088
1089 def testPackUbootDtb(self):
1090 """Test that a device tree can be added to U-Boot"""
Simon Glass511f6582018-10-01 12:22:30 -06001091 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001092 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glass72232452016-11-25 20:15:53 -07001093
1094 def testPackX86RomNoSize(self):
1095 """Test that the end-at-4gb property requires a size property"""
1096 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001097 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001098 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glass72232452016-11-25 20:15:53 -07001099 "using end-at-4gb", str(e.exception))
1100
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301101 def test4gbAndSkipAtStartTogether(self):
1102 """Test that the end-at-4gb and skip-at-size property can't be used
1103 together"""
1104 with self.assertRaises(ValueError) as e:
Simon Glass11f2bd02019-08-24 07:23:02 -06001105 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001106 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301107 "'skip-at-start'", str(e.exception))
1108
Simon Glass72232452016-11-25 20:15:53 -07001109 def testPackX86RomOutside(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001110 """Test that the end-at-4gb property checks for offset boundaries"""
Simon Glass72232452016-11-25 20:15:53 -07001111 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001112 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glassd6179862020-10-26 17:40:05 -06001113 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
1114 "is outside the section '/binman' starting at "
1115 '0xffffffe0 (4294967264) of size 0x20 (32)',
Simon Glass72232452016-11-25 20:15:53 -07001116 str(e.exception))
1117
1118 def testPackX86Rom(self):
1119 """Test that a basic x86 ROM can be created"""
Simon Glass7057d022018-10-01 21:12:47 -06001120 self._SetupSplElf()
Simon Glass1d167762019-08-24 07:23:01 -06001121 data = self._DoReadFile('029_x86_rom.dts')
Simon Glass80025522022-01-29 14:14:04 -07001122 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 3) + U_BOOT_SPL_DATA +
1123 tools.get_bytes(0, 2), data)
Simon Glass72232452016-11-25 20:15:53 -07001124
1125 def testPackX86RomMeNoDesc(self):
1126 """Test that an invalid Intel descriptor entry is detected"""
Simon Glasse88cef92020-07-09 18:39:41 -06001127 try:
Simon Glass14c596c2020-07-25 15:11:19 -06001128 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
Simon Glasse88cef92020-07-09 18:39:41 -06001129 with self.assertRaises(ValueError) as e:
Simon Glass14c596c2020-07-25 15:11:19 -06001130 self._DoTestFile('163_x86_rom_me_empty.dts')
Simon Glasse88cef92020-07-09 18:39:41 -06001131 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1132 str(e.exception))
1133 finally:
1134 self._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -07001135
1136 def testPackX86RomBadDesc(self):
1137 """Test that the Intel requires a descriptor entry"""
1138 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06001139 self._DoTestFile('030_x86_rom_me_no_desc.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001140 self.assertIn("Node '/binman/intel-me': No offset set with "
1141 "offset-unset: should another entry provide this correct "
1142 "offset?", str(e.exception))
Simon Glass72232452016-11-25 20:15:53 -07001143
1144 def testPackX86RomMe(self):
1145 """Test that an x86 ROM with an ME region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001146 data = self._DoReadFile('031_x86_rom_me.dts')
Simon Glass80025522022-01-29 14:14:04 -07001147 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glass759af872019-07-08 13:18:54 -06001148 if data[:0x1000] != expected_desc:
1149 self.fail('Expected descriptor binary at start of image')
Simon Glass72232452016-11-25 20:15:53 -07001150 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1151
1152 def testPackVga(self):
1153 """Test that an image with a VGA binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001154 data = self._DoReadFile('032_intel_vga.dts')
Simon Glass72232452016-11-25 20:15:53 -07001155 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1156
1157 def testPackStart16(self):
1158 """Test that an image with an x86 start16 region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001159 data = self._DoReadFile('033_x86_start16.dts')
Simon Glass72232452016-11-25 20:15:53 -07001160 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1161
Jagdish Gediya311d4842018-09-03 21:35:08 +05301162 def testPackPowerpcMpc85xxBootpgResetvec(self):
1163 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1164 created"""
Simon Glass11f2bd02019-08-24 07:23:02 -06001165 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
Jagdish Gediya311d4842018-09-03 21:35:08 +05301166 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1167
Simon Glass6ba679c2018-07-06 10:27:17 -06001168 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glass820af1d2018-07-06 10:27:16 -06001169 """Handle running a test for insertion of microcode
1170
1171 Args:
1172 dts_fname: Name of test .dts file
1173 nodtb_data: Data that we expect in the first section
Simon Glass6ba679c2018-07-06 10:27:17 -06001174 ucode_second: True if the microsecond entry is second instead of
1175 third
Simon Glass820af1d2018-07-06 10:27:16 -06001176
1177 Returns:
1178 Tuple:
1179 Contents of first region (U-Boot or SPL)
Simon Glasse8561af2018-08-01 15:22:37 -06001180 Offset and size components of microcode pointer, as inserted
Simon Glass820af1d2018-07-06 10:27:16 -06001181 in the above (two 4-byte words)
1182 """
Simon Glass3d274232017-11-12 21:52:27 -07001183 data = self._DoReadFile(dts_fname, True)
Simon Glass72232452016-11-25 20:15:53 -07001184
1185 # Now check the device tree has no microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001186 if ucode_second:
1187 ucode_content = data[len(nodtb_data):]
1188 ucode_pos = len(nodtb_data)
1189 dtb_with_ucode = ucode_content[16:]
1190 fdt_len = self.GetFdtLen(dtb_with_ucode)
1191 else:
1192 dtb_with_ucode = data[len(nodtb_data):]
1193 fdt_len = self.GetFdtLen(dtb_with_ucode)
1194 ucode_content = dtb_with_ucode[fdt_len:]
1195 ucode_pos = len(nodtb_data) + fdt_len
Simon Glass80025522022-01-29 14:14:04 -07001196 fname = tools.get_output_filename('test.dtb')
Simon Glass72232452016-11-25 20:15:53 -07001197 with open(fname, 'wb') as fd:
Simon Glass820af1d2018-07-06 10:27:16 -06001198 fd.write(dtb_with_ucode)
Simon Glass22c92ca2017-05-27 07:38:29 -06001199 dtb = fdt.FdtScan(fname)
1200 ucode = dtb.GetNode('/microcode')
Simon Glass72232452016-11-25 20:15:53 -07001201 self.assertTrue(ucode)
1202 for node in ucode.subnodes:
1203 self.assertFalse(node.props.get('data'))
1204
Simon Glass72232452016-11-25 20:15:53 -07001205 # Check that the microcode appears immediately after the Fdt
1206 # This matches the concatenation of the data properties in
Simon Glasse83679d2017-11-12 21:52:26 -07001207 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glass72232452016-11-25 20:15:53 -07001208 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1209 0x78235609)
Simon Glass820af1d2018-07-06 10:27:16 -06001210 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glass72232452016-11-25 20:15:53 -07001211
1212 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001213 # expected offset and size
Simon Glass72232452016-11-25 20:15:53 -07001214 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1215 len(ucode_data))
Simon Glass6ba679c2018-07-06 10:27:17 -06001216 u_boot = data[:len(nodtb_data)]
1217 return u_boot, pos_and_size
Simon Glass3d274232017-11-12 21:52:27 -07001218
1219 def testPackUbootMicrocode(self):
1220 """Test that x86 microcode can be handled correctly
1221
1222 We expect to see the following in the image, in order:
1223 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1224 place
1225 u-boot.dtb with the microcode removed
1226 the microcode
1227 """
Simon Glass511f6582018-10-01 12:22:30 -06001228 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass3d274232017-11-12 21:52:27 -07001229 U_BOOT_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06001230 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1231 b' somewhere in here', first)
Simon Glass72232452016-11-25 20:15:53 -07001232
Simon Glassbac25c82017-05-27 07:38:26 -06001233 def _RunPackUbootSingleMicrocode(self):
Simon Glass72232452016-11-25 20:15:53 -07001234 """Test that x86 microcode can be handled correctly
1235
1236 We expect to see the following in the image, in order:
1237 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1238 place
1239 u-boot.dtb with the microcode
1240 an empty microcode region
1241 """
1242 # We need the libfdt library to run this test since only that allows
1243 # finding the offset of a property. This is required by
1244 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass511f6582018-10-01 12:22:30 -06001245 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glass72232452016-11-25 20:15:53 -07001246
1247 second = data[len(U_BOOT_NODTB_DATA):]
1248
1249 fdt_len = self.GetFdtLen(second)
1250 third = second[fdt_len:]
1251 second = second[:fdt_len]
1252
Simon Glassbac25c82017-05-27 07:38:26 -06001253 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1254 self.assertIn(ucode_data, second)
1255 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glass72232452016-11-25 20:15:53 -07001256
Simon Glassbac25c82017-05-27 07:38:26 -06001257 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001258 # expected offset and size
Simon Glassbac25c82017-05-27 07:38:26 -06001259 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1260 len(ucode_data))
1261 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glass303f62f2019-05-17 22:00:46 -06001262 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1263 b' somewhere in here', first)
Simon Glass996021e2016-11-25 20:15:54 -07001264
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001265 def testPackUbootSingleMicrocode(self):
1266 """Test that x86 microcode can be handled correctly with fdt_normal.
1267 """
Simon Glassbac25c82017-05-27 07:38:26 -06001268 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001269
Simon Glass996021e2016-11-25 20:15:54 -07001270 def testUBootImg(self):
1271 """Test that u-boot.img can be put in a file"""
Simon Glass511f6582018-10-01 12:22:30 -06001272 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glass996021e2016-11-25 20:15:54 -07001273 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001274
1275 def testNoMicrocode(self):
1276 """Test that a missing microcode region is detected"""
1277 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001278 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001279 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1280 "node found in ", str(e.exception))
1281
1282 def testMicrocodeWithoutNode(self):
1283 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1284 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001285 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001286 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1287 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1288
1289 def testMicrocodeWithoutNode2(self):
1290 """Test that a missing u-boot-ucode node is detected"""
1291 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001292 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001293 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1294 "microcode region u-boot-ucode", str(e.exception))
1295
1296 def testMicrocodeWithoutPtrInElf(self):
1297 """Test that a U-Boot binary without the microcode symbol is detected"""
1298 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001299 try:
Simon Glassfaaaa162019-08-24 07:22:55 -06001300 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001301 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001302
1303 with self.assertRaises(ValueError) as e:
Simon Glassbac25c82017-05-27 07:38:26 -06001304 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001305 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1306 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1307
1308 finally:
1309 # Put the original file back
Simon Glass4affd4b2019-08-24 07:22:54 -06001310 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001311 tools.read_file(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001312
1313 def testMicrocodeNotInImage(self):
1314 """Test that microcode must be placed within the image"""
1315 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001316 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001317 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1318 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glassad5a7712018-06-01 09:38:14 -06001319 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001320
1321 def testWithoutMicrocode(self):
1322 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glassfaaaa162019-08-24 07:22:55 -06001323 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001324 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass511f6582018-10-01 12:22:30 -06001325 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001326
1327 # Now check the device tree has no microcode
1328 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1329 second = data[len(U_BOOT_NODTB_DATA):]
1330
1331 fdt_len = self.GetFdtLen(second)
1332 self.assertEqual(dtb, second[:fdt_len])
1333
1334 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1335 third = data[used_len:]
Simon Glass80025522022-01-29 14:14:04 -07001336 self.assertEqual(tools.get_bytes(0, 0x200 - used_len), third)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001337
1338 def testUnknownPosSize(self):
1339 """Test that microcode must be placed within the image"""
1340 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001341 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glasse8561af2018-08-01 15:22:37 -06001342 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001343 "entry 'invalid-entry'", str(e.exception))
Simon Glassb4176d42016-11-25 20:15:56 -07001344
1345 def testPackFsp(self):
1346 """Test that an image with a FSP binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001347 data = self._DoReadFile('042_intel_fsp.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001348 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1349
1350 def testPackCmc(self):
Bin Mengd7bcdf52017-08-15 22:41:54 -07001351 """Test that an image with a CMC binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001352 data = self._DoReadFile('043_intel_cmc.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001353 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Mengd7bcdf52017-08-15 22:41:54 -07001354
1355 def testPackVbt(self):
1356 """Test that an image with a VBT binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001357 data = self._DoReadFile('046_intel_vbt.dts')
Bin Mengd7bcdf52017-08-15 22:41:54 -07001358 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glassac599912017-11-12 21:52:22 -07001359
Simon Glass7f94e832017-11-12 21:52:25 -07001360 def testSplBssPad(self):
1361 """Test that we can pad SPL's BSS with zeros"""
Simon Glass3d274232017-11-12 21:52:27 -07001362 # ELF file with a '__bss_size' symbol
Simon Glass7057d022018-10-01 21:12:47 -06001363 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001364 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07001365 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glassac0d4952019-05-14 15:53:47 -06001366 data)
Simon Glass7f94e832017-11-12 21:52:25 -07001367
Simon Glass04cda032018-10-01 21:12:42 -06001368 def testSplBssPadMissing(self):
1369 """Test that a missing symbol is detected"""
Simon Glass7057d022018-10-01 21:12:47 -06001370 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass24ad3652017-11-13 18:54:54 -07001371 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001372 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass24ad3652017-11-13 18:54:54 -07001373 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1374 str(e.exception))
1375
Simon Glasse83679d2017-11-12 21:52:26 -07001376 def testPackStart16Spl(self):
Simon Glassed40e962018-09-14 04:57:10 -06001377 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001378 data = self._DoReadFile('048_x86_start16_spl.dts')
Simon Glasse83679d2017-11-12 21:52:26 -07001379 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1380
Simon Glass6ba679c2018-07-06 10:27:17 -06001381 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1382 """Helper function for microcode tests
Simon Glass3d274232017-11-12 21:52:27 -07001383
1384 We expect to see the following in the image, in order:
1385 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1386 correct place
1387 u-boot.dtb with the microcode removed
1388 the microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001389
1390 Args:
1391 dts: Device tree file to use for test
1392 ucode_second: True if the microsecond entry is second instead of
1393 third
Simon Glass3d274232017-11-12 21:52:27 -07001394 """
Simon Glass7057d022018-10-01 21:12:47 -06001395 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass6ba679c2018-07-06 10:27:17 -06001396 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1397 ucode_second=ucode_second)
Simon Glass303f62f2019-05-17 22:00:46 -06001398 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1399 b'ter somewhere in here', first)
Simon Glass3d274232017-11-12 21:52:27 -07001400
Simon Glass6ba679c2018-07-06 10:27:17 -06001401 def testPackUbootSplMicrocode(self):
1402 """Test that x86 microcode can be handled correctly in SPL"""
Simon Glass511f6582018-10-01 12:22:30 -06001403 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass6ba679c2018-07-06 10:27:17 -06001404
1405 def testPackUbootSplMicrocodeReorder(self):
1406 """Test that order doesn't matter for microcode entries
1407
1408 This is the same as testPackUbootSplMicrocode but when we process the
1409 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1410 entry, so we reply on binman to try later.
1411 """
Simon Glass511f6582018-10-01 12:22:30 -06001412 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass6ba679c2018-07-06 10:27:17 -06001413 ucode_second=True)
1414
Simon Glassa409c932017-11-12 21:52:28 -07001415 def testPackMrc(self):
1416 """Test that an image with an MRC binary can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001417 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassa409c932017-11-12 21:52:28 -07001418 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1419
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001420 def testSplDtb(self):
1421 """Test that an image with spl/u-boot-spl.dtb can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001422 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001423 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1424
Simon Glass0a6da312017-11-13 18:54:56 -07001425 def testSplNoDtb(self):
1426 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12001427 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001428 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass0a6da312017-11-13 18:54:56 -07001429 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1430
Simon Glass7098b7f2021-03-21 18:24:30 +13001431 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
1432 use_expanded=False):
Simon Glass31e04cb2021-03-18 20:24:56 +13001433 """Check the image contains the expected symbol values
1434
1435 Args:
1436 dts: Device tree file to use for test
1437 base_data: Data before and after 'u-boot' section
1438 u_boot_offset: Offset of 'u-boot' section in image
Simon Glass7098b7f2021-03-21 18:24:30 +13001439 entry_args: Dict of entry args to supply to binman
1440 key: arg name
1441 value: value of that arg
1442 use_expanded: True to use expanded entries where available, e.g.
1443 'u-boot-expanded' instead of 'u-boot'
Simon Glass31e04cb2021-03-18 20:24:56 +13001444 """
Simon Glass5d0c0262019-08-24 07:22:56 -06001445 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass4ca8e042017-11-13 18:55:01 -07001446 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1447 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001448 self.assertEqual(syms['_binman_sym_magic'].address, addr)
Simon Glass31e04cb2021-03-18 20:24:56 +13001449 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001450 addr + 4)
Simon Glass4ca8e042017-11-13 18:55:01 -07001451
Simon Glass7057d022018-10-01 21:12:47 -06001452 self._SetupSplElf('u_boot_binman_syms')
Simon Glass7098b7f2021-03-21 18:24:30 +13001453 data = self._DoReadFileDtb(dts, entry_args=entry_args,
1454 use_expanded=use_expanded)[0]
Simon Glass31e04cb2021-03-18 20:24:56 +13001455 # The image should contain the symbols from u_boot_binman_syms.c
1456 # Note that image_pos is adjusted by the base address of the image,
1457 # which is 0x10 in our test image
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001458 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE,
1459 0x00, u_boot_offset + len(U_BOOT_DATA),
Simon Glass31e04cb2021-03-18 20:24:56 +13001460 0x10 + u_boot_offset, 0x04)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001461 expected = (sym_values + base_data[24:] +
Simon Glass80025522022-01-29 14:14:04 -07001462 tools.get_bytes(0xff, 1) + U_BOOT_DATA + sym_values +
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001463 base_data[24:])
Simon Glass4ca8e042017-11-13 18:55:01 -07001464 self.assertEqual(expected, data)
1465
Simon Glass31e04cb2021-03-18 20:24:56 +13001466 def testSymbols(self):
1467 """Test binman can assign symbols embedded in U-Boot"""
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001468 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glass31e04cb2021-03-18 20:24:56 +13001469
1470 def testSymbolsNoDtb(self):
1471 """Test binman can assign symbols embedded in U-Boot SPL"""
Simon Glass3bbc9932021-03-21 18:24:29 +13001472 self.checkSymbols('196_symbols_nodtb.dts',
Simon Glass31e04cb2021-03-18 20:24:56 +13001473 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1474 0x38)
1475
Simon Glasse76a3e62018-06-01 09:38:11 -06001476 def testPackUnitAddress(self):
1477 """Test that we support multiple binaries with the same name"""
Simon Glass511f6582018-10-01 12:22:30 -06001478 data = self._DoReadFile('054_unit_address.dts')
Simon Glasse76a3e62018-06-01 09:38:11 -06001479 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1480
Simon Glassa91e1152018-06-01 09:38:16 -06001481 def testSections(self):
1482 """Basic test of sections"""
Simon Glass511f6582018-10-01 12:22:30 -06001483 data = self._DoReadFile('055_sections.dts')
Simon Glass80025522022-01-29 14:14:04 -07001484 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1485 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
1486 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glassa91e1152018-06-01 09:38:16 -06001487 self.assertEqual(expected, data)
Simon Glassac599912017-11-12 21:52:22 -07001488
Simon Glass30732662018-06-01 09:38:20 -06001489 def testMap(self):
1490 """Tests outputting a map of the images"""
Simon Glass511f6582018-10-01 12:22:30 -06001491 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001492 self.assertEqual('''ImagePos Offset Size Name
149300000000 00000000 00000028 main-section
149400000000 00000000 00000010 section@0
149500000000 00000000 00000004 u-boot
149600000010 00000010 00000010 section@1
149700000010 00000000 00000004 u-boot
149800000020 00000020 00000004 section@2
149900000020 00000000 00000004 u-boot
Simon Glass30732662018-06-01 09:38:20 -06001500''', map_data)
1501
Simon Glass3b78d532018-06-01 09:38:21 -06001502 def testNamePrefix(self):
1503 """Tests that name prefixes are used"""
Simon Glass511f6582018-10-01 12:22:30 -06001504 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001505 self.assertEqual('''ImagePos Offset Size Name
150600000000 00000000 00000028 main-section
150700000000 00000000 00000010 section@0
150800000000 00000000 00000004 ro-u-boot
150900000010 00000010 00000010 section@1
151000000010 00000000 00000004 rw-u-boot
Simon Glass3b78d532018-06-01 09:38:21 -06001511''', map_data)
1512
Simon Glass6ba679c2018-07-06 10:27:17 -06001513 def testUnknownContents(self):
1514 """Test that obtaining the contents works as expected"""
1515 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001516 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass39dd2152019-07-08 14:25:47 -06001517 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glassc585dd42020-04-17 18:09:03 -06001518 "processing of contents: remaining ["
1519 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass6ba679c2018-07-06 10:27:17 -06001520
Simon Glass2e1169f2018-07-06 10:27:19 -06001521 def testBadChangeSize(self):
1522 """Test that trying to change the size of an entry fails"""
Simon Glasse61b6f62019-07-08 14:25:37 -06001523 try:
1524 state.SetAllowEntryExpansion(False)
1525 with self.assertRaises(ValueError) as e:
1526 self._DoReadFile('059_change_size.dts', True)
Simon Glass8c702fb2019-07-20 12:23:57 -06001527 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glasse61b6f62019-07-08 14:25:37 -06001528 str(e.exception))
1529 finally:
1530 state.SetAllowEntryExpansion(True)
Simon Glass2e1169f2018-07-06 10:27:19 -06001531
Simon Glassa87014e2018-07-06 10:27:42 -06001532 def testUpdateFdt(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001533 """Test that we can update the device tree with offset/size info"""
Simon Glass511f6582018-10-01 12:22:30 -06001534 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glassa87014e2018-07-06 10:27:42 -06001535 update_dtb=True)
Simon Glass5463a6a2018-07-17 13:25:52 -06001536 dtb = fdt.Fdt(out_dtb_fname)
1537 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06001538 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glassa87014e2018-07-06 10:27:42 -06001539 self.assertEqual({
Simon Glass9dcc8612018-08-01 15:22:42 -06001540 'image-pos': 0,
Simon Glass3a9a2b82018-07-17 13:25:28 -06001541 'offset': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001542 '_testing:offset': 32,
Simon Glass8c702fb2019-07-20 12:23:57 -06001543 '_testing:size': 2,
Simon Glass9dcc8612018-08-01 15:22:42 -06001544 '_testing:image-pos': 32,
Simon Glasse8561af2018-08-01 15:22:37 -06001545 'section@0/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001546 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001547 'section@0/u-boot:image-pos': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001548 'section@0:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001549 'section@0:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001550 'section@0:image-pos': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001551
Simon Glasse8561af2018-08-01 15:22:37 -06001552 'section@1/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001553 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001554 'section@1/u-boot:image-pos': 16,
Simon Glasse8561af2018-08-01 15:22:37 -06001555 'section@1:offset': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001556 'section@1:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001557 'section@1:image-pos': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001558 'size': 40
1559 }, props)
1560
1561 def testUpdateFdtBad(self):
1562 """Test that we detect when ProcessFdt never completes"""
1563 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001564 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glassa87014e2018-07-06 10:27:42 -06001565 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glassc585dd42020-04-17 18:09:03 -06001566 '[<binman.etype._testing.Entry__testing',
1567 str(e.exception))
Simon Glass2e1169f2018-07-06 10:27:19 -06001568
Simon Glass91710b32018-07-17 13:25:32 -06001569 def testEntryArgs(self):
1570 """Test passing arguments to entries from the command line"""
1571 entry_args = {
1572 'test-str-arg': 'test1',
1573 'test-int-arg': '456',
1574 }
Simon Glass511f6582018-10-01 12:22:30 -06001575 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001576 self.assertIn('image', control.images)
1577 entry = control.images['image'].GetEntries()['_testing']
1578 self.assertEqual('test0', entry.test_str_fdt)
1579 self.assertEqual('test1', entry.test_str_arg)
1580 self.assertEqual(123, entry.test_int_fdt)
1581 self.assertEqual(456, entry.test_int_arg)
1582
1583 def testEntryArgsMissing(self):
1584 """Test missing arguments and properties"""
1585 entry_args = {
1586 'test-int-arg': '456',
1587 }
Simon Glass511f6582018-10-01 12:22:30 -06001588 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001589 entry = control.images['image'].GetEntries()['_testing']
1590 self.assertEqual('test0', entry.test_str_fdt)
1591 self.assertEqual(None, entry.test_str_arg)
1592 self.assertEqual(None, entry.test_int_fdt)
1593 self.assertEqual(456, entry.test_int_arg)
1594
1595 def testEntryArgsRequired(self):
1596 """Test missing arguments and properties"""
1597 entry_args = {
1598 'test-int-arg': '456',
1599 }
1600 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001601 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass21db0ff2020-09-01 05:13:54 -06001602 self.assertIn("Node '/binman/_testing': "
1603 'Missing required properties/entry args: test-str-arg, '
1604 'test-int-fdt, test-int-arg',
Simon Glass91710b32018-07-17 13:25:32 -06001605 str(e.exception))
1606
1607 def testEntryArgsInvalidFormat(self):
1608 """Test that an invalid entry-argument format is detected"""
Simon Glassf46732a2019-07-08 14:25:29 -06001609 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1610 '-ano-value']
Simon Glass91710b32018-07-17 13:25:32 -06001611 with self.assertRaises(ValueError) as e:
1612 self._DoBinman(*args)
1613 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1614
1615 def testEntryArgsInvalidInteger(self):
1616 """Test that an invalid entry-argument integer is detected"""
1617 entry_args = {
1618 'test-int-arg': 'abc',
1619 }
1620 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001621 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001622 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1623 "'test-int-arg' (value 'abc') to integer",
1624 str(e.exception))
1625
1626 def testEntryArgsInvalidDatatype(self):
1627 """Test that an invalid entry-argument datatype is detected
1628
1629 This test could be written in entry_test.py except that it needs
1630 access to control.entry_args, which seems more than that module should
1631 be able to see.
1632 """
1633 entry_args = {
1634 'test-bad-datatype-arg': '12',
1635 }
1636 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001637 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass91710b32018-07-17 13:25:32 -06001638 entry_args=entry_args)
1639 self.assertIn('GetArg() internal error: Unknown data type ',
1640 str(e.exception))
1641
Simon Glass2ca52032018-07-17 13:25:33 -06001642 def testText(self):
1643 """Test for a text entry type"""
1644 entry_args = {
1645 'test-id': TEXT_DATA,
1646 'test-id2': TEXT_DATA2,
1647 'test-id3': TEXT_DATA3,
1648 }
Simon Glass511f6582018-10-01 12:22:30 -06001649 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glass2ca52032018-07-17 13:25:33 -06001650 entry_args=entry_args)
Simon Glass80025522022-01-29 14:14:04 -07001651 expected = (tools.to_bytes(TEXT_DATA) +
1652 tools.get_bytes(0, 8 - len(TEXT_DATA)) +
1653 tools.to_bytes(TEXT_DATA2) + tools.to_bytes(TEXT_DATA3) +
Simon Glass47f6a622019-07-08 13:18:40 -06001654 b'some text' + b'more text')
Simon Glass2ca52032018-07-17 13:25:33 -06001655 self.assertEqual(expected, data)
1656
Simon Glass969616c2018-07-17 13:25:36 -06001657 def testEntryDocs(self):
1658 """Test for creation of entry documentation"""
1659 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001660 control.WriteEntryDocs(control.GetEntryModules())
Simon Glass969616c2018-07-17 13:25:36 -06001661 self.assertTrue(len(stdout.getvalue()) > 0)
1662
1663 def testEntryDocsMissing(self):
1664 """Test handling of missing entry documentation"""
1665 with self.assertRaises(ValueError) as e:
1666 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001667 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glass969616c2018-07-17 13:25:36 -06001668 self.assertIn('Documentation is missing for modules: u_boot',
1669 str(e.exception))
1670
Simon Glass704784b2018-07-17 13:25:38 -06001671 def testFmap(self):
1672 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06001673 data = self._DoReadFile('067_fmap.dts')
Simon Glass704784b2018-07-17 13:25:38 -06001674 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass80025522022-01-29 14:14:04 -07001675 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1676 U_BOOT_DATA + tools.get_bytes(ord('a'), 12))
Simon Glass704784b2018-07-17 13:25:38 -06001677 self.assertEqual(expected, data[:32])
Simon Glass303f62f2019-05-17 22:00:46 -06001678 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass704784b2018-07-17 13:25:38 -06001679 self.assertEqual(1, fhdr.ver_major)
1680 self.assertEqual(0, fhdr.ver_minor)
1681 self.assertEqual(0, fhdr.base)
Simon Glassb1d414c2021-04-03 11:05:10 +13001682 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 5
Simon Glass82059c22021-04-03 11:05:09 +13001683 self.assertEqual(16 + 16 + expect_size, fhdr.image_size)
Simon Glass303f62f2019-05-17 22:00:46 -06001684 self.assertEqual(b'FMAP', fhdr.name)
Simon Glassb1d414c2021-04-03 11:05:10 +13001685 self.assertEqual(5, fhdr.nareas)
Simon Glass82059c22021-04-03 11:05:09 +13001686 fiter = iter(fentries)
Simon Glass704784b2018-07-17 13:25:38 -06001687
Simon Glass82059c22021-04-03 11:05:09 +13001688 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001689 self.assertEqual(b'SECTION0', fentry.name)
1690 self.assertEqual(0, fentry.offset)
1691 self.assertEqual(16, fentry.size)
1692 self.assertEqual(0, fentry.flags)
1693
1694 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001695 self.assertEqual(b'RO_U_BOOT', fentry.name)
1696 self.assertEqual(0, fentry.offset)
1697 self.assertEqual(4, fentry.size)
1698 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001699
Simon Glass82059c22021-04-03 11:05:09 +13001700 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001701 self.assertEqual(b'SECTION1', fentry.name)
1702 self.assertEqual(16, fentry.offset)
1703 self.assertEqual(16, fentry.size)
1704 self.assertEqual(0, fentry.flags)
1705
1706 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001707 self.assertEqual(b'RW_U_BOOT', fentry.name)
1708 self.assertEqual(16, fentry.offset)
1709 self.assertEqual(4, fentry.size)
1710 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001711
Simon Glass82059c22021-04-03 11:05:09 +13001712 fentry = next(fiter)
1713 self.assertEqual(b'FMAP', fentry.name)
1714 self.assertEqual(32, fentry.offset)
1715 self.assertEqual(expect_size, fentry.size)
1716 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001717
Simon Glassdb168d42018-07-17 13:25:39 -06001718 def testBlobNamedByArg(self):
1719 """Test we can add a blob with the filename coming from an entry arg"""
1720 entry_args = {
1721 'cros-ec-rw-path': 'ecrw.bin',
1722 }
Simon Glass21db0ff2020-09-01 05:13:54 -06001723 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassdb168d42018-07-17 13:25:39 -06001724
Simon Glass53f53992018-07-17 13:25:40 -06001725 def testFill(self):
1726 """Test for an fill entry type"""
Simon Glass511f6582018-10-01 12:22:30 -06001727 data = self._DoReadFile('069_fill.dts')
Simon Glass80025522022-01-29 14:14:04 -07001728 expected = tools.get_bytes(0xff, 8) + tools.get_bytes(0, 8)
Simon Glass53f53992018-07-17 13:25:40 -06001729 self.assertEqual(expected, data)
1730
1731 def testFillNoSize(self):
1732 """Test for an fill entry type with no size"""
1733 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001734 self._DoReadFile('070_fill_no_size.dts')
Simon Glass0cf5bce2022-08-13 11:40:44 -06001735 self.assertIn("'fill' entry is missing properties: size",
Simon Glass53f53992018-07-17 13:25:40 -06001736 str(e.exception))
1737
Simon Glassc1ae83c2018-07-17 13:25:44 -06001738 def _HandleGbbCommand(self, pipe_list):
1739 """Fake calls to the futility utility"""
1740 if pipe_list[0][0] == 'futility':
1741 fname = pipe_list[0][-1]
1742 # Append our GBB data to the file, which will happen every time the
1743 # futility command is called.
Simon Glass33486662019-05-14 15:53:42 -06001744 with open(fname, 'ab') as fd:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001745 fd.write(GBB_DATA)
1746 return command.CommandResult()
1747
1748 def testGbb(self):
1749 """Test for the Chromium OS Google Binary Block"""
1750 command.test_result = self._HandleGbbCommand
1751 entry_args = {
1752 'keydir': 'devkeys',
1753 'bmpblk': 'bmpblk.bin',
1754 }
Simon Glass511f6582018-10-01 12:22:30 -06001755 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glassc1ae83c2018-07-17 13:25:44 -06001756
1757 # Since futility
Simon Glass80025522022-01-29 14:14:04 -07001758 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
1759 tools.get_bytes(0, 0x2180 - 16))
Simon Glassc1ae83c2018-07-17 13:25:44 -06001760 self.assertEqual(expected, data)
1761
1762 def testGbbTooSmall(self):
1763 """Test for the Chromium OS Google Binary Block being large enough"""
1764 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001765 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001766 self.assertIn("Node '/binman/gbb': GBB is too small",
1767 str(e.exception))
1768
1769 def testGbbNoSize(self):
1770 """Test for the Chromium OS Google Binary Block having a size"""
1771 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001772 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001773 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1774 str(e.exception))
1775
Simon Glass66152ce2022-01-09 20:14:09 -07001776 def testGbbMissing(self):
1777 """Test that binman still produces an image if futility is missing"""
1778 entry_args = {
1779 'keydir': 'devkeys',
1780 }
1781 with test_util.capture_sys_output() as (_, stderr):
1782 self._DoTestFile('071_gbb.dts', force_missing_bintools='futility',
1783 entry_args=entry_args)
1784 err = stderr.getvalue()
1785 self.assertRegex(err,
1786 "Image 'main-section'.*missing bintools.*: futility")
1787
Simon Glass5c350162018-07-17 13:25:47 -06001788 def _HandleVblockCommand(self, pipe_list):
Simon Glass220c6222021-01-06 21:35:17 -07001789 """Fake calls to the futility utility
1790
1791 The expected pipe is:
1792
1793 [('futility', 'vbutil_firmware', '--vblock',
1794 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1795 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1796 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1797 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1798
1799 This writes to the output file (here, 'vblock.vblock'). If
1800 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1801 of the input data (here, 'input.vblock').
1802 """
Simon Glass5c350162018-07-17 13:25:47 -06001803 if pipe_list[0][0] == 'futility':
1804 fname = pipe_list[0][3]
Simon Glass639505b2018-09-14 04:57:11 -06001805 with open(fname, 'wb') as fd:
Simon Glass220c6222021-01-06 21:35:17 -07001806 if self._hash_data:
1807 infile = pipe_list[0][11]
1808 m = hashlib.sha256()
Simon Glass80025522022-01-29 14:14:04 -07001809 data = tools.read_file(infile)
Simon Glass220c6222021-01-06 21:35:17 -07001810 m.update(data)
1811 fd.write(m.digest())
1812 else:
1813 fd.write(VBLOCK_DATA)
1814
Simon Glass5c350162018-07-17 13:25:47 -06001815 return command.CommandResult()
1816
1817 def testVblock(self):
1818 """Test for the Chromium OS Verified Boot Block"""
Simon Glass220c6222021-01-06 21:35:17 -07001819 self._hash_data = False
Simon Glass5c350162018-07-17 13:25:47 -06001820 command.test_result = self._HandleVblockCommand
1821 entry_args = {
1822 'keydir': 'devkeys',
1823 }
Simon Glass511f6582018-10-01 12:22:30 -06001824 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass5c350162018-07-17 13:25:47 -06001825 entry_args=entry_args)
1826 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1827 self.assertEqual(expected, data)
1828
1829 def testVblockNoContent(self):
1830 """Test we detect a vblock which has no content to sign"""
1831 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001832 self._DoReadFile('075_vblock_no_content.dts')
Simon Glasse1915782021-03-21 18:24:31 +13001833 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
Simon Glass5c350162018-07-17 13:25:47 -06001834 'property', str(e.exception))
1835
1836 def testVblockBadPhandle(self):
1837 """Test that we detect a vblock with an invalid phandle in contents"""
1838 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001839 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001840 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1841 '1000', str(e.exception))
1842
1843 def testVblockBadEntry(self):
1844 """Test that we detect an entry that points to a non-entry"""
1845 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001846 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001847 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1848 "'other'", str(e.exception))
1849
Simon Glass220c6222021-01-06 21:35:17 -07001850 def testVblockContent(self):
1851 """Test that the vblock signs the right data"""
1852 self._hash_data = True
1853 command.test_result = self._HandleVblockCommand
1854 entry_args = {
1855 'keydir': 'devkeys',
1856 }
1857 data = self._DoReadFileDtb(
1858 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1859 entry_args=entry_args)[0]
1860 hashlen = 32 # SHA256 hash is 32 bytes
1861 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1862 hashval = data[-hashlen:]
1863 dtb = data[len(U_BOOT_DATA):-hashlen]
1864
1865 expected_data = U_BOOT_DATA + dtb
1866
1867 # The hashval should be a hash of the dtb
1868 m = hashlib.sha256()
1869 m.update(expected_data)
1870 expected_hashval = m.digest()
1871 self.assertEqual(expected_hashval, hashval)
1872
Simon Glass66152ce2022-01-09 20:14:09 -07001873 def testVblockMissing(self):
1874 """Test that binman still produces an image if futility is missing"""
1875 entry_args = {
1876 'keydir': 'devkeys',
1877 }
1878 with test_util.capture_sys_output() as (_, stderr):
1879 self._DoTestFile('074_vblock.dts',
1880 force_missing_bintools='futility',
1881 entry_args=entry_args)
1882 err = stderr.getvalue()
1883 self.assertRegex(err,
1884 "Image 'main-section'.*missing bintools.*: futility")
1885
Simon Glass8425a1f2018-07-17 13:25:48 -06001886 def testTpl(self):
Simon Glass3eb5b202019-08-24 07:23:00 -06001887 """Test that an image with TPL and its device tree can be created"""
Simon Glass8425a1f2018-07-17 13:25:48 -06001888 # ELF file with a '__bss_size' symbol
Simon Glass3eb5b202019-08-24 07:23:00 -06001889 self._SetupTplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001890 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glass8425a1f2018-07-17 13:25:48 -06001891 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1892
Simon Glass24b97442018-07-17 13:25:51 -06001893 def testUsesPos(self):
1894 """Test that the 'pos' property cannot be used anymore"""
1895 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001896 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass24b97442018-07-17 13:25:51 -06001897 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1898 "'pos'", str(e.exception))
1899
Simon Glass274bf092018-09-14 04:57:08 -06001900 def testFillZero(self):
1901 """Test for an fill entry type with a size of 0"""
Simon Glass511f6582018-10-01 12:22:30 -06001902 data = self._DoReadFile('080_fill_empty.dts')
Simon Glass80025522022-01-29 14:14:04 -07001903 self.assertEqual(tools.get_bytes(0, 16), data)
Simon Glass274bf092018-09-14 04:57:08 -06001904
Simon Glass267de432018-09-14 04:57:09 -06001905 def testTextMissing(self):
1906 """Test for a text entry type where there is no text"""
1907 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001908 self._DoReadFileDtb('066_text.dts',)
Simon Glass267de432018-09-14 04:57:09 -06001909 self.assertIn("Node '/binman/text': No value provided for text label "
1910 "'test-id'", str(e.exception))
1911
Simon Glassed40e962018-09-14 04:57:10 -06001912 def testPackStart16Tpl(self):
1913 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001914 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glassed40e962018-09-14 04:57:10 -06001915 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1916
Simon Glass3b376c32018-09-14 04:57:12 -06001917 def testSelectImage(self):
1918 """Test that we can select which images to build"""
Simon Glassb4595d82019-04-25 21:58:34 -06001919 expected = 'Skipping images: image1'
1920
1921 # We should only get the expected message in verbose mode
Simon Glass8a50b4a2019-07-08 13:18:48 -06001922 for verbosity in (0, 2):
Simon Glassb4595d82019-04-25 21:58:34 -06001923 with test_util.capture_sys_output() as (stdout, stderr):
1924 retcode = self._DoTestFile('006_dual_image.dts',
1925 verbosity=verbosity,
1926 images=['image2'])
1927 self.assertEqual(0, retcode)
1928 if verbosity:
1929 self.assertIn(expected, stdout.getvalue())
1930 else:
1931 self.assertNotIn(expected, stdout.getvalue())
Simon Glass3b376c32018-09-14 04:57:12 -06001932
Simon Glass80025522022-01-29 14:14:04 -07001933 self.assertFalse(os.path.exists(tools.get_output_filename('image1.bin')))
1934 self.assertTrue(os.path.exists(tools.get_output_filename('image2.bin')))
Simon Glassb3d6fc72019-07-20 12:24:10 -06001935 self._CleanupOutputDir()
Simon Glass3b376c32018-09-14 04:57:12 -06001936
Simon Glasse219aa42018-09-14 04:57:24 -06001937 def testUpdateFdtAll(self):
1938 """Test that all device trees are updated with offset/size info"""
Simon Glass5b4bce32019-07-08 14:25:26 -06001939 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glasse219aa42018-09-14 04:57:24 -06001940
1941 base_expected = {
Simon Glasse219aa42018-09-14 04:57:24 -06001942 'offset': 0,
Simon Glass56d05412022-02-28 07:16:54 -07001943 'image-pos': 0,
1944 'size': 2320,
Simon Glasse219aa42018-09-14 04:57:24 -06001945 'section:offset': 0,
Simon Glass56d05412022-02-28 07:16:54 -07001946 'section:image-pos': 0,
1947 'section:size': 565,
1948 'section/u-boot-dtb:offset': 0,
1949 'section/u-boot-dtb:image-pos': 0,
1950 'section/u-boot-dtb:size': 565,
1951 'u-boot-spl-dtb:offset': 565,
1952 'u-boot-spl-dtb:image-pos': 565,
1953 'u-boot-spl-dtb:size': 585,
1954 'u-boot-tpl-dtb:offset': 1150,
1955 'u-boot-tpl-dtb:image-pos': 1150,
1956 'u-boot-tpl-dtb:size': 585,
1957 'u-boot-vpl-dtb:image-pos': 1735,
1958 'u-boot-vpl-dtb:offset': 1735,
1959 'u-boot-vpl-dtb:size': 585,
Simon Glasse219aa42018-09-14 04:57:24 -06001960 }
1961
1962 # We expect three device-tree files in the output, one after the other.
1963 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1964 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1965 # main U-Boot tree. All three should have the same postions and offset.
1966 start = 0
Simon Glass56d05412022-02-28 07:16:54 -07001967 self.maxDiff = None
1968 for item in ['', 'spl', 'tpl', 'vpl']:
Simon Glasse219aa42018-09-14 04:57:24 -06001969 dtb = fdt.Fdt.FromData(data[start:])
1970 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06001971 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
Simon Glass56d05412022-02-28 07:16:54 -07001972 ['spl', 'tpl', 'vpl'])
Simon Glasse219aa42018-09-14 04:57:24 -06001973 expected = dict(base_expected)
1974 if item:
1975 expected[item] = 0
1976 self.assertEqual(expected, props)
1977 start += dtb._fdt_obj.totalsize()
1978
1979 def testUpdateFdtOutput(self):
1980 """Test that output DTB files are updated"""
1981 try:
Simon Glass511f6582018-10-01 12:22:30 -06001982 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glasse219aa42018-09-14 04:57:24 -06001983 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1984
1985 # Unfortunately, compiling a source file always results in a file
1986 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass511f6582018-10-01 12:22:30 -06001987 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glasse219aa42018-09-14 04:57:24 -06001988 # binman as a file called u-boot.dtb. To fix this, copy the file
1989 # over to the expected place.
Simon Glasse219aa42018-09-14 04:57:24 -06001990 start = 0
1991 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
Simon Glass56d05412022-02-28 07:16:54 -07001992 'tpl/u-boot-tpl.dtb.out', 'vpl/u-boot-vpl.dtb.out']:
Simon Glasse219aa42018-09-14 04:57:24 -06001993 dtb = fdt.Fdt.FromData(data[start:])
1994 size = dtb._fdt_obj.totalsize()
Simon Glass80025522022-01-29 14:14:04 -07001995 pathname = tools.get_output_filename(os.path.split(fname)[1])
1996 outdata = tools.read_file(pathname)
Simon Glasse219aa42018-09-14 04:57:24 -06001997 name = os.path.split(fname)[0]
1998
1999 if name:
Simon Glass56d05412022-02-28 07:16:54 -07002000 orig_indata = self._GetDtbContentsForSpls(dtb_data, name)
Simon Glasse219aa42018-09-14 04:57:24 -06002001 else:
2002 orig_indata = dtb_data
2003 self.assertNotEqual(outdata, orig_indata,
2004 "Expected output file '%s' be updated" % pathname)
2005 self.assertEqual(outdata, data[start:start + size],
2006 "Expected output file '%s' to match output image" %
2007 pathname)
2008 start += size
2009 finally:
2010 self._ResetDtbs()
2011
Simon Glass7ba33592018-09-14 04:57:26 -06002012 def _decompress(self, data):
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02002013 bintool = self.comp_bintools['lz4']
2014 return bintool.decompress(data)
Simon Glass7ba33592018-09-14 04:57:26 -06002015
2016 def testCompress(self):
2017 """Test compression of blobs"""
Simon Glass1de34482019-07-08 13:18:53 -06002018 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06002019 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass7ba33592018-09-14 04:57:26 -06002020 use_real_dtb=True, update_dtb=True)
2021 dtb = fdt.Fdt(out_dtb_fname)
2022 dtb.Scan()
2023 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2024 orig = self._decompress(data)
2025 self.assertEquals(COMPRESS_DATA, orig)
Simon Glass789b34402020-10-26 17:40:15 -06002026
2027 # Do a sanity check on various fields
2028 image = control.images['image']
2029 entries = image.GetEntries()
2030 self.assertEqual(1, len(entries))
2031
2032 entry = entries['blob']
2033 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
2034 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
2035 orig = self._decompress(entry.data)
2036 self.assertEqual(orig, entry.uncomp_data)
2037
Simon Glass72eeff12020-10-26 17:40:16 -06002038 self.assertEqual(image.data, entry.data)
2039
Simon Glass7ba33592018-09-14 04:57:26 -06002040 expected = {
2041 'blob:uncomp-size': len(COMPRESS_DATA),
2042 'blob:size': len(data),
2043 'size': len(data),
2044 }
2045 self.assertEqual(expected, props)
2046
Simon Glassac6328c2018-09-14 04:57:28 -06002047 def testFiles(self):
2048 """Test bringing in multiple files"""
Simon Glass511f6582018-10-01 12:22:30 -06002049 data = self._DoReadFile('084_files.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002050 self.assertEqual(FILES_DATA, data)
2051
2052 def testFilesCompress(self):
2053 """Test bringing in multiple files and compressing them"""
Simon Glass1de34482019-07-08 13:18:53 -06002054 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06002055 data = self._DoReadFile('085_files_compress.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002056
2057 image = control.images['image']
2058 entries = image.GetEntries()
2059 files = entries['files']
Simon Glass39dd2152019-07-08 14:25:47 -06002060 entries = files._entries
Simon Glassac6328c2018-09-14 04:57:28 -06002061
Simon Glass303f62f2019-05-17 22:00:46 -06002062 orig = b''
Simon Glassac6328c2018-09-14 04:57:28 -06002063 for i in range(1, 3):
2064 key = '%d.dat' % i
2065 start = entries[key].image_pos
2066 len = entries[key].size
2067 chunk = data[start:start + len]
2068 orig += self._decompress(chunk)
2069
2070 self.assertEqual(FILES_DATA, orig)
2071
2072 def testFilesMissing(self):
2073 """Test missing files"""
2074 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002075 data = self._DoReadFile('086_files_none.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002076 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
2077 'no files', str(e.exception))
2078
2079 def testFilesNoPattern(self):
2080 """Test missing files"""
2081 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002082 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002083 self.assertIn("Node '/binman/files': Missing 'pattern' property",
2084 str(e.exception))
2085
Simon Glassdd156a42022-03-05 20:18:59 -07002086 def testExtendSize(self):
2087 """Test an extending entry"""
2088 data, _, map_data, _ = self._DoReadFileDtb('088_extend_size.dts',
Simon Glassfa79a812018-09-14 04:57:29 -06002089 map=True)
Simon Glass80025522022-01-29 14:14:04 -07002090 expect = (tools.get_bytes(ord('a'), 8) + U_BOOT_DATA +
2091 MRC_DATA + tools.get_bytes(ord('b'), 1) + U_BOOT_DATA +
2092 tools.get_bytes(ord('c'), 8) + U_BOOT_DATA +
2093 tools.get_bytes(ord('d'), 8))
Simon Glassfa79a812018-09-14 04:57:29 -06002094 self.assertEqual(expect, data)
2095 self.assertEqual('''ImagePos Offset Size Name
209600000000 00000000 00000028 main-section
209700000000 00000000 00000008 fill
209800000008 00000008 00000004 u-boot
20990000000c 0000000c 00000004 section
21000000000c 00000000 00000003 intel-mrc
210100000010 00000010 00000004 u-boot2
210200000014 00000014 0000000c section2
210300000014 00000000 00000008 fill
21040000001c 00000008 00000004 u-boot
210500000020 00000020 00000008 fill2
2106''', map_data)
2107
Simon Glassdd156a42022-03-05 20:18:59 -07002108 def testExtendSizeBad(self):
2109 """Test an extending entry which fails to provide contents"""
Simon Glasscd817d52018-09-14 04:57:36 -06002110 with test_util.capture_sys_output() as (stdout, stderr):
2111 with self.assertRaises(ValueError) as e:
Simon Glassdd156a42022-03-05 20:18:59 -07002112 self._DoReadFileDtb('089_extend_size_bad.dts', map=True)
Simon Glassfa79a812018-09-14 04:57:29 -06002113 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
2114 'expanding entry', str(e.exception))
2115
Simon Glassae7cf032018-09-14 04:57:31 -06002116 def testHash(self):
2117 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002118 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002119 use_real_dtb=True, update_dtb=True)
2120 dtb = fdt.Fdt(out_dtb_fname)
2121 dtb.Scan()
2122 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
2123 m = hashlib.sha256()
2124 m.update(U_BOOT_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002125 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002126
2127 def testHashNoAlgo(self):
2128 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002129 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glassae7cf032018-09-14 04:57:31 -06002130 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2131 'hash node', str(e.exception))
2132
2133 def testHashBadAlgo(self):
2134 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002135 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glass64af7c22022-02-08 10:59:44 -07002136 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm 'invalid'",
Simon Glassae7cf032018-09-14 04:57:31 -06002137 str(e.exception))
2138
2139 def testHashSection(self):
2140 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002141 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002142 use_real_dtb=True, update_dtb=True)
2143 dtb = fdt.Fdt(out_dtb_fname)
2144 dtb.Scan()
2145 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2146 m = hashlib.sha256()
2147 m.update(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07002148 m.update(tools.get_bytes(ord('a'), 16))
Simon Glass303f62f2019-05-17 22:00:46 -06002149 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002150
Simon Glass3fb4f422018-09-14 04:57:32 -06002151 def testPackUBootTplMicrocode(self):
2152 """Test that x86 microcode can be handled correctly in TPL
2153
2154 We expect to see the following in the image, in order:
2155 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2156 place
2157 u-boot-tpl.dtb with the microcode removed
2158 the microcode
2159 """
Simon Glass3eb5b202019-08-24 07:23:00 -06002160 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass511f6582018-10-01 12:22:30 -06002161 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glass3fb4f422018-09-14 04:57:32 -06002162 U_BOOT_TPL_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002163 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2164 b'ter somewhere in here', first)
Simon Glass3fb4f422018-09-14 04:57:32 -06002165
Simon Glassc64aea52018-09-14 04:57:34 -06002166 def testFmapX86(self):
2167 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002168 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassc64aea52018-09-14 04:57:34 -06002169 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass80025522022-01-29 14:14:04 -07002170 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('a'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002171 self.assertEqual(expected, data[:32])
2172 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2173
2174 self.assertEqual(0x100, fhdr.image_size)
2175
2176 self.assertEqual(0, fentries[0].offset)
2177 self.assertEqual(4, fentries[0].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002178 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002179
2180 self.assertEqual(4, fentries[1].offset)
2181 self.assertEqual(3, fentries[1].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002182 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002183
2184 self.assertEqual(32, fentries[2].offset)
2185 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2186 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002187 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002188
2189 def testFmapX86Section(self):
2190 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002191 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glass80025522022-01-29 14:14:04 -07002192 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('b'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002193 self.assertEqual(expected, data[:32])
2194 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2195
Simon Glassb1d414c2021-04-03 11:05:10 +13002196 self.assertEqual(0x180, fhdr.image_size)
2197 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
Simon Glass82059c22021-04-03 11:05:09 +13002198 fiter = iter(fentries)
Simon Glassc64aea52018-09-14 04:57:34 -06002199
Simon Glass82059c22021-04-03 11:05:09 +13002200 fentry = next(fiter)
2201 self.assertEqual(b'U_BOOT', fentry.name)
2202 self.assertEqual(0, fentry.offset)
2203 self.assertEqual(4, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002204
Simon Glass82059c22021-04-03 11:05:09 +13002205 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13002206 self.assertEqual(b'SECTION', fentry.name)
2207 self.assertEqual(4, fentry.offset)
2208 self.assertEqual(0x20 + expect_size, fentry.size)
2209
2210 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13002211 self.assertEqual(b'INTEL_MRC', fentry.name)
2212 self.assertEqual(4, fentry.offset)
2213 self.assertEqual(3, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002214
Simon Glass82059c22021-04-03 11:05:09 +13002215 fentry = next(fiter)
2216 self.assertEqual(b'FMAP', fentry.name)
2217 self.assertEqual(36, fentry.offset)
2218 self.assertEqual(expect_size, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002219
Simon Glassb1714232018-09-14 04:57:35 -06002220 def testElf(self):
2221 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002222 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002223 self._SetupTplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002224 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002225 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002226 data = self._DoReadFile('096_elf.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002227
Simon Glass0d673792019-07-08 13:18:25 -06002228 def testElfStrip(self):
Simon Glassb1714232018-09-14 04:57:35 -06002229 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002230 self._SetupSplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002231 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002232 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002233 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002234
Simon Glasscd817d52018-09-14 04:57:36 -06002235 def testPackOverlapMap(self):
2236 """Test that overlapping regions are detected"""
2237 with test_util.capture_sys_output() as (stdout, stderr):
2238 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002239 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glass80025522022-01-29 14:14:04 -07002240 map_fname = tools.get_output_filename('image.map')
Simon Glasscd817d52018-09-14 04:57:36 -06002241 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2242 stdout.getvalue())
2243
2244 # We should not get an inmage, but there should be a map file
Simon Glass80025522022-01-29 14:14:04 -07002245 self.assertFalse(os.path.exists(tools.get_output_filename('image.bin')))
Simon Glasscd817d52018-09-14 04:57:36 -06002246 self.assertTrue(os.path.exists(map_fname))
Simon Glass80025522022-01-29 14:14:04 -07002247 map_data = tools.read_file(map_fname, binary=False)
Simon Glasscd817d52018-09-14 04:57:36 -06002248 self.assertEqual('''ImagePos Offset Size Name
Simon Glassd99850b2020-10-26 17:40:24 -06002249<none> 00000000 00000008 main-section
Simon Glasscd817d52018-09-14 04:57:36 -06002250<none> 00000000 00000004 u-boot
2251<none> 00000003 00000004 u-boot-align
2252''', map_data)
2253
Simon Glass0d673792019-07-08 13:18:25 -06002254 def testPackRefCode(self):
Simon Glass41902e42018-10-01 12:22:31 -06002255 """Test that an image with an Intel Reference code binary works"""
2256 data = self._DoReadFile('100_intel_refcode.dts')
2257 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2258
Simon Glasseb023b32019-04-25 21:58:39 -06002259 def testSectionOffset(self):
2260 """Tests use of a section with an offset"""
2261 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2262 map=True)
2263 self.assertEqual('''ImagePos Offset Size Name
226400000000 00000000 00000038 main-section
226500000004 00000004 00000010 section@0
226600000004 00000000 00000004 u-boot
226700000018 00000018 00000010 section@1
226800000018 00000000 00000004 u-boot
22690000002c 0000002c 00000004 section@2
22700000002c 00000000 00000004 u-boot
2271''', map_data)
2272 self.assertEqual(data,
Simon Glass80025522022-01-29 14:14:04 -07002273 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2274 tools.get_bytes(0x21, 12) +
2275 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2276 tools.get_bytes(0x61, 12) +
2277 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2278 tools.get_bytes(0x26, 8))
Simon Glasseb023b32019-04-25 21:58:39 -06002279
Simon Glass1de34482019-07-08 13:18:53 -06002280 def testCbfsRaw(self):
2281 """Test base handling of a Coreboot Filesystem (CBFS)
2282
2283 The exact contents of the CBFS is verified by similar tests in
2284 cbfs_util_test.py. The tests here merely check that the files added to
2285 the CBFS can be found in the final image.
2286 """
2287 data = self._DoReadFile('102_cbfs_raw.dts')
2288 size = 0xb0
2289
2290 cbfs = cbfs_util.CbfsReader(data)
2291 self.assertEqual(size, cbfs.rom_size)
2292
2293 self.assertIn('u-boot-dtb', cbfs.files)
2294 cfile = cbfs.files['u-boot-dtb']
2295 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2296
2297 def testCbfsArch(self):
2298 """Test on non-x86 architecture"""
2299 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2300 size = 0x100
2301
2302 cbfs = cbfs_util.CbfsReader(data)
2303 self.assertEqual(size, cbfs.rom_size)
2304
2305 self.assertIn('u-boot-dtb', cbfs.files)
2306 cfile = cbfs.files['u-boot-dtb']
2307 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2308
2309 def testCbfsStage(self):
2310 """Tests handling of a Coreboot Filesystem (CBFS)"""
2311 if not elf.ELF_TOOLS:
2312 self.skipTest('Python elftools not available')
2313 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2314 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2315 size = 0xb0
2316
2317 data = self._DoReadFile('104_cbfs_stage.dts')
2318 cbfs = cbfs_util.CbfsReader(data)
2319 self.assertEqual(size, cbfs.rom_size)
2320
2321 self.assertIn('u-boot', cbfs.files)
2322 cfile = cbfs.files['u-boot']
2323 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2324
2325 def testCbfsRawCompress(self):
2326 """Test handling of compressing raw files"""
2327 self._CheckLz4()
2328 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2329 size = 0x140
2330
2331 cbfs = cbfs_util.CbfsReader(data)
2332 self.assertIn('u-boot', cbfs.files)
2333 cfile = cbfs.files['u-boot']
2334 self.assertEqual(COMPRESS_DATA, cfile.data)
2335
2336 def testCbfsBadArch(self):
2337 """Test handling of a bad architecture"""
2338 with self.assertRaises(ValueError) as e:
2339 self._DoReadFile('106_cbfs_bad_arch.dts')
2340 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2341
2342 def testCbfsNoSize(self):
2343 """Test handling of a missing size property"""
2344 with self.assertRaises(ValueError) as e:
2345 self._DoReadFile('107_cbfs_no_size.dts')
2346 self.assertIn('entry must have a size property', str(e.exception))
2347
Simon Glass3e28f4f2021-11-23 11:03:54 -07002348 def testCbfsNoContents(self):
Simon Glass1de34482019-07-08 13:18:53 -06002349 """Test handling of a CBFS entry which does not provide contentsy"""
2350 with self.assertRaises(ValueError) as e:
2351 self._DoReadFile('108_cbfs_no_contents.dts')
2352 self.assertIn('Could not complete processing of contents',
2353 str(e.exception))
2354
2355 def testCbfsBadCompress(self):
2356 """Test handling of a bad architecture"""
2357 with self.assertRaises(ValueError) as e:
2358 self._DoReadFile('109_cbfs_bad_compress.dts')
2359 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2360 str(e.exception))
2361
2362 def testCbfsNamedEntries(self):
2363 """Test handling of named entries"""
2364 data = self._DoReadFile('110_cbfs_name.dts')
2365
2366 cbfs = cbfs_util.CbfsReader(data)
2367 self.assertIn('FRED', cbfs.files)
2368 cfile1 = cbfs.files['FRED']
2369 self.assertEqual(U_BOOT_DATA, cfile1.data)
2370
2371 self.assertIn('hello', cbfs.files)
2372 cfile2 = cbfs.files['hello']
2373 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2374
Simon Glass759af872019-07-08 13:18:54 -06002375 def _SetupIfwi(self, fname):
2376 """Set up to run an IFWI test
2377
2378 Args:
2379 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2380 """
2381 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002382 self._SetupTplElf()
Simon Glass759af872019-07-08 13:18:54 -06002383
2384 # Intel Integrated Firmware Image (IFWI) file
2385 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2386 data = fd.read()
2387 TestFunctional._MakeInputFile(fname,data)
2388
2389 def _CheckIfwi(self, data):
2390 """Check that an image with an IFWI contains the correct output
2391
2392 Args:
2393 data: Conents of output file
2394 """
Simon Glass80025522022-01-29 14:14:04 -07002395 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glass759af872019-07-08 13:18:54 -06002396 if data[:0x1000] != expected_desc:
2397 self.fail('Expected descriptor binary at start of image')
2398
2399 # We expect to find the TPL wil in subpart IBBP entry IBBL
Simon Glass80025522022-01-29 14:14:04 -07002400 image_fname = tools.get_output_filename('image.bin')
2401 tpl_fname = tools.get_output_filename('tpl.out')
Simon Glass57c7a482022-01-09 20:14:01 -07002402 ifwitool = bintool.Bintool.create('ifwitool')
2403 ifwitool.extract(image_fname, 'IBBP', 'IBBL', tpl_fname)
Simon Glass759af872019-07-08 13:18:54 -06002404
Simon Glass80025522022-01-29 14:14:04 -07002405 tpl_data = tools.read_file(tpl_fname)
Simon Glassf55bd692019-08-24 07:22:51 -06002406 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glass759af872019-07-08 13:18:54 -06002407
2408 def testPackX86RomIfwi(self):
2409 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2410 self._SetupIfwi('fitimage.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002411 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glass759af872019-07-08 13:18:54 -06002412 self._CheckIfwi(data)
2413
2414 def testPackX86RomIfwiNoDesc(self):
2415 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2416 self._SetupIfwi('ifwi.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002417 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glass759af872019-07-08 13:18:54 -06002418 self._CheckIfwi(data)
2419
2420 def testPackX86RomIfwiNoData(self):
2421 """Test that an x86 ROM with IFWI handles missing data"""
2422 self._SetupIfwi('ifwi.bin')
2423 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06002424 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glass759af872019-07-08 13:18:54 -06002425 self.assertIn('Could not complete processing of contents',
2426 str(e.exception))
Simon Glass91710b32018-07-17 13:25:32 -06002427
Simon Glass66152ce2022-01-09 20:14:09 -07002428 def testIfwiMissing(self):
2429 """Test that binman still produces an image if ifwitool is missing"""
2430 self._SetupIfwi('fitimage.bin')
2431 with test_util.capture_sys_output() as (_, stderr):
2432 self._DoTestFile('111_x86_rom_ifwi.dts',
2433 force_missing_bintools='ifwitool')
2434 err = stderr.getvalue()
2435 self.assertRegex(err,
2436 "Image 'main-section'.*missing bintools.*: ifwitool")
2437
Simon Glassc2f1aed2019-07-08 13:18:56 -06002438 def testCbfsOffset(self):
2439 """Test a CBFS with files at particular offsets
2440
2441 Like all CFBS tests, this is just checking the logic that calls
2442 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2443 """
2444 data = self._DoReadFile('114_cbfs_offset.dts')
2445 size = 0x200
2446
2447 cbfs = cbfs_util.CbfsReader(data)
2448 self.assertEqual(size, cbfs.rom_size)
2449
2450 self.assertIn('u-boot', cbfs.files)
2451 cfile = cbfs.files['u-boot']
2452 self.assertEqual(U_BOOT_DATA, cfile.data)
2453 self.assertEqual(0x40, cfile.cbfs_offset)
2454
2455 self.assertIn('u-boot-dtb', cbfs.files)
2456 cfile2 = cbfs.files['u-boot-dtb']
2457 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2458 self.assertEqual(0x140, cfile2.cbfs_offset)
2459
Simon Glass0f621332019-07-08 14:25:27 -06002460 def testFdtmap(self):
2461 """Test an FDT map can be inserted in the image"""
2462 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2463 fdtmap_data = data[len(U_BOOT_DATA):]
2464 magic = fdtmap_data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002465 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07002466 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass0f621332019-07-08 14:25:27 -06002467
2468 fdt_data = fdtmap_data[16:]
2469 dtb = fdt.Fdt.FromData(fdt_data)
2470 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002471 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass0f621332019-07-08 14:25:27 -06002472 self.assertEqual({
2473 'image-pos': 0,
2474 'offset': 0,
2475 'u-boot:offset': 0,
2476 'u-boot:size': len(U_BOOT_DATA),
2477 'u-boot:image-pos': 0,
2478 'fdtmap:image-pos': 4,
2479 'fdtmap:offset': 4,
2480 'fdtmap:size': len(fdtmap_data),
2481 'size': len(data),
2482 }, props)
2483
2484 def testFdtmapNoMatch(self):
2485 """Check handling of an FDT map when the section cannot be found"""
2486 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2487
2488 # Mangle the section name, which should cause a mismatch between the
2489 # correct FDT path and the one expected by the section
2490 image = control.images['image']
Simon Glasscec34ba2019-07-08 14:25:28 -06002491 image._node.path += '-suffix'
Simon Glass0f621332019-07-08 14:25:27 -06002492 entries = image.GetEntries()
2493 fdtmap = entries['fdtmap']
2494 with self.assertRaises(ValueError) as e:
2495 fdtmap._GetFdtmap()
2496 self.assertIn("Cannot locate node for path '/binman-suffix'",
2497 str(e.exception))
2498
Simon Glasscec34ba2019-07-08 14:25:28 -06002499 def testFdtmapHeader(self):
2500 """Test an FDT map and image header can be inserted in the image"""
2501 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2502 fdtmap_pos = len(U_BOOT_DATA)
2503 fdtmap_data = data[fdtmap_pos:]
2504 fdt_data = fdtmap_data[16:]
2505 dtb = fdt.Fdt.FromData(fdt_data)
2506 fdt_size = dtb.GetFdtObj().totalsize()
2507 hdr_data = data[-8:]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002508 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002509 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2510 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2511
2512 def testFdtmapHeaderStart(self):
2513 """Test an image header can be inserted at the image start"""
2514 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2515 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2516 hdr_data = data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002517 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002518 offset = struct.unpack('<I', hdr_data[4:])[0]
2519 self.assertEqual(fdtmap_pos, offset)
2520
2521 def testFdtmapHeaderPos(self):
2522 """Test an image header can be inserted at a chosen position"""
2523 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2524 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2525 hdr_data = data[0x80:0x88]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002526 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002527 offset = struct.unpack('<I', hdr_data[4:])[0]
2528 self.assertEqual(fdtmap_pos, offset)
2529
2530 def testHeaderMissingFdtmap(self):
2531 """Test an image header requires an fdtmap"""
2532 with self.assertRaises(ValueError) as e:
2533 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2534 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2535 str(e.exception))
2536
2537 def testHeaderNoLocation(self):
2538 """Test an image header with a no specified location is detected"""
2539 with self.assertRaises(ValueError) as e:
2540 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2541 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2542 str(e.exception))
2543
Simon Glasse61b6f62019-07-08 14:25:37 -06002544 def testEntryExpand(self):
Simon Glassdd156a42022-03-05 20:18:59 -07002545 """Test extending an entry after it is packed"""
2546 data = self._DoReadFile('121_entry_extend.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002547 self.assertEqual(b'aaa', data[:3])
2548 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2549 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002550
Simon Glassdd156a42022-03-05 20:18:59 -07002551 def testEntryExtendBad(self):
2552 """Test extending an entry after it is packed, twice"""
Simon Glasse61b6f62019-07-08 14:25:37 -06002553 with self.assertRaises(ValueError) as e:
Simon Glassdd156a42022-03-05 20:18:59 -07002554 self._DoReadFile('122_entry_extend_twice.dts')
Simon Glass9d8ee322019-07-20 12:23:58 -06002555 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glasse61b6f62019-07-08 14:25:37 -06002556 str(e.exception))
2557
Simon Glassdd156a42022-03-05 20:18:59 -07002558 def testEntryExtendSection(self):
2559 """Test extending an entry within a section after it is packed"""
2560 data = self._DoReadFile('123_entry_extend_section.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002561 self.assertEqual(b'aaa', data[:3])
2562 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2563 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002564
Simon Glass90d29682019-07-08 14:25:38 -06002565 def testCompressDtb(self):
2566 """Test that compress of device-tree files is supported"""
2567 self._CheckLz4()
2568 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2569 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2570 comp_data = data[len(U_BOOT_DATA):]
2571 orig = self._decompress(comp_data)
2572 dtb = fdt.Fdt.FromData(orig)
2573 dtb.Scan()
2574 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2575 expected = {
2576 'u-boot:size': len(U_BOOT_DATA),
2577 'u-boot-dtb:uncomp-size': len(orig),
2578 'u-boot-dtb:size': len(comp_data),
2579 'size': len(data),
2580 }
2581 self.assertEqual(expected, props)
2582
Simon Glass151bbbf2019-07-08 14:25:41 -06002583 def testCbfsUpdateFdt(self):
2584 """Test that we can update the device tree with CBFS offset/size info"""
2585 self._CheckLz4()
2586 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2587 update_dtb=True)
2588 dtb = fdt.Fdt(out_dtb_fname)
2589 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002590 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass151bbbf2019-07-08 14:25:41 -06002591 del props['cbfs/u-boot:size']
2592 self.assertEqual({
2593 'offset': 0,
2594 'size': len(data),
2595 'image-pos': 0,
2596 'cbfs:offset': 0,
2597 'cbfs:size': len(data),
2598 'cbfs:image-pos': 0,
2599 'cbfs/u-boot:offset': 0x38,
2600 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2601 'cbfs/u-boot:image-pos': 0x38,
2602 'cbfs/u-boot-dtb:offset': 0xb8,
2603 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2604 'cbfs/u-boot-dtb:image-pos': 0xb8,
2605 }, props)
2606
Simon Glass3c9b4f22019-07-08 14:25:42 -06002607 def testCbfsBadType(self):
2608 """Test an image header with a no specified location is detected"""
2609 with self.assertRaises(ValueError) as e:
2610 self._DoReadFile('126_cbfs_bad_type.dts')
2611 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2612
Simon Glass6b156f82019-07-08 14:25:43 -06002613 def testList(self):
2614 """Test listing the files in an image"""
2615 self._CheckLz4()
2616 data = self._DoReadFile('127_list.dts')
2617 image = control.images['image']
2618 entries = image.BuildEntryList()
2619 self.assertEqual(7, len(entries))
2620
2621 ent = entries[0]
2622 self.assertEqual(0, ent.indent)
2623 self.assertEqual('main-section', ent.name)
2624 self.assertEqual('section', ent.etype)
2625 self.assertEqual(len(data), ent.size)
2626 self.assertEqual(0, ent.image_pos)
2627 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002628 self.assertEqual(0, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002629
2630 ent = entries[1]
2631 self.assertEqual(1, ent.indent)
2632 self.assertEqual('u-boot', ent.name)
2633 self.assertEqual('u-boot', ent.etype)
2634 self.assertEqual(len(U_BOOT_DATA), ent.size)
2635 self.assertEqual(0, ent.image_pos)
2636 self.assertEqual(None, ent.uncomp_size)
2637 self.assertEqual(0, ent.offset)
2638
2639 ent = entries[2]
2640 self.assertEqual(1, ent.indent)
2641 self.assertEqual('section', ent.name)
2642 self.assertEqual('section', ent.etype)
2643 section_size = ent.size
2644 self.assertEqual(0x100, ent.image_pos)
2645 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002646 self.assertEqual(0x100, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002647
2648 ent = entries[3]
2649 self.assertEqual(2, ent.indent)
2650 self.assertEqual('cbfs', ent.name)
2651 self.assertEqual('cbfs', ent.etype)
2652 self.assertEqual(0x400, ent.size)
2653 self.assertEqual(0x100, ent.image_pos)
2654 self.assertEqual(None, ent.uncomp_size)
2655 self.assertEqual(0, ent.offset)
2656
2657 ent = entries[4]
2658 self.assertEqual(3, ent.indent)
2659 self.assertEqual('u-boot', ent.name)
2660 self.assertEqual('u-boot', ent.etype)
2661 self.assertEqual(len(U_BOOT_DATA), ent.size)
2662 self.assertEqual(0x138, ent.image_pos)
2663 self.assertEqual(None, ent.uncomp_size)
2664 self.assertEqual(0x38, ent.offset)
2665
2666 ent = entries[5]
2667 self.assertEqual(3, ent.indent)
2668 self.assertEqual('u-boot-dtb', ent.name)
2669 self.assertEqual('text', ent.etype)
2670 self.assertGreater(len(COMPRESS_DATA), ent.size)
2671 self.assertEqual(0x178, ent.image_pos)
2672 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2673 self.assertEqual(0x78, ent.offset)
2674
2675 ent = entries[6]
2676 self.assertEqual(2, ent.indent)
2677 self.assertEqual('u-boot-dtb', ent.name)
2678 self.assertEqual('u-boot-dtb', ent.etype)
2679 self.assertEqual(0x500, ent.image_pos)
2680 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2681 dtb_size = ent.size
2682 # Compressing this data expands it since headers are added
2683 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2684 self.assertEqual(0x400, ent.offset)
2685
2686 self.assertEqual(len(data), 0x100 + section_size)
2687 self.assertEqual(section_size, 0x400 + dtb_size)
2688
Simon Glass8d8bf4e2019-07-08 14:25:44 -06002689 def testFindFdtmap(self):
2690 """Test locating an FDT map in an image"""
2691 self._CheckLz4()
2692 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2693 image = control.images['image']
2694 entries = image.GetEntries()
2695 entry = entries['fdtmap']
2696 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2697
2698 def testFindFdtmapMissing(self):
2699 """Test failing to locate an FDP map"""
2700 data = self._DoReadFile('005_simple.dts')
2701 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2702
Simon Glassed39a3c2019-07-08 14:25:45 -06002703 def testFindImageHeader(self):
2704 """Test locating a image header"""
2705 self._CheckLz4()
Simon Glassb8424fa2019-07-08 14:25:46 -06002706 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002707 image = control.images['image']
2708 entries = image.GetEntries()
2709 entry = entries['fdtmap']
2710 # The header should point to the FDT map
2711 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2712
2713 def testFindImageHeaderStart(self):
2714 """Test locating a image header located at the start of an image"""
Simon Glassb8424fa2019-07-08 14:25:46 -06002715 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002716 image = control.images['image']
2717 entries = image.GetEntries()
2718 entry = entries['fdtmap']
2719 # The header should point to the FDT map
2720 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2721
2722 def testFindImageHeaderMissing(self):
2723 """Test failing to locate an image header"""
2724 data = self._DoReadFile('005_simple.dts')
2725 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2726
Simon Glassb8424fa2019-07-08 14:25:46 -06002727 def testReadImage(self):
2728 """Test reading an image and accessing its FDT map"""
2729 self._CheckLz4()
2730 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass80025522022-01-29 14:14:04 -07002731 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002732 orig_image = control.images['image']
2733 image = Image.FromFile(image_fname)
2734 self.assertEqual(orig_image.GetEntries().keys(),
2735 image.GetEntries().keys())
2736
2737 orig_entry = orig_image.GetEntries()['fdtmap']
2738 entry = image.GetEntries()['fdtmap']
2739 self.assertEquals(orig_entry.offset, entry.offset)
2740 self.assertEquals(orig_entry.size, entry.size)
2741 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2742
2743 def testReadImageNoHeader(self):
2744 """Test accessing an image's FDT map without an image header"""
2745 self._CheckLz4()
2746 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
Simon Glass80025522022-01-29 14:14:04 -07002747 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002748 image = Image.FromFile(image_fname)
2749 self.assertTrue(isinstance(image, Image))
Simon Glass072959a2019-07-20 12:23:50 -06002750 self.assertEqual('image', image.image_name[-5:])
Simon Glassb8424fa2019-07-08 14:25:46 -06002751
2752 def testReadImageFail(self):
2753 """Test failing to read an image image's FDT map"""
2754 self._DoReadFile('005_simple.dts')
Simon Glass80025522022-01-29 14:14:04 -07002755 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002756 with self.assertRaises(ValueError) as e:
2757 image = Image.FromFile(image_fname)
2758 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glassc2f1aed2019-07-08 13:18:56 -06002759
Simon Glassb2fd11d2019-07-08 14:25:48 -06002760 def testListCmd(self):
2761 """Test listing the files in an image using an Fdtmap"""
2762 self._CheckLz4()
2763 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2764
2765 # lz4 compression size differs depending on the version
2766 image = control.images['image']
2767 entries = image.GetEntries()
2768 section_size = entries['section'].size
2769 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2770 fdtmap_offset = entries['fdtmap'].offset
2771
Simon Glassb3d6fc72019-07-20 12:24:10 -06002772 try:
2773 tmpdir, updated_fname = self._SetupImageInTmpdir()
2774 with test_util.capture_sys_output() as (stdout, stderr):
2775 self._DoBinman('ls', '-i', updated_fname)
2776 finally:
2777 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002778 lines = stdout.getvalue().splitlines()
2779 expected = [
2780'Name Image-pos Size Entry-type Offset Uncomp-size',
2781'----------------------------------------------------------------------',
2782'main-section 0 c00 section 0',
2783' u-boot 0 4 u-boot 0',
2784' section 100 %x section 100' % section_size,
2785' cbfs 100 400 cbfs 0',
2786' u-boot 138 4 u-boot 38',
Simon Glassc5fd10a2019-10-31 07:43:03 -06002787' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002788' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassc5fd10a2019-10-31 07:43:03 -06002789' fdtmap %x 3bd fdtmap %x' %
Simon Glassb2fd11d2019-07-08 14:25:48 -06002790 (fdtmap_offset, fdtmap_offset),
2791' image-header bf8 8 image-header bf8',
2792 ]
2793 self.assertEqual(expected, lines)
2794
2795 def testListCmdFail(self):
2796 """Test failing to list an image"""
2797 self._DoReadFile('005_simple.dts')
Simon Glassb3d6fc72019-07-20 12:24:10 -06002798 try:
2799 tmpdir, updated_fname = self._SetupImageInTmpdir()
2800 with self.assertRaises(ValueError) as e:
2801 self._DoBinman('ls', '-i', updated_fname)
2802 finally:
2803 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002804 self.assertIn("Cannot find FDT map in image", str(e.exception))
2805
2806 def _RunListCmd(self, paths, expected):
2807 """List out entries and check the result
2808
2809 Args:
2810 paths: List of paths to pass to the list command
2811 expected: Expected list of filenames to be returned, in order
2812 """
2813 self._CheckLz4()
2814 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002815 image_fname = tools.get_output_filename('image.bin')
Simon Glassb2fd11d2019-07-08 14:25:48 -06002816 image = Image.FromFile(image_fname)
2817 lines = image.GetListEntries(paths)[1]
2818 files = [line[0].strip() for line in lines[1:]]
2819 self.assertEqual(expected, files)
2820
2821 def testListCmdSection(self):
2822 """Test listing the files in a section"""
2823 self._RunListCmd(['section'],
2824 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2825
2826 def testListCmdFile(self):
2827 """Test listing a particular file"""
2828 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2829
2830 def testListCmdWildcard(self):
2831 """Test listing a wildcarded file"""
2832 self._RunListCmd(['*boot*'],
2833 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2834
2835 def testListCmdWildcardMulti(self):
2836 """Test listing a wildcarded file"""
2837 self._RunListCmd(['*cb*', '*head*'],
2838 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2839
2840 def testListCmdEmpty(self):
2841 """Test listing a wildcarded file"""
2842 self._RunListCmd(['nothing'], [])
2843
2844 def testListCmdPath(self):
2845 """Test listing the files in a sub-entry of a section"""
2846 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2847
Simon Glass4c613bf2019-07-08 14:25:50 -06002848 def _RunExtractCmd(self, entry_name, decomp=True):
2849 """Extract an entry from an image
2850
2851 Args:
2852 entry_name: Entry name to extract
2853 decomp: True to decompress the data if compressed, False to leave
2854 it in its raw uncompressed format
2855
2856 Returns:
2857 data from entry
2858 """
2859 self._CheckLz4()
2860 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002861 image_fname = tools.get_output_filename('image.bin')
Simon Glass4c613bf2019-07-08 14:25:50 -06002862 return control.ReadEntry(image_fname, entry_name, decomp)
2863
2864 def testExtractSimple(self):
2865 """Test extracting a single file"""
2866 data = self._RunExtractCmd('u-boot')
2867 self.assertEqual(U_BOOT_DATA, data)
2868
Simon Glass980a2842019-07-08 14:25:52 -06002869 def testExtractSection(self):
2870 """Test extracting the files in a section"""
2871 data = self._RunExtractCmd('section')
2872 cbfs_data = data[:0x400]
2873 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassc5fd10a2019-10-31 07:43:03 -06002874 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass980a2842019-07-08 14:25:52 -06002875 dtb_data = data[0x400:]
2876 dtb = self._decompress(dtb_data)
2877 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2878
2879 def testExtractCompressed(self):
2880 """Test extracting compressed data"""
2881 data = self._RunExtractCmd('section/u-boot-dtb')
2882 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2883
2884 def testExtractRaw(self):
2885 """Test extracting compressed data without decompressing it"""
2886 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2887 dtb = self._decompress(data)
2888 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2889
2890 def testExtractCbfs(self):
2891 """Test extracting CBFS data"""
2892 data = self._RunExtractCmd('section/cbfs/u-boot')
2893 self.assertEqual(U_BOOT_DATA, data)
2894
2895 def testExtractCbfsCompressed(self):
2896 """Test extracting CBFS compressed data"""
2897 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2898 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2899
2900 def testExtractCbfsRaw(self):
2901 """Test extracting CBFS compressed data without decompressing it"""
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02002902 bintool = self.comp_bintools['lzma_alone']
2903 self._CheckBintool(bintool)
Simon Glass980a2842019-07-08 14:25:52 -06002904 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02002905 dtb = bintool.decompress(data)
Simon Glass980a2842019-07-08 14:25:52 -06002906 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2907
Simon Glass4c613bf2019-07-08 14:25:50 -06002908 def testExtractBadEntry(self):
2909 """Test extracting a bad section path"""
2910 with self.assertRaises(ValueError) as e:
2911 self._RunExtractCmd('section/does-not-exist')
2912 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2913 str(e.exception))
2914
2915 def testExtractMissingFile(self):
2916 """Test extracting file that does not exist"""
2917 with self.assertRaises(IOError) as e:
2918 control.ReadEntry('missing-file', 'name')
2919
2920 def testExtractBadFile(self):
2921 """Test extracting an invalid file"""
2922 fname = os.path.join(self._indir, 'badfile')
Simon Glass80025522022-01-29 14:14:04 -07002923 tools.write_file(fname, b'')
Simon Glass4c613bf2019-07-08 14:25:50 -06002924 with self.assertRaises(ValueError) as e:
2925 control.ReadEntry(fname, 'name')
2926
Simon Glass980a2842019-07-08 14:25:52 -06002927 def testExtractCmd(self):
2928 """Test extracting a file fron an image on the command line"""
2929 self._CheckLz4()
2930 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass980a2842019-07-08 14:25:52 -06002931 fname = os.path.join(self._indir, 'output.extact')
Simon Glassb3d6fc72019-07-20 12:24:10 -06002932 try:
2933 tmpdir, updated_fname = self._SetupImageInTmpdir()
2934 with test_util.capture_sys_output() as (stdout, stderr):
2935 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2936 '-f', fname)
2937 finally:
2938 shutil.rmtree(tmpdir)
Simon Glass80025522022-01-29 14:14:04 -07002939 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06002940 self.assertEqual(U_BOOT_DATA, data)
2941
2942 def testExtractOneEntry(self):
2943 """Test extracting a single entry fron an image """
2944 self._CheckLz4()
2945 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002946 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06002947 fname = os.path.join(self._indir, 'output.extact')
2948 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07002949 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06002950 self.assertEqual(U_BOOT_DATA, data)
2951
2952 def _CheckExtractOutput(self, decomp):
2953 """Helper to test file output with and without decompression
2954
2955 Args:
2956 decomp: True to decompress entry data, False to output it raw
2957 """
2958 def _CheckPresent(entry_path, expect_data, expect_size=None):
2959 """Check and remove expected file
2960
2961 This checks the data/size of a file and removes the file both from
2962 the outfiles set and from the output directory. Once all files are
2963 processed, both the set and directory should be empty.
2964
2965 Args:
2966 entry_path: Entry path
2967 expect_data: Data to expect in file, or None to skip check
2968 expect_size: Size of data to expect in file, or None to skip
2969 """
2970 path = os.path.join(outdir, entry_path)
Simon Glass80025522022-01-29 14:14:04 -07002971 data = tools.read_file(path)
Simon Glass980a2842019-07-08 14:25:52 -06002972 os.remove(path)
2973 if expect_data:
2974 self.assertEqual(expect_data, data)
2975 elif expect_size:
2976 self.assertEqual(expect_size, len(data))
2977 outfiles.remove(path)
2978
2979 def _CheckDirPresent(name):
2980 """Remove expected directory
2981
2982 This gives an error if the directory does not exist as expected
2983
2984 Args:
2985 name: Name of directory to remove
2986 """
2987 path = os.path.join(outdir, name)
2988 os.rmdir(path)
2989
2990 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002991 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06002992 outdir = os.path.join(self._indir, 'extract')
2993 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2994
2995 # Create a set of all file that were output (should be 9)
2996 outfiles = set()
2997 for root, dirs, files in os.walk(outdir):
2998 outfiles |= set([os.path.join(root, fname) for fname in files])
2999 self.assertEqual(9, len(outfiles))
3000 self.assertEqual(9, len(einfos))
3001
3002 image = control.images['image']
3003 entries = image.GetEntries()
3004
3005 # Check the 9 files in various ways
3006 section = entries['section']
3007 section_entries = section.GetEntries()
3008 cbfs_entries = section_entries['cbfs'].GetEntries()
3009 _CheckPresent('u-boot', U_BOOT_DATA)
3010 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
3011 dtb_len = EXTRACT_DTB_SIZE
3012 if not decomp:
3013 dtb_len = cbfs_entries['u-boot-dtb'].size
3014 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
3015 if not decomp:
3016 dtb_len = section_entries['u-boot-dtb'].size
3017 _CheckPresent('section/u-boot-dtb', None, dtb_len)
3018
3019 fdtmap = entries['fdtmap']
3020 _CheckPresent('fdtmap', fdtmap.data)
3021 hdr = entries['image-header']
3022 _CheckPresent('image-header', hdr.data)
3023
3024 _CheckPresent('section/root', section.data)
3025 cbfs = section_entries['cbfs']
3026 _CheckPresent('section/cbfs/root', cbfs.data)
Simon Glass80025522022-01-29 14:14:04 -07003027 data = tools.read_file(image_fname)
Simon Glass980a2842019-07-08 14:25:52 -06003028 _CheckPresent('root', data)
3029
3030 # There should be no files left. Remove all the directories to check.
3031 # If there are any files/dirs remaining, one of these checks will fail.
3032 self.assertEqual(0, len(outfiles))
3033 _CheckDirPresent('section/cbfs')
3034 _CheckDirPresent('section')
3035 _CheckDirPresent('')
3036 self.assertFalse(os.path.exists(outdir))
3037
3038 def testExtractAllEntries(self):
3039 """Test extracting all entries"""
3040 self._CheckLz4()
3041 self._CheckExtractOutput(decomp=True)
3042
3043 def testExtractAllEntriesRaw(self):
3044 """Test extracting all entries without decompressing them"""
3045 self._CheckLz4()
3046 self._CheckExtractOutput(decomp=False)
3047
3048 def testExtractSelectedEntries(self):
3049 """Test extracting some entries"""
3050 self._CheckLz4()
3051 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003052 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003053 outdir = os.path.join(self._indir, 'extract')
3054 einfos = control.ExtractEntries(image_fname, None, outdir,
3055 ['*cb*', '*head*'])
3056
3057 # File output is tested by testExtractAllEntries(), so just check that
3058 # the expected entries are selected
3059 names = [einfo.name for einfo in einfos]
3060 self.assertEqual(names,
3061 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
3062
3063 def testExtractNoEntryPaths(self):
3064 """Test extracting some entries"""
3065 self._CheckLz4()
3066 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003067 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003068 with self.assertRaises(ValueError) as e:
3069 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassa772d3f2019-07-20 12:24:14 -06003070 self.assertIn('Must specify an entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003071 str(e.exception))
3072
3073 def testExtractTooManyEntryPaths(self):
3074 """Test extracting some entries"""
3075 self._CheckLz4()
3076 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003077 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003078 with self.assertRaises(ValueError) as e:
3079 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassa772d3f2019-07-20 12:24:14 -06003080 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003081 str(e.exception))
3082
Simon Glass52d06212019-07-08 14:25:53 -06003083 def testPackAlignSection(self):
3084 """Test that sections can have alignment"""
3085 self._DoReadFile('131_pack_align_section.dts')
3086
3087 self.assertIn('image', control.images)
3088 image = control.images['image']
3089 entries = image.GetEntries()
3090 self.assertEqual(3, len(entries))
3091
3092 # First u-boot
3093 self.assertIn('u-boot', entries)
3094 entry = entries['u-boot']
3095 self.assertEqual(0, entry.offset)
3096 self.assertEqual(0, entry.image_pos)
3097 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3098 self.assertEqual(len(U_BOOT_DATA), entry.size)
3099
3100 # Section0
3101 self.assertIn('section0', entries)
3102 section0 = entries['section0']
3103 self.assertEqual(0x10, section0.offset)
3104 self.assertEqual(0x10, section0.image_pos)
3105 self.assertEqual(len(U_BOOT_DATA), section0.size)
3106
3107 # Second u-boot
3108 section_entries = section0.GetEntries()
3109 self.assertIn('u-boot', section_entries)
3110 entry = section_entries['u-boot']
3111 self.assertEqual(0, entry.offset)
3112 self.assertEqual(0x10, entry.image_pos)
3113 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3114 self.assertEqual(len(U_BOOT_DATA), entry.size)
3115
3116 # Section1
3117 self.assertIn('section1', entries)
3118 section1 = entries['section1']
3119 self.assertEqual(0x14, section1.offset)
3120 self.assertEqual(0x14, section1.image_pos)
3121 self.assertEqual(0x20, section1.size)
3122
3123 # Second u-boot
3124 section_entries = section1.GetEntries()
3125 self.assertIn('u-boot', section_entries)
3126 entry = section_entries['u-boot']
3127 self.assertEqual(0, entry.offset)
3128 self.assertEqual(0x14, entry.image_pos)
3129 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3130 self.assertEqual(len(U_BOOT_DATA), entry.size)
3131
3132 # Section2
3133 self.assertIn('section2', section_entries)
3134 section2 = section_entries['section2']
3135 self.assertEqual(0x4, section2.offset)
3136 self.assertEqual(0x18, section2.image_pos)
3137 self.assertEqual(4, section2.size)
3138
3139 # Third u-boot
3140 section_entries = section2.GetEntries()
3141 self.assertIn('u-boot', section_entries)
3142 entry = section_entries['u-boot']
3143 self.assertEqual(0, entry.offset)
3144 self.assertEqual(0x18, entry.image_pos)
3145 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3146 self.assertEqual(len(U_BOOT_DATA), entry.size)
3147
Simon Glassf8a54bc2019-07-20 12:23:56 -06003148 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3149 dts='132_replace.dts'):
Simon Glass072959a2019-07-20 12:23:50 -06003150 """Replace an entry in an image
3151
3152 This writes the entry data to update it, then opens the updated file and
3153 returns the value that it now finds there.
3154
3155 Args:
3156 entry_name: Entry name to replace
3157 data: Data to replace it with
3158 decomp: True to compress the data if needed, False if data is
3159 already compressed so should be used as is
Simon Glassf8a54bc2019-07-20 12:23:56 -06003160 allow_resize: True to allow entries to change size, False to raise
3161 an exception
Simon Glass072959a2019-07-20 12:23:50 -06003162
3163 Returns:
3164 Tuple:
3165 data from entry
3166 data from fdtmap (excluding header)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003167 Image object that was modified
Simon Glass072959a2019-07-20 12:23:50 -06003168 """
Simon Glassf8a54bc2019-07-20 12:23:56 -06003169 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass072959a2019-07-20 12:23:50 -06003170 update_dtb=True)[1]
3171
3172 self.assertIn('image', control.images)
3173 image = control.images['image']
3174 entries = image.GetEntries()
3175 orig_dtb_data = entries['u-boot-dtb'].data
3176 orig_fdtmap_data = entries['fdtmap'].data
3177
Simon Glass80025522022-01-29 14:14:04 -07003178 image_fname = tools.get_output_filename('image.bin')
3179 updated_fname = tools.get_output_filename('image-updated.bin')
3180 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassf8a54bc2019-07-20 12:23:56 -06003181 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3182 allow_resize)
Simon Glass072959a2019-07-20 12:23:50 -06003183 data = control.ReadEntry(updated_fname, entry_name, decomp)
3184
Simon Glassf8a54bc2019-07-20 12:23:56 -06003185 # The DT data should not change unless resized:
3186 if not allow_resize:
3187 new_dtb_data = entries['u-boot-dtb'].data
3188 self.assertEqual(new_dtb_data, orig_dtb_data)
3189 new_fdtmap_data = entries['fdtmap'].data
3190 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass072959a2019-07-20 12:23:50 -06003191
Simon Glassf8a54bc2019-07-20 12:23:56 -06003192 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass072959a2019-07-20 12:23:50 -06003193
3194 def testReplaceSimple(self):
3195 """Test replacing a single file"""
3196 expected = b'x' * len(U_BOOT_DATA)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003197 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3198 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003199 self.assertEqual(expected, data)
3200
3201 # Test that the state looks right. There should be an FDT for the fdtmap
3202 # that we jsut read back in, and it should match what we find in the
3203 # 'control' tables. Checking for an FDT that does not exist should
3204 # return None.
3205 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glassf8a54bc2019-07-20 12:23:56 -06003206 self.assertIsNotNone(path)
Simon Glass072959a2019-07-20 12:23:50 -06003207 self.assertEqual(expected_fdtmap, fdtmap)
3208
3209 dtb = state.GetFdtForEtype('fdtmap')
3210 self.assertEqual(dtb.GetContents(), fdtmap)
3211
3212 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3213 self.assertIsNone(missing_path)
3214 self.assertIsNone(missing_fdtmap)
3215
3216 missing_dtb = state.GetFdtForEtype('missing')
3217 self.assertIsNone(missing_dtb)
3218
3219 self.assertEqual('/binman', state.fdt_path_prefix)
3220
3221 def testReplaceResizeFail(self):
3222 """Test replacing a file by something larger"""
3223 expected = U_BOOT_DATA + b'x'
3224 with self.assertRaises(ValueError) as e:
Simon Glassf8a54bc2019-07-20 12:23:56 -06003225 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3226 dts='139_replace_repack.dts')
Simon Glass072959a2019-07-20 12:23:50 -06003227 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3228 str(e.exception))
3229
3230 def testReplaceMulti(self):
3231 """Test replacing entry data where multiple images are generated"""
3232 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3233 update_dtb=True)[0]
3234 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003235 updated_fname = tools.get_output_filename('image-updated.bin')
3236 tools.write_file(updated_fname, data)
Simon Glass072959a2019-07-20 12:23:50 -06003237 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003238 control.WriteEntry(updated_fname, entry_name, expected,
3239 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003240 data = control.ReadEntry(updated_fname, entry_name)
3241 self.assertEqual(expected, data)
3242
3243 # Check the state looks right.
3244 self.assertEqual('/binman/image', state.fdt_path_prefix)
3245
3246 # Now check we can write the first image
Simon Glass80025522022-01-29 14:14:04 -07003247 image_fname = tools.get_output_filename('first-image.bin')
3248 updated_fname = tools.get_output_filename('first-updated.bin')
3249 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glass072959a2019-07-20 12:23:50 -06003250 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003251 control.WriteEntry(updated_fname, entry_name, expected,
3252 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003253 data = control.ReadEntry(updated_fname, entry_name)
3254 self.assertEqual(expected, data)
3255
3256 # Check the state looks right.
3257 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass39dd2152019-07-08 14:25:47 -06003258
Simon Glassfb30e292019-07-20 12:23:51 -06003259 def testUpdateFdtAllRepack(self):
3260 """Test that all device trees are updated with offset/size info"""
3261 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3262 SECTION_SIZE = 0x300
3263 DTB_SIZE = 602
3264 FDTMAP_SIZE = 608
3265 base_expected = {
3266 'offset': 0,
3267 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3268 'image-pos': 0,
3269 'section:offset': 0,
3270 'section:size': SECTION_SIZE,
3271 'section:image-pos': 0,
3272 'section/u-boot-dtb:offset': 4,
3273 'section/u-boot-dtb:size': 636,
3274 'section/u-boot-dtb:image-pos': 4,
3275 'u-boot-spl-dtb:offset': SECTION_SIZE,
3276 'u-boot-spl-dtb:size': DTB_SIZE,
3277 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3278 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3279 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3280 'u-boot-tpl-dtb:size': DTB_SIZE,
3281 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3282 'fdtmap:size': FDTMAP_SIZE,
3283 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3284 }
3285 main_expected = {
3286 'section:orig-size': SECTION_SIZE,
3287 'section/u-boot-dtb:orig-offset': 4,
3288 }
3289
3290 # We expect three device-tree files in the output, with the first one
3291 # within a fixed-size section.
3292 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3293 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3294 # main U-Boot tree. All three should have the same positions and offset
3295 # except that the main tree should include the main_expected properties
3296 start = 4
3297 for item in ['', 'spl', 'tpl', None]:
3298 if item is None:
3299 start += 16 # Move past fdtmap header
3300 dtb = fdt.Fdt.FromData(data[start:])
3301 dtb.Scan()
3302 props = self._GetPropTree(dtb,
3303 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3304 prefix='/' if item is None else '/binman/')
3305 expected = dict(base_expected)
3306 if item:
3307 expected[item] = 0
3308 else:
3309 # Main DTB and fdtdec should include the 'orig-' properties
3310 expected.update(main_expected)
3311 # Helpful for debugging:
3312 #for prop in sorted(props):
3313 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3314 self.assertEqual(expected, props)
3315 if item == '':
3316 start = SECTION_SIZE
3317 else:
3318 start += dtb._fdt_obj.totalsize()
3319
Simon Glass11453762019-07-20 12:23:55 -06003320 def testFdtmapHeaderMiddle(self):
3321 """Test an FDT map in the middle of an image when it should be at end"""
3322 with self.assertRaises(ValueError) as e:
3323 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3324 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3325 str(e.exception))
3326
3327 def testFdtmapHeaderStartBad(self):
3328 """Test an FDT map in middle of an image when it should be at start"""
3329 with self.assertRaises(ValueError) as e:
3330 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3331 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3332 str(e.exception))
3333
3334 def testFdtmapHeaderEndBad(self):
3335 """Test an FDT map at the start of an image when it should be at end"""
3336 with self.assertRaises(ValueError) as e:
3337 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3338 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3339 str(e.exception))
3340
3341 def testFdtmapHeaderNoSize(self):
3342 """Test an image header at the end of an image with undefined size"""
3343 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3344
Simon Glassf8a54bc2019-07-20 12:23:56 -06003345 def testReplaceResize(self):
3346 """Test replacing a single file in an entry with a larger file"""
3347 expected = U_BOOT_DATA + b'x'
3348 data, _, image = self._RunReplaceCmd('u-boot', expected,
3349 dts='139_replace_repack.dts')
3350 self.assertEqual(expected, data)
3351
3352 entries = image.GetEntries()
3353 dtb_data = entries['u-boot-dtb'].data
3354 dtb = fdt.Fdt.FromData(dtb_data)
3355 dtb.Scan()
3356
3357 # The u-boot section should now be larger in the dtb
3358 node = dtb.GetNode('/binman/u-boot')
3359 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3360
3361 # Same for the fdtmap
3362 fdata = entries['fdtmap'].data
3363 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3364 fdtb.Scan()
3365 fnode = fdtb.GetNode('/u-boot')
3366 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3367
3368 def testReplaceResizeNoRepack(self):
3369 """Test replacing an entry with a larger file when not allowed"""
3370 expected = U_BOOT_DATA + b'x'
3371 with self.assertRaises(ValueError) as e:
3372 self._RunReplaceCmd('u-boot', expected)
3373 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3374 str(e.exception))
3375
Simon Glass9d8ee322019-07-20 12:23:58 -06003376 def testEntryShrink(self):
3377 """Test contracting an entry after it is packed"""
3378 try:
3379 state.SetAllowEntryContraction(True)
3380 data = self._DoReadFileDtb('140_entry_shrink.dts',
3381 update_dtb=True)[0]
3382 finally:
3383 state.SetAllowEntryContraction(False)
3384 self.assertEqual(b'a', data[:1])
3385 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3386 self.assertEqual(b'a', data[-1:])
3387
3388 def testEntryShrinkFail(self):
3389 """Test not being allowed to contract an entry after it is packed"""
3390 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3391
3392 # In this case there is a spare byte at the end of the data. The size of
3393 # the contents is only 1 byte but we still have the size before it
3394 # shrunk.
3395 self.assertEqual(b'a\0', data[:2])
3396 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3397 self.assertEqual(b'a\0', data[-2:])
3398
Simon Glass70e32982019-07-20 12:24:01 -06003399 def testDescriptorOffset(self):
3400 """Test that the Intel descriptor is always placed at at the start"""
3401 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3402 image = control.images['image']
3403 entries = image.GetEntries()
3404 desc = entries['intel-descriptor']
3405 self.assertEqual(0xff800000, desc.offset);
3406 self.assertEqual(0xff800000, desc.image_pos);
3407
Simon Glass37fdd142019-07-20 12:24:06 -06003408 def testReplaceCbfs(self):
3409 """Test replacing a single file in CBFS without changing the size"""
3410 self._CheckLz4()
3411 expected = b'x' * len(U_BOOT_DATA)
3412 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003413 updated_fname = tools.get_output_filename('image-updated.bin')
3414 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003415 entry_name = 'section/cbfs/u-boot'
3416 control.WriteEntry(updated_fname, entry_name, expected,
3417 allow_resize=True)
3418 data = control.ReadEntry(updated_fname, entry_name)
3419 self.assertEqual(expected, data)
3420
3421 def testReplaceResizeCbfs(self):
3422 """Test replacing a single file in CBFS with one of a different size"""
3423 self._CheckLz4()
3424 expected = U_BOOT_DATA + b'x'
3425 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003426 updated_fname = tools.get_output_filename('image-updated.bin')
3427 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003428 entry_name = 'section/cbfs/u-boot'
3429 control.WriteEntry(updated_fname, entry_name, expected,
3430 allow_resize=True)
3431 data = control.ReadEntry(updated_fname, entry_name)
3432 self.assertEqual(expected, data)
3433
Simon Glass30033c22019-07-20 12:24:15 -06003434 def _SetupForReplace(self):
3435 """Set up some files to use to replace entries
3436
3437 This generates an image, copies it to a new file, extracts all the files
3438 in it and updates some of them
3439
3440 Returns:
3441 List
3442 Image filename
3443 Output directory
3444 Expected values for updated entries, each a string
3445 """
3446 data = self._DoReadFileRealDtb('143_replace_all.dts')
3447
Simon Glass80025522022-01-29 14:14:04 -07003448 updated_fname = tools.get_output_filename('image-updated.bin')
3449 tools.write_file(updated_fname, data)
Simon Glass30033c22019-07-20 12:24:15 -06003450
3451 outdir = os.path.join(self._indir, 'extract')
3452 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3453
3454 expected1 = b'x' + U_BOOT_DATA + b'y'
3455 u_boot_fname1 = os.path.join(outdir, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07003456 tools.write_file(u_boot_fname1, expected1)
Simon Glass30033c22019-07-20 12:24:15 -06003457
3458 expected2 = b'a' + U_BOOT_DATA + b'b'
3459 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
Simon Glass80025522022-01-29 14:14:04 -07003460 tools.write_file(u_boot_fname2, expected2)
Simon Glass30033c22019-07-20 12:24:15 -06003461
3462 expected_text = b'not the same text'
3463 text_fname = os.path.join(outdir, 'text')
Simon Glass80025522022-01-29 14:14:04 -07003464 tools.write_file(text_fname, expected_text)
Simon Glass30033c22019-07-20 12:24:15 -06003465
3466 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3467 dtb = fdt.FdtScan(dtb_fname)
3468 node = dtb.GetNode('/binman/text')
3469 node.AddString('my-property', 'the value')
3470 dtb.Sync(auto_resize=True)
3471 dtb.Flush()
3472
3473 return updated_fname, outdir, expected1, expected2, expected_text
3474
3475 def _CheckReplaceMultiple(self, entry_paths):
3476 """Handle replacing the contents of multiple entries
3477
3478 Args:
3479 entry_paths: List of entry paths to replace
3480
3481 Returns:
3482 List
3483 Dict of entries in the image:
3484 key: Entry name
3485 Value: Entry object
3486 Expected values for updated entries, each a string
3487 """
3488 updated_fname, outdir, expected1, expected2, expected_text = (
3489 self._SetupForReplace())
3490 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3491
3492 image = Image.FromFile(updated_fname)
3493 image.LoadData()
3494 return image.GetEntries(), expected1, expected2, expected_text
3495
3496 def testReplaceAll(self):
3497 """Test replacing the contents of all entries"""
3498 entries, expected1, expected2, expected_text = (
3499 self._CheckReplaceMultiple([]))
3500 data = entries['u-boot'].data
3501 self.assertEqual(expected1, data)
3502
3503 data = entries['u-boot2'].data
3504 self.assertEqual(expected2, data)
3505
3506 data = entries['text'].data
3507 self.assertEqual(expected_text, data)
3508
3509 # Check that the device tree is updated
3510 data = entries['u-boot-dtb'].data
3511 dtb = fdt.Fdt.FromData(data)
3512 dtb.Scan()
3513 node = dtb.GetNode('/binman/text')
3514 self.assertEqual('the value', node.props['my-property'].value)
3515
3516 def testReplaceSome(self):
3517 """Test replacing the contents of a few entries"""
3518 entries, expected1, expected2, expected_text = (
3519 self._CheckReplaceMultiple(['u-boot2', 'text']))
3520
3521 # This one should not change
3522 data = entries['u-boot'].data
3523 self.assertEqual(U_BOOT_DATA, data)
3524
3525 data = entries['u-boot2'].data
3526 self.assertEqual(expected2, data)
3527
3528 data = entries['text'].data
3529 self.assertEqual(expected_text, data)
3530
3531 def testReplaceCmd(self):
3532 """Test replacing a file fron an image on the command line"""
3533 self._DoReadFileRealDtb('143_replace_all.dts')
3534
3535 try:
3536 tmpdir, updated_fname = self._SetupImageInTmpdir()
3537
3538 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3539 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003540 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003541
3542 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
Simon Glass80025522022-01-29 14:14:04 -07003543 data = tools.read_file(updated_fname)
Simon Glass30033c22019-07-20 12:24:15 -06003544 self.assertEqual(expected, data[:len(expected)])
3545 map_fname = os.path.join(tmpdir, 'image-updated.map')
3546 self.assertFalse(os.path.exists(map_fname))
3547 finally:
3548 shutil.rmtree(tmpdir)
3549
3550 def testReplaceCmdSome(self):
3551 """Test replacing some files fron an image on the command line"""
3552 updated_fname, outdir, expected1, expected2, expected_text = (
3553 self._SetupForReplace())
3554
3555 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3556 'u-boot2', 'text')
3557
Simon Glass80025522022-01-29 14:14:04 -07003558 tools.prepare_output_dir(None)
Simon Glass30033c22019-07-20 12:24:15 -06003559 image = Image.FromFile(updated_fname)
3560 image.LoadData()
3561 entries = image.GetEntries()
3562
3563 # This one should not change
3564 data = entries['u-boot'].data
3565 self.assertEqual(U_BOOT_DATA, data)
3566
3567 data = entries['u-boot2'].data
3568 self.assertEqual(expected2, data)
3569
3570 data = entries['text'].data
3571 self.assertEqual(expected_text, data)
3572
3573 def testReplaceMissing(self):
3574 """Test replacing entries where the file is missing"""
3575 updated_fname, outdir, expected1, expected2, expected_text = (
3576 self._SetupForReplace())
3577
3578 # Remove one of the files, to generate a warning
3579 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3580 os.remove(u_boot_fname1)
3581
3582 with test_util.capture_sys_output() as (stdout, stderr):
3583 control.ReplaceEntries(updated_fname, None, outdir, [])
3584 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass6e02f7c2020-07-09 18:39:39 -06003585 stderr.getvalue())
Simon Glass30033c22019-07-20 12:24:15 -06003586
3587 def testReplaceCmdMap(self):
3588 """Test replacing a file fron an image on the command line"""
3589 self._DoReadFileRealDtb('143_replace_all.dts')
3590
3591 try:
3592 tmpdir, updated_fname = self._SetupImageInTmpdir()
3593
3594 fname = os.path.join(self._indir, 'update-u-boot.bin')
3595 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003596 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003597
3598 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3599 '-f', fname, '-m')
3600 map_fname = os.path.join(tmpdir, 'image-updated.map')
3601 self.assertTrue(os.path.exists(map_fname))
3602 finally:
3603 shutil.rmtree(tmpdir)
3604
3605 def testReplaceNoEntryPaths(self):
3606 """Test replacing an entry without an entry path"""
3607 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003608 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003609 with self.assertRaises(ValueError) as e:
3610 control.ReplaceEntries(image_fname, 'fname', None, [])
3611 self.assertIn('Must specify an entry path to read with -f',
3612 str(e.exception))
3613
3614 def testReplaceTooManyEntryPaths(self):
3615 """Test extracting some entries"""
3616 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003617 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003618 with self.assertRaises(ValueError) as e:
3619 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3620 self.assertIn('Must specify exactly one entry path to write with -f',
3621 str(e.exception))
3622
Simon Glass0b074d62019-08-24 07:22:48 -06003623 def testPackReset16(self):
3624 """Test that an image with an x86 reset16 region can be created"""
3625 data = self._DoReadFile('144_x86_reset16.dts')
3626 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3627
3628 def testPackReset16Spl(self):
3629 """Test that an image with an x86 reset16-spl region can be created"""
3630 data = self._DoReadFile('145_x86_reset16_spl.dts')
3631 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3632
3633 def testPackReset16Tpl(self):
3634 """Test that an image with an x86 reset16-tpl region can be created"""
3635 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3636 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3637
Simon Glass232f90c2019-08-24 07:22:50 -06003638 def testPackIntelFit(self):
3639 """Test that an image with an Intel FIT and pointer can be created"""
3640 data = self._DoReadFile('147_intel_fit.dts')
3641 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3642 fit = data[16:32];
3643 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3644 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3645
3646 image = control.images['image']
3647 entries = image.GetEntries()
3648 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3649 self.assertEqual(expected_ptr, ptr)
3650
3651 def testPackIntelFitMissing(self):
3652 """Test detection of a FIT pointer with not FIT region"""
3653 with self.assertRaises(ValueError) as e:
3654 self._DoReadFile('148_intel_fit_missing.dts')
3655 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3656 str(e.exception))
3657
Simon Glass72555fa2019-11-06 17:22:44 -07003658 def _CheckSymbolsTplSection(self, dts, expected_vals):
3659 data = self._DoReadFile(dts)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003660 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE, *expected_vals)
Simon Glass3eb5b202019-08-24 07:23:00 -06003661 upto1 = 4 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003662 expected1 = tools.get_bytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003663 self.assertEqual(expected1, data[:upto1])
3664
3665 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003666 expected2 = tools.get_bytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003667 self.assertEqual(expected2, data[upto1:upto2])
3668
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003669 upto3 = 0x3c + len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003670 expected3 = tools.get_bytes(0xff, 1) + U_BOOT_DATA
Simon Glass3eb5b202019-08-24 07:23:00 -06003671 self.assertEqual(expected3, data[upto2:upto3])
3672
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003673 expected4 = sym_values + U_BOOT_TPL_DATA[24:]
Simon Glass72555fa2019-11-06 17:22:44 -07003674 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3675
3676 def testSymbolsTplSection(self):
3677 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3678 self._SetupSplElf('u_boot_binman_syms')
3679 self._SetupTplElf('u_boot_binman_syms')
3680 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003681 [0x04, 0x20, 0x10 + 0x3c, 0x04])
Simon Glass72555fa2019-11-06 17:22:44 -07003682
3683 def testSymbolsTplSectionX86(self):
3684 """Test binman can assign symbols in a section with end-at-4gb"""
3685 self._SetupSplElf('u_boot_binman_syms_x86')
3686 self._SetupTplElf('u_boot_binman_syms_x86')
3687 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003688 [0xffffff04, 0xffffff20, 0xffffff3c,
Simon Glass72555fa2019-11-06 17:22:44 -07003689 0x04])
Simon Glass3eb5b202019-08-24 07:23:00 -06003690
Simon Glass98c59572019-08-24 07:23:03 -06003691 def testPackX86RomIfwiSectiom(self):
3692 """Test that a section can be placed in an IFWI region"""
3693 self._SetupIfwi('fitimage.bin')
3694 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3695 self._CheckIfwi(data)
3696
Simon Glassba7985d2019-08-24 07:23:07 -06003697 def testPackFspM(self):
3698 """Test that an image with a FSP memory-init binary can be created"""
3699 data = self._DoReadFile('152_intel_fsp_m.dts')
3700 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3701
Simon Glass4d9086d2019-10-20 21:31:35 -06003702 def testPackFspS(self):
3703 """Test that an image with a FSP silicon-init binary can be created"""
3704 data = self._DoReadFile('153_intel_fsp_s.dts')
3705 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassba7985d2019-08-24 07:23:07 -06003706
Simon Glass9ea87b22019-10-20 21:31:36 -06003707 def testPackFspT(self):
3708 """Test that an image with a FSP temp-ram-init binary can be created"""
3709 data = self._DoReadFile('154_intel_fsp_t.dts')
3710 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3711
Simon Glass48f3aad2020-07-09 18:39:31 -06003712 def testMkimage(self):
3713 """Test using mkimage to build an image"""
3714 data = self._DoReadFile('156_mkimage.dts')
3715
3716 # Just check that the data appears in the file somewhere
3717 self.assertIn(U_BOOT_SPL_DATA, data)
3718
Simon Glass66152ce2022-01-09 20:14:09 -07003719 def testMkimageMissing(self):
3720 """Test that binman still produces an image if mkimage is missing"""
3721 with test_util.capture_sys_output() as (_, stderr):
3722 self._DoTestFile('156_mkimage.dts',
3723 force_missing_bintools='mkimage')
3724 err = stderr.getvalue()
3725 self.assertRegex(err,
3726 "Image 'main-section'.*missing bintools.*: mkimage")
3727
Simon Glass5e560182020-07-09 18:39:36 -06003728 def testExtblob(self):
3729 """Test an image with an external blob"""
3730 data = self._DoReadFile('157_blob_ext.dts')
3731 self.assertEqual(REFCODE_DATA, data)
3732
3733 def testExtblobMissing(self):
3734 """Test an image with a missing external blob"""
3735 with self.assertRaises(ValueError) as e:
3736 self._DoReadFile('158_blob_ext_missing.dts')
3737 self.assertIn("Filename 'missing-file' not found in input path",
3738 str(e.exception))
3739
Simon Glass5d94cc62020-07-09 18:39:38 -06003740 def testExtblobMissingOk(self):
3741 """Test an image with an missing external blob that is allowed"""
Simon Glassa003cd32020-07-09 18:39:40 -06003742 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass6bce5dc2022-11-09 19:14:42 -07003743 ret = self._DoTestFile('158_blob_ext_missing.dts',
3744 allow_missing=True)
3745 self.assertEqual(103, ret)
Simon Glassa003cd32020-07-09 18:39:40 -06003746 err = stderr.getvalue()
3747 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
Simon Glass6bce5dc2022-11-09 19:14:42 -07003748 self.assertIn('Some images are invalid', err)
3749
3750 def testExtblobMissingOkFlag(self):
3751 """Test an image with an missing external blob allowed with -W"""
3752 with test_util.capture_sys_output() as (stdout, stderr):
3753 ret = self._DoTestFile('158_blob_ext_missing.dts',
3754 allow_missing=True, ignore_missing=True)
3755 self.assertEqual(0, ret)
3756 err = stderr.getvalue()
3757 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
3758 self.assertIn('Some images are invalid', err)
Simon Glassa003cd32020-07-09 18:39:40 -06003759
3760 def testExtblobMissingOkSect(self):
3761 """Test an image with an missing external blob that is allowed"""
3762 with test_util.capture_sys_output() as (stdout, stderr):
3763 self._DoTestFile('159_blob_ext_missing_sect.dts',
3764 allow_missing=True)
3765 err = stderr.getvalue()
3766 self.assertRegex(err, "Image 'main-section'.*missing.*: "
3767 "blob-ext blob-ext2")
Simon Glass5d94cc62020-07-09 18:39:38 -06003768
Simon Glasse88cef92020-07-09 18:39:41 -06003769 def testPackX86RomMeMissingDesc(self):
3770 """Test that an missing Intel descriptor entry is allowed"""
Simon Glasse88cef92020-07-09 18:39:41 -06003771 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass14c596c2020-07-25 15:11:19 -06003772 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glasse88cef92020-07-09 18:39:41 -06003773 err = stderr.getvalue()
3774 self.assertRegex(err,
3775 "Image 'main-section'.*missing.*: intel-descriptor")
3776
3777 def testPackX86RomMissingIfwi(self):
3778 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3779 self._SetupIfwi('fitimage.bin')
3780 pathname = os.path.join(self._indir, 'fitimage.bin')
3781 os.remove(pathname)
3782 with test_util.capture_sys_output() as (stdout, stderr):
3783 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3784 err = stderr.getvalue()
3785 self.assertRegex(err, "Image 'main-section'.*missing.*: intel-ifwi")
3786
Simon Glass2a0fa982022-02-11 13:23:21 -07003787 def testPackOverlapZero(self):
Simon Glassd70829a2020-07-09 18:39:42 -06003788 """Test that zero-size overlapping regions are ignored"""
3789 self._DoTestFile('160_pack_overlap_zero.dts')
3790
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003791 def _CheckSimpleFitData(self, fit_data, kernel_data, fdt1_data):
Simon Glass45d556d2020-07-09 18:39:45 -06003792 # The data should be inside the FIT
3793 dtb = fdt.Fdt.FromData(fit_data)
3794 dtb.Scan()
3795 fnode = dtb.GetNode('/images/kernel')
3796 self.assertIn('data', fnode.props)
3797
3798 fname = os.path.join(self._indir, 'fit_data.fit')
Simon Glass80025522022-01-29 14:14:04 -07003799 tools.write_file(fname, fit_data)
3800 out = tools.run('dumpimage', '-l', fname)
Simon Glass45d556d2020-07-09 18:39:45 -06003801
3802 # Check a few features to make sure the plumbing works. We don't need
3803 # to test the operation of mkimage or dumpimage here. First convert the
3804 # output into a dict where the keys are the fields printed by dumpimage
3805 # and the values are a list of values for each field
3806 lines = out.splitlines()
3807
3808 # Converts "Compression: gzip compressed" into two groups:
3809 # 'Compression' and 'gzip compressed'
3810 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3811 vals = collections.defaultdict(list)
3812 for line in lines:
3813 mat = re_line.match(line)
3814 vals[mat.group(1)].append(mat.group(2))
3815
3816 self.assertEquals('FIT description: test-desc', lines[0])
3817 self.assertIn('Created:', lines[1])
3818 self.assertIn('Image 0 (kernel)', vals)
3819 self.assertIn('Hash value', vals)
3820 data_sizes = vals.get('Data Size')
3821 self.assertIsNotNone(data_sizes)
3822 self.assertEqual(2, len(data_sizes))
3823 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003824 self.assertEqual(len(kernel_data), int(data_sizes[0].split()[0]))
3825 self.assertEqual(len(fdt1_data), int(data_sizes[1].split()[0]))
3826
Alper Nebi Yasak1a0ee0f2022-03-27 18:31:47 +03003827 # Check if entry listing correctly omits /images/
3828 image = control.images['image']
3829 fit_entry = image.GetEntries()['fit']
3830 subentries = list(fit_entry.GetEntries().keys())
3831 expected = ['kernel', 'fdt-1']
3832 self.assertEqual(expected, subentries)
3833
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003834 def testSimpleFit(self):
3835 """Test an image with a FIT inside"""
3836 data = self._DoReadFile('161_fit.dts')
3837 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3838 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3839 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3840
3841 self._CheckSimpleFitData(fit_data, U_BOOT_DATA, U_BOOT_SPL_DTB_DATA)
3842
3843 def testSimpleFitExpandsSubentries(self):
3844 """Test that FIT images expand their subentries"""
3845 data = self._DoReadFileDtb('161_fit.dts', use_expanded=True)[0]
3846 self.assertEqual(U_BOOT_EXP_DATA, data[:len(U_BOOT_EXP_DATA)])
3847 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3848 fit_data = data[len(U_BOOT_EXP_DATA):-len(U_BOOT_NODTB_DATA)]
3849
3850 self._CheckSimpleFitData(fit_data, U_BOOT_EXP_DATA, U_BOOT_SPL_DTB_DATA)
Simon Glass45d556d2020-07-09 18:39:45 -06003851
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003852 def testSimpleFitImagePos(self):
3853 """Test that we have correct image-pos for FIT subentries"""
3854 data, _, _, out_dtb_fname = self._DoReadFileDtb('161_fit.dts',
3855 update_dtb=True)
3856 dtb = fdt.Fdt(out_dtb_fname)
3857 dtb.Scan()
3858 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3859
Simon Glassb7bad182022-03-05 20:19:01 -07003860 self.maxDiff = None
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003861 self.assertEqual({
3862 'image-pos': 0,
3863 'offset': 0,
3864 'size': 1890,
3865
3866 'u-boot:image-pos': 0,
3867 'u-boot:offset': 0,
3868 'u-boot:size': 4,
3869
3870 'fit:image-pos': 4,
3871 'fit:offset': 4,
3872 'fit:size': 1840,
3873
Simon Glassb7bad182022-03-05 20:19:01 -07003874 'fit/images/kernel:image-pos': 304,
3875 'fit/images/kernel:offset': 300,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003876 'fit/images/kernel:size': 4,
3877
Simon Glassb7bad182022-03-05 20:19:01 -07003878 'fit/images/kernel/u-boot:image-pos': 304,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003879 'fit/images/kernel/u-boot:offset': 0,
3880 'fit/images/kernel/u-boot:size': 4,
3881
Simon Glassb7bad182022-03-05 20:19:01 -07003882 'fit/images/fdt-1:image-pos': 552,
3883 'fit/images/fdt-1:offset': 548,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003884 'fit/images/fdt-1:size': 6,
3885
Simon Glassb7bad182022-03-05 20:19:01 -07003886 'fit/images/fdt-1/u-boot-spl-dtb:image-pos': 552,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003887 'fit/images/fdt-1/u-boot-spl-dtb:offset': 0,
3888 'fit/images/fdt-1/u-boot-spl-dtb:size': 6,
3889
3890 'u-boot-nodtb:image-pos': 1844,
3891 'u-boot-nodtb:offset': 1844,
3892 'u-boot-nodtb:size': 46,
3893 }, props)
3894
3895 # Actually check the data is where we think it is
3896 for node, expected in [
3897 ("u-boot", U_BOOT_DATA),
3898 ("fit/images/kernel", U_BOOT_DATA),
3899 ("fit/images/kernel/u-boot", U_BOOT_DATA),
3900 ("fit/images/fdt-1", U_BOOT_SPL_DTB_DATA),
3901 ("fit/images/fdt-1/u-boot-spl-dtb", U_BOOT_SPL_DTB_DATA),
3902 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
3903 ]:
3904 image_pos = props[f"{node}:image-pos"]
3905 size = props[f"{node}:size"]
3906 self.assertEqual(len(expected), size)
3907 self.assertEqual(expected, data[image_pos:image_pos+size])
3908
Simon Glass45d556d2020-07-09 18:39:45 -06003909 def testFitExternal(self):
Simon Glass31ee50f2020-09-01 05:13:55 -06003910 """Test an image with an FIT with external images"""
Simon Glass45d556d2020-07-09 18:39:45 -06003911 data = self._DoReadFile('162_fit_external.dts')
3912 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3913
Simon Glass7932c882022-01-09 20:13:39 -07003914 # Size of the external-data region as set up by mkimage
3915 external_data_size = len(U_BOOT_DATA) + 2
3916 expected_size = (len(U_BOOT_DATA) + 0x400 +
Simon Glass80025522022-01-29 14:14:04 -07003917 tools.align(external_data_size, 4) +
Simon Glass7932c882022-01-09 20:13:39 -07003918 len(U_BOOT_NODTB_DATA))
3919
Simon Glass45d556d2020-07-09 18:39:45 -06003920 # The data should be outside the FIT
3921 dtb = fdt.Fdt.FromData(fit_data)
3922 dtb.Scan()
3923 fnode = dtb.GetNode('/images/kernel')
3924 self.assertNotIn('data', fnode.props)
Simon Glass7932c882022-01-09 20:13:39 -07003925 self.assertEqual(len(U_BOOT_DATA),
3926 fdt_util.fdt32_to_cpu(fnode.props['data-size'].value))
3927 fit_pos = 0x400;
3928 self.assertEqual(
3929 fit_pos,
3930 fdt_util.fdt32_to_cpu(fnode.props['data-position'].value))
3931
3932 self.assertEquals(expected_size, len(data))
3933 actual_pos = len(U_BOOT_DATA) + fit_pos
3934 self.assertEqual(U_BOOT_DATA + b'aa',
3935 data[actual_pos:actual_pos + external_data_size])
Simon Glassfb30e292019-07-20 12:23:51 -06003936
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003937 def testFitExternalImagePos(self):
3938 """Test that we have correct image-pos for external FIT subentries"""
3939 data, _, _, out_dtb_fname = self._DoReadFileDtb('162_fit_external.dts',
3940 update_dtb=True)
3941 dtb = fdt.Fdt(out_dtb_fname)
3942 dtb.Scan()
3943 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3944
3945 self.assertEqual({
3946 'image-pos': 0,
3947 'offset': 0,
3948 'size': 1082,
3949
3950 'u-boot:image-pos': 0,
3951 'u-boot:offset': 0,
3952 'u-boot:size': 4,
3953
3954 'fit:size': 1032,
3955 'fit:offset': 4,
3956 'fit:image-pos': 4,
3957
3958 'fit/images/kernel:size': 4,
3959 'fit/images/kernel:offset': 1024,
3960 'fit/images/kernel:image-pos': 1028,
3961
3962 'fit/images/kernel/u-boot:size': 4,
3963 'fit/images/kernel/u-boot:offset': 0,
3964 'fit/images/kernel/u-boot:image-pos': 1028,
3965
3966 'fit/images/fdt-1:size': 2,
3967 'fit/images/fdt-1:offset': 1028,
3968 'fit/images/fdt-1:image-pos': 1032,
3969
3970 'fit/images/fdt-1/_testing:size': 2,
3971 'fit/images/fdt-1/_testing:offset': 0,
3972 'fit/images/fdt-1/_testing:image-pos': 1032,
3973
3974 'u-boot-nodtb:image-pos': 1036,
3975 'u-boot-nodtb:offset': 1036,
3976 'u-boot-nodtb:size': 46,
3977 }, props)
3978
3979 # Actually check the data is where we think it is
3980 for node, expected in [
3981 ("u-boot", U_BOOT_DATA),
3982 ("fit/images/kernel", U_BOOT_DATA),
3983 ("fit/images/kernel/u-boot", U_BOOT_DATA),
3984 ("fit/images/fdt-1", b'aa'),
3985 ("fit/images/fdt-1/_testing", b'aa'),
3986 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
3987 ]:
3988 image_pos = props[f"{node}:image-pos"]
3989 size = props[f"{node}:size"]
3990 self.assertEqual(len(expected), size)
3991 self.assertEqual(expected, data[image_pos:image_pos+size])
3992
Simon Glass66152ce2022-01-09 20:14:09 -07003993 def testFitMissing(self):
3994 """Test that binman still produces a FIT image if mkimage is missing"""
3995 with test_util.capture_sys_output() as (_, stderr):
3996 self._DoTestFile('162_fit_external.dts',
3997 force_missing_bintools='mkimage')
3998 err = stderr.getvalue()
3999 self.assertRegex(err,
4000 "Image 'main-section'.*missing bintools.*: mkimage")
4001
Alper Nebi Yasak6aae2392020-08-31 12:58:18 +03004002 def testSectionIgnoreHashSignature(self):
4003 """Test that sections ignore hash, signature nodes for its data"""
4004 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
4005 expected = (U_BOOT_DATA + U_BOOT_DATA)
4006 self.assertEqual(expected, data)
4007
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03004008 def testPadInSections(self):
4009 """Test pad-before, pad-after for entries in sections"""
Simon Glassd12599d2020-10-26 17:40:09 -06004010 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4011 '166_pad_in_sections.dts', update_dtb=True)
Simon Glass80025522022-01-29 14:14:04 -07004012 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4013 U_BOOT_DATA + tools.get_bytes(ord('!'), 6) +
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03004014 U_BOOT_DATA)
4015 self.assertEqual(expected, data)
4016
Simon Glassd12599d2020-10-26 17:40:09 -06004017 dtb = fdt.Fdt(out_dtb_fname)
4018 dtb.Scan()
4019 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
4020 expected = {
4021 'image-pos': 0,
4022 'offset': 0,
4023 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
4024
4025 'section:image-pos': 0,
4026 'section:offset': 0,
4027 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
4028
4029 'section/before:image-pos': 0,
4030 'section/before:offset': 0,
4031 'section/before:size': len(U_BOOT_DATA),
4032
4033 'section/u-boot:image-pos': 4,
4034 'section/u-boot:offset': 4,
4035 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
4036
4037 'section/after:image-pos': 26,
4038 'section/after:offset': 26,
4039 'section/after:size': len(U_BOOT_DATA),
4040 }
4041 self.assertEqual(expected, props)
4042
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004043 def testFitImageSubentryAlignment(self):
4044 """Test relative alignability of FIT image subentries"""
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03004045 self._SetupSplElf()
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004046 entry_args = {
4047 'test-id': TEXT_DATA,
4048 }
4049 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
4050 entry_args=entry_args)
4051 dtb = fdt.Fdt.FromData(data)
4052 dtb.Scan()
4053
4054 node = dtb.GetNode('/images/kernel')
4055 data = dtb.GetProps(node)["data"].bytes
4056 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
Simon Glass80025522022-01-29 14:14:04 -07004057 expected = (tools.get_bytes(0, 0x20) + U_BOOT_SPL_DATA +
4058 tools.get_bytes(0, align_pad) + U_BOOT_DATA)
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004059 self.assertEqual(expected, data)
4060
4061 node = dtb.GetNode('/images/fdt-1')
4062 data = dtb.GetProps(node)["data"].bytes
Simon Glass80025522022-01-29 14:14:04 -07004063 expected = (U_BOOT_SPL_DTB_DATA + tools.get_bytes(0, 20) +
4064 tools.to_bytes(TEXT_DATA) + tools.get_bytes(0, 30) +
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004065 U_BOOT_DTB_DATA)
4066 self.assertEqual(expected, data)
4067
4068 def testFitExtblobMissingOk(self):
4069 """Test a FIT with a missing external blob that is allowed"""
4070 with test_util.capture_sys_output() as (stdout, stderr):
4071 self._DoTestFile('168_fit_missing_blob.dts',
4072 allow_missing=True)
4073 err = stderr.getvalue()
Simon Glassa820af72020-09-06 10:39:09 -06004074 self.assertRegex(err, "Image 'main-section'.*missing.*: atf-bl31")
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004075
Simon Glass21db0ff2020-09-01 05:13:54 -06004076 def testBlobNamedByArgMissing(self):
4077 """Test handling of a missing entry arg"""
4078 with self.assertRaises(ValueError) as e:
4079 self._DoReadFile('068_blob_named_by_arg.dts')
4080 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
4081 str(e.exception))
4082
Simon Glass559c4de2020-09-01 05:13:58 -06004083 def testPackBl31(self):
4084 """Test that an image with an ATF BL31 binary can be created"""
4085 data = self._DoReadFile('169_atf_bl31.dts')
4086 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
4087
Samuel Holland9d8cc632020-10-21 21:12:15 -05004088 def testPackScp(self):
4089 """Test that an image with an SCP binary can be created"""
4090 data = self._DoReadFile('172_scp.dts')
4091 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
4092
Simon Glassa435cd12020-09-01 05:13:59 -06004093 def testFitFdt(self):
4094 """Test an image with an FIT with multiple FDT images"""
4095 def _CheckFdt(seq, expected_data):
4096 """Check the FDT nodes
4097
4098 Args:
4099 seq: Sequence number to check (0 or 1)
4100 expected_data: Expected contents of 'data' property
4101 """
4102 name = 'fdt-%d' % seq
4103 fnode = dtb.GetNode('/images/%s' % name)
4104 self.assertIsNotNone(fnode)
4105 self.assertEqual({'description','type', 'compression', 'data'},
4106 set(fnode.props.keys()))
4107 self.assertEqual(expected_data, fnode.props['data'].bytes)
4108 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
4109 fnode.props['description'].value)
Jan Kiszkaa1419df2022-02-28 17:06:20 +01004110 self.assertEqual(fnode.subnodes[0].name, 'hash')
Simon Glassa435cd12020-09-01 05:13:59 -06004111
4112 def _CheckConfig(seq, expected_data):
4113 """Check the configuration nodes
4114
4115 Args:
4116 seq: Sequence number to check (0 or 1)
4117 expected_data: Expected contents of 'data' property
4118 """
4119 cnode = dtb.GetNode('/configurations')
4120 self.assertIn('default', cnode.props)
Simon Glass1032acc2020-09-06 10:39:08 -06004121 self.assertEqual('config-2', cnode.props['default'].value)
Simon Glassa435cd12020-09-01 05:13:59 -06004122
4123 name = 'config-%d' % seq
4124 fnode = dtb.GetNode('/configurations/%s' % name)
4125 self.assertIsNotNone(fnode)
4126 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
4127 set(fnode.props.keys()))
4128 self.assertEqual('conf-test-fdt%d.dtb' % seq,
4129 fnode.props['description'].value)
4130 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
4131
4132 entry_args = {
4133 'of-list': 'test-fdt1 test-fdt2',
Simon Glass1032acc2020-09-06 10:39:08 -06004134 'default-dt': 'test-fdt2',
Simon Glassa435cd12020-09-01 05:13:59 -06004135 }
4136 data = self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004137 '170_fit_fdt.dts',
Simon Glassa435cd12020-09-01 05:13:59 -06004138 entry_args=entry_args,
4139 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4140 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4141 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4142
4143 dtb = fdt.Fdt.FromData(fit_data)
4144 dtb.Scan()
4145 fnode = dtb.GetNode('/images/kernel')
4146 self.assertIn('data', fnode.props)
4147
4148 # Check all the properties in fdt-1 and fdt-2
4149 _CheckFdt(1, TEST_FDT1_DATA)
4150 _CheckFdt(2, TEST_FDT2_DATA)
4151
4152 # Check configurations
4153 _CheckConfig(1, TEST_FDT1_DATA)
4154 _CheckConfig(2, TEST_FDT2_DATA)
4155
4156 def testFitFdtMissingList(self):
4157 """Test handling of a missing 'of-list' entry arg"""
4158 with self.assertRaises(ValueError) as e:
Bin Meng16cf5662021-05-10 20:23:32 +08004159 self._DoReadFile('170_fit_fdt.dts')
Simon Glassa435cd12020-09-01 05:13:59 -06004160 self.assertIn("Generator node requires 'of-list' entry argument",
4161 str(e.exception))
4162
4163 def testFitFdtEmptyList(self):
4164 """Test handling of an empty 'of-list' entry arg"""
4165 entry_args = {
4166 'of-list': '',
4167 }
4168 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
4169
4170 def testFitFdtMissingProp(self):
4171 """Test handling of a missing 'fit,fdt-list' property"""
4172 with self.assertRaises(ValueError) as e:
4173 self._DoReadFile('171_fit_fdt_missing_prop.dts')
4174 self.assertIn("Generator node requires 'fit,fdt-list' property",
4175 str(e.exception))
Simon Glass559c4de2020-09-01 05:13:58 -06004176
Simon Glass1032acc2020-09-06 10:39:08 -06004177 def testFitFdtMissing(self):
4178 """Test handling of a missing 'default-dt' entry arg"""
4179 entry_args = {
4180 'of-list': 'test-fdt1 test-fdt2',
4181 }
4182 with self.assertRaises(ValueError) as e:
4183 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004184 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004185 entry_args=entry_args,
4186 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4187 self.assertIn("Generated 'default' node requires default-dt entry argument",
4188 str(e.exception))
4189
4190 def testFitFdtNotInList(self):
4191 """Test handling of a default-dt that is not in the of-list"""
4192 entry_args = {
4193 'of-list': 'test-fdt1 test-fdt2',
4194 'default-dt': 'test-fdt3',
4195 }
4196 with self.assertRaises(ValueError) as e:
4197 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004198 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004199 entry_args=entry_args,
4200 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4201 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
4202 str(e.exception))
4203
Simon Glassa820af72020-09-06 10:39:09 -06004204 def testFitExtblobMissingHelp(self):
4205 """Test display of help messages when an external blob is missing"""
4206 control.missing_blob_help = control._ReadMissingBlobHelp()
4207 control.missing_blob_help['wibble'] = 'Wibble test'
4208 control.missing_blob_help['another'] = 'Another test'
4209 with test_util.capture_sys_output() as (stdout, stderr):
4210 self._DoTestFile('168_fit_missing_blob.dts',
4211 allow_missing=True)
4212 err = stderr.getvalue()
4213
4214 # We can get the tag from the name, the type or the missing-msg
4215 # property. Check all three.
4216 self.assertIn('You may need to build ARM Trusted', err)
4217 self.assertIn('Wibble test', err)
4218 self.assertIn('Another test', err)
4219
Simon Glass6f1f4d42020-09-06 10:35:32 -06004220 def testMissingBlob(self):
4221 """Test handling of a blob containing a missing file"""
4222 with self.assertRaises(ValueError) as e:
4223 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
4224 self.assertIn("Filename 'missing' not found in input path",
4225 str(e.exception))
4226
Simon Glassa0729502020-09-06 10:35:33 -06004227 def testEnvironment(self):
4228 """Test adding a U-Boot environment"""
4229 data = self._DoReadFile('174_env.dts')
4230 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
4231 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4232 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4233 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
4234 env)
4235
4236 def testEnvironmentNoSize(self):
4237 """Test that a missing 'size' property is detected"""
4238 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004239 self._DoTestFile('175_env_no_size.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004240 self.assertIn("'u-boot-env' entry must have a size property",
4241 str(e.exception))
4242
4243 def testEnvironmentTooSmall(self):
4244 """Test handling of an environment that does not fit"""
4245 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004246 self._DoTestFile('176_env_too_small.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004247
4248 # checksum, start byte, environment with \0 terminator, final \0
4249 need = 4 + 1 + len(ENV_DATA) + 1 + 1
4250 short = need - 0x8
4251 self.assertIn("too small to hold data (need %#x more bytes)" % short,
4252 str(e.exception))
4253
Simon Glassd1fdf752020-10-26 17:40:01 -06004254 def testSkipAtStart(self):
4255 """Test handling of skip-at-start section"""
4256 data = self._DoReadFile('177_skip_at_start.dts')
4257 self.assertEqual(U_BOOT_DATA, data)
4258
4259 image = control.images['image']
4260 entries = image.GetEntries()
4261 section = entries['section']
4262 self.assertEqual(0, section.offset)
4263 self.assertEqual(len(U_BOOT_DATA), section.size)
4264 self.assertEqual(U_BOOT_DATA, section.GetData())
4265
4266 entry = section.GetEntries()['u-boot']
4267 self.assertEqual(16, entry.offset)
4268 self.assertEqual(len(U_BOOT_DATA), entry.size)
4269 self.assertEqual(U_BOOT_DATA, entry.data)
4270
4271 def testSkipAtStartPad(self):
4272 """Test handling of skip-at-start section with padded entry"""
4273 data = self._DoReadFile('178_skip_at_start_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004274 before = tools.get_bytes(0, 8)
4275 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004276 all = before + U_BOOT_DATA + after
4277 self.assertEqual(all, data)
4278
4279 image = control.images['image']
4280 entries = image.GetEntries()
4281 section = entries['section']
4282 self.assertEqual(0, section.offset)
4283 self.assertEqual(len(all), section.size)
4284 self.assertEqual(all, section.GetData())
4285
4286 entry = section.GetEntries()['u-boot']
4287 self.assertEqual(16, entry.offset)
4288 self.assertEqual(len(all), entry.size)
4289 self.assertEqual(U_BOOT_DATA, entry.data)
4290
4291 def testSkipAtStartSectionPad(self):
4292 """Test handling of skip-at-start section with padding"""
4293 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004294 before = tools.get_bytes(0, 8)
4295 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004296 all = before + U_BOOT_DATA + after
Simon Glass510ef0f2020-10-26 17:40:13 -06004297 self.assertEqual(all, data)
Simon Glassd1fdf752020-10-26 17:40:01 -06004298
4299 image = control.images['image']
4300 entries = image.GetEntries()
4301 section = entries['section']
4302 self.assertEqual(0, section.offset)
4303 self.assertEqual(len(all), section.size)
Simon Glass72eeff12020-10-26 17:40:16 -06004304 self.assertEqual(U_BOOT_DATA, section.data)
Simon Glass510ef0f2020-10-26 17:40:13 -06004305 self.assertEqual(all, section.GetPaddedData())
Simon Glassd1fdf752020-10-26 17:40:01 -06004306
4307 entry = section.GetEntries()['u-boot']
4308 self.assertEqual(16, entry.offset)
4309 self.assertEqual(len(U_BOOT_DATA), entry.size)
4310 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassa0729502020-09-06 10:35:33 -06004311
Simon Glassbb395742020-10-26 17:40:14 -06004312 def testSectionPad(self):
4313 """Testing padding with sections"""
4314 data = self._DoReadFile('180_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004315 expected = (tools.get_bytes(ord('&'), 3) +
4316 tools.get_bytes(ord('!'), 5) +
Simon Glassbb395742020-10-26 17:40:14 -06004317 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004318 tools.get_bytes(ord('!'), 1) +
4319 tools.get_bytes(ord('&'), 2))
Simon Glassbb395742020-10-26 17:40:14 -06004320 self.assertEqual(expected, data)
4321
4322 def testSectionAlign(self):
4323 """Testing alignment with sections"""
4324 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4325 expected = (b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004326 tools.get_bytes(ord('&'), 1) + # padding to section align
Simon Glassbb395742020-10-26 17:40:14 -06004327 b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004328 tools.get_bytes(ord('!'), 3) + # padding to u-boot align
Simon Glassbb395742020-10-26 17:40:14 -06004329 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004330 tools.get_bytes(ord('!'), 4) + # padding to u-boot size
4331 tools.get_bytes(ord('!'), 4)) # padding to section size
Simon Glassbb395742020-10-26 17:40:14 -06004332 self.assertEqual(expected, data)
4333
Simon Glassd92c8362020-10-26 17:40:25 -06004334 def testCompressImage(self):
4335 """Test compression of the entire image"""
4336 self._CheckLz4()
4337 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4338 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4339 dtb = fdt.Fdt(out_dtb_fname)
4340 dtb.Scan()
4341 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4342 'uncomp-size'])
4343 orig = self._decompress(data)
4344 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4345
4346 # Do a sanity check on various fields
4347 image = control.images['image']
4348 entries = image.GetEntries()
4349 self.assertEqual(2, len(entries))
4350
4351 entry = entries['blob']
4352 self.assertEqual(COMPRESS_DATA, entry.data)
4353 self.assertEqual(len(COMPRESS_DATA), entry.size)
4354
4355 entry = entries['u-boot']
4356 self.assertEqual(U_BOOT_DATA, entry.data)
4357 self.assertEqual(len(U_BOOT_DATA), entry.size)
4358
4359 self.assertEqual(len(data), image.size)
4360 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4361 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4362 orig = self._decompress(image.data)
4363 self.assertEqual(orig, image.uncomp_data)
4364
4365 expected = {
4366 'blob:offset': 0,
4367 'blob:size': len(COMPRESS_DATA),
4368 'u-boot:offset': len(COMPRESS_DATA),
4369 'u-boot:size': len(U_BOOT_DATA),
4370 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4371 'offset': 0,
4372 'image-pos': 0,
4373 'size': len(data),
4374 }
4375 self.assertEqual(expected, props)
4376
4377 def testCompressImageLess(self):
4378 """Test compression where compression reduces the image size"""
4379 self._CheckLz4()
4380 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4381 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4382 dtb = fdt.Fdt(out_dtb_fname)
4383 dtb.Scan()
4384 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4385 'uncomp-size'])
4386 orig = self._decompress(data)
4387
4388 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
4389
4390 # Do a sanity check on various fields
4391 image = control.images['image']
4392 entries = image.GetEntries()
4393 self.assertEqual(2, len(entries))
4394
4395 entry = entries['blob']
4396 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4397 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4398
4399 entry = entries['u-boot']
4400 self.assertEqual(U_BOOT_DATA, entry.data)
4401 self.assertEqual(len(U_BOOT_DATA), entry.size)
4402
4403 self.assertEqual(len(data), image.size)
4404 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4405 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4406 image.uncomp_size)
4407 orig = self._decompress(image.data)
4408 self.assertEqual(orig, image.uncomp_data)
4409
4410 expected = {
4411 'blob:offset': 0,
4412 'blob:size': len(COMPRESS_DATA_BIG),
4413 'u-boot:offset': len(COMPRESS_DATA_BIG),
4414 'u-boot:size': len(U_BOOT_DATA),
4415 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4416 'offset': 0,
4417 'image-pos': 0,
4418 'size': len(data),
4419 }
4420 self.assertEqual(expected, props)
4421
4422 def testCompressSectionSize(self):
4423 """Test compression of a section with a fixed size"""
4424 self._CheckLz4()
4425 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4426 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4427 dtb = fdt.Fdt(out_dtb_fname)
4428 dtb.Scan()
4429 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4430 'uncomp-size'])
4431 orig = self._decompress(data)
4432 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4433 expected = {
4434 'section/blob:offset': 0,
4435 'section/blob:size': len(COMPRESS_DATA),
4436 'section/u-boot:offset': len(COMPRESS_DATA),
4437 'section/u-boot:size': len(U_BOOT_DATA),
4438 'section:offset': 0,
4439 'section:image-pos': 0,
4440 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4441 'section:size': 0x30,
4442 'offset': 0,
4443 'image-pos': 0,
4444 'size': 0x30,
4445 }
4446 self.assertEqual(expected, props)
4447
4448 def testCompressSection(self):
4449 """Test compression of a section with no fixed size"""
4450 self._CheckLz4()
4451 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4452 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4453 dtb = fdt.Fdt(out_dtb_fname)
4454 dtb.Scan()
4455 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4456 'uncomp-size'])
4457 orig = self._decompress(data)
4458 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4459 expected = {
4460 'section/blob:offset': 0,
4461 'section/blob:size': len(COMPRESS_DATA),
4462 'section/u-boot:offset': len(COMPRESS_DATA),
4463 'section/u-boot:size': len(U_BOOT_DATA),
4464 'section:offset': 0,
4465 'section:image-pos': 0,
4466 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4467 'section:size': len(data),
4468 'offset': 0,
4469 'image-pos': 0,
4470 'size': len(data),
4471 }
4472 self.assertEqual(expected, props)
4473
Stefan Herbrechtsmeier94813a02022-08-19 16:25:31 +02004474 def testLz4Missing(self):
4475 """Test that binman still produces an image if lz4 is missing"""
4476 with test_util.capture_sys_output() as (_, stderr):
4477 self._DoTestFile('185_compress_section.dts',
4478 force_missing_bintools='lz4')
4479 err = stderr.getvalue()
4480 self.assertRegex(err,
4481 "Image 'main-section'.*missing bintools.*: lz4")
4482
Simon Glassd92c8362020-10-26 17:40:25 -06004483 def testCompressExtra(self):
4484 """Test compression of a section with no fixed size"""
4485 self._CheckLz4()
4486 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4487 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4488 dtb = fdt.Fdt(out_dtb_fname)
4489 dtb.Scan()
4490 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4491 'uncomp-size'])
4492
4493 base = data[len(U_BOOT_DATA):]
4494 self.assertEquals(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
4495 rest = base[len(U_BOOT_DATA):]
4496
4497 # Check compressed data
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02004498 bintool = self.comp_bintools['lz4']
4499 expect1 = bintool.compress(COMPRESS_DATA + U_BOOT_DATA)
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004500 data1 = rest[:len(expect1)]
4501 section1 = self._decompress(data1)
4502 self.assertEquals(expect1, data1)
Simon Glassd92c8362020-10-26 17:40:25 -06004503 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, section1)
4504 rest1 = rest[len(expect1):]
4505
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02004506 expect2 = bintool.compress(COMPRESS_DATA + COMPRESS_DATA)
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004507 data2 = rest1[:len(expect2)]
4508 section2 = self._decompress(data2)
4509 self.assertEquals(expect2, data2)
Simon Glassd92c8362020-10-26 17:40:25 -06004510 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA, section2)
4511 rest2 = rest1[len(expect2):]
4512
4513 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4514 len(expect2) + len(U_BOOT_DATA))
4515 #self.assertEquals(expect_size, len(data))
4516
4517 #self.assertEquals(U_BOOT_DATA, rest2)
4518
4519 self.maxDiff = None
4520 expected = {
4521 'u-boot:offset': 0,
4522 'u-boot:image-pos': 0,
4523 'u-boot:size': len(U_BOOT_DATA),
4524
4525 'base:offset': len(U_BOOT_DATA),
4526 'base:image-pos': len(U_BOOT_DATA),
4527 'base:size': len(data) - len(U_BOOT_DATA),
4528 'base/u-boot:offset': 0,
4529 'base/u-boot:image-pos': len(U_BOOT_DATA),
4530 'base/u-boot:size': len(U_BOOT_DATA),
4531 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4532 len(expect2),
4533 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4534 len(expect2),
4535 'base/u-boot2:size': len(U_BOOT_DATA),
4536
4537 'base/section:offset': len(U_BOOT_DATA),
4538 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4539 'base/section:size': len(expect1),
4540 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4541 'base/section/blob:offset': 0,
4542 'base/section/blob:size': len(COMPRESS_DATA),
4543 'base/section/u-boot:offset': len(COMPRESS_DATA),
4544 'base/section/u-boot:size': len(U_BOOT_DATA),
4545
4546 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4547 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4548 'base/section2:size': len(expect2),
4549 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4550 'base/section2/blob:offset': 0,
4551 'base/section2/blob:size': len(COMPRESS_DATA),
4552 'base/section2/blob2:offset': len(COMPRESS_DATA),
4553 'base/section2/blob2:size': len(COMPRESS_DATA),
4554
4555 'offset': 0,
4556 'image-pos': 0,
4557 'size': len(data),
4558 }
4559 self.assertEqual(expected, props)
4560
Simon Glassecbe4732021-01-06 21:35:15 -07004561 def testSymbolsSubsection(self):
4562 """Test binman can assign symbols from a subsection"""
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03004563 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glassecbe4732021-01-06 21:35:15 -07004564
Simon Glass3fb25402021-01-06 21:35:16 -07004565 def testReadImageEntryArg(self):
4566 """Test reading an image that would need an entry arg to generate"""
4567 entry_args = {
4568 'cros-ec-rw-path': 'ecrw.bin',
4569 }
4570 data = self.data = self._DoReadFileDtb(
4571 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4572 entry_args=entry_args)
4573
Simon Glass80025522022-01-29 14:14:04 -07004574 image_fname = tools.get_output_filename('image.bin')
Simon Glass3fb25402021-01-06 21:35:16 -07004575 orig_image = control.images['image']
4576
4577 # This should not generate an error about the missing 'cros-ec-rw-path'
4578 # since we are reading the image from a file. Compare with
4579 # testEntryArgsRequired()
4580 image = Image.FromFile(image_fname)
4581 self.assertEqual(orig_image.GetEntries().keys(),
4582 image.GetEntries().keys())
4583
Simon Glassa2af7302021-01-06 21:35:18 -07004584 def testFilesAlign(self):
4585 """Test alignment with files"""
4586 data = self._DoReadFile('190_files_align.dts')
4587
4588 # The first string is 15 bytes so will align to 16
4589 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4590 self.assertEqual(expect, data)
4591
Simon Glassdb84b562021-01-06 21:35:19 -07004592 def testReadImageSkip(self):
4593 """Test reading an image and accessing its FDT map"""
4594 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
Simon Glass80025522022-01-29 14:14:04 -07004595 image_fname = tools.get_output_filename('image.bin')
Simon Glassdb84b562021-01-06 21:35:19 -07004596 orig_image = control.images['image']
4597 image = Image.FromFile(image_fname)
4598 self.assertEqual(orig_image.GetEntries().keys(),
4599 image.GetEntries().keys())
4600
4601 orig_entry = orig_image.GetEntries()['fdtmap']
4602 entry = image.GetEntries()['fdtmap']
4603 self.assertEqual(orig_entry.offset, entry.offset)
4604 self.assertEqual(orig_entry.size, entry.size)
4605 self.assertEqual(16, entry.image_pos)
4606
4607 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4608
4609 self.assertEquals(U_BOOT_DATA, u_boot.ReadData())
4610
Simon Glassc98de972021-03-18 20:24:57 +13004611 def testTplNoDtb(self):
4612 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12004613 self._SetupTplElf()
Simon Glassc98de972021-03-18 20:24:57 +13004614 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4615 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4616 data[:len(U_BOOT_TPL_NODTB_DATA)])
4617
Simon Glass63f41d42021-03-18 20:24:58 +13004618 def testTplBssPad(self):
4619 """Test that we can pad TPL's BSS with zeros"""
4620 # ELF file with a '__bss_size' symbol
4621 self._SetupTplElf()
4622 data = self._DoReadFile('193_tpl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004623 self.assertEqual(U_BOOT_TPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glass63f41d42021-03-18 20:24:58 +13004624 data)
4625
4626 def testTplBssPadMissing(self):
4627 """Test that a missing symbol is detected"""
4628 self._SetupTplElf('u_boot_ucode_ptr')
4629 with self.assertRaises(ValueError) as e:
4630 self._DoReadFile('193_tpl_bss_pad.dts')
4631 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4632 str(e.exception))
4633
Simon Glass718b5292021-03-18 20:25:07 +13004634 def checkDtbSizes(self, data, pad_len, start):
4635 """Check the size arguments in a dtb embedded in an image
4636
4637 Args:
4638 data: The image data
4639 pad_len: Length of the pad section in the image, in bytes
4640 start: Start offset of the devicetree to examine, within the image
4641
4642 Returns:
4643 Size of the devicetree in bytes
4644 """
4645 dtb_data = data[start:]
4646 dtb = fdt.Fdt.FromData(dtb_data)
4647 fdt_size = dtb.GetFdtObj().totalsize()
4648 dtb.Scan()
4649 props = self._GetPropTree(dtb, 'size')
4650 self.assertEqual({
4651 'size': len(data),
4652 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4653 'u-boot-spl/u-boot-spl-dtb:size': 801,
4654 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4655 'u-boot-spl:size': 860,
4656 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4657 'u-boot/u-boot-dtb:size': 781,
4658 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4659 'u-boot:size': 827,
4660 }, props)
4661 return fdt_size
4662
4663 def testExpanded(self):
4664 """Test that an expanded entry type is selected when needed"""
4665 self._SetupSplElf()
4666 self._SetupTplElf()
4667
4668 # SPL has a devicetree, TPL does not
4669 entry_args = {
4670 'spl-dtb': '1',
4671 'spl-bss-pad': 'y',
4672 'tpl-dtb': '',
4673 }
4674 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4675 entry_args=entry_args)
4676 image = control.images['image']
4677 entries = image.GetEntries()
4678 self.assertEqual(3, len(entries))
4679
4680 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4681 self.assertIn('u-boot', entries)
4682 entry = entries['u-boot']
4683 self.assertEqual('u-boot-expanded', entry.etype)
4684 subent = entry.GetEntries()
4685 self.assertEqual(2, len(subent))
4686 self.assertIn('u-boot-nodtb', subent)
4687 self.assertIn('u-boot-dtb', subent)
4688
4689 # Second, u-boot-spl, which should be expanded into three parts
4690 self.assertIn('u-boot-spl', entries)
4691 entry = entries['u-boot-spl']
4692 self.assertEqual('u-boot-spl-expanded', entry.etype)
4693 subent = entry.GetEntries()
4694 self.assertEqual(3, len(subent))
4695 self.assertIn('u-boot-spl-nodtb', subent)
4696 self.assertIn('u-boot-spl-bss-pad', subent)
4697 self.assertIn('u-boot-spl-dtb', subent)
4698
4699 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4700 # devicetree
4701 self.assertIn('u-boot-tpl', entries)
4702 entry = entries['u-boot-tpl']
4703 self.assertEqual('u-boot-tpl', entry.etype)
4704 self.assertEqual(None, entry.GetEntries())
4705
4706 def testExpandedTpl(self):
4707 """Test that an expanded entry type is selected for TPL when needed"""
4708 self._SetupTplElf()
4709
4710 entry_args = {
4711 'tpl-bss-pad': 'y',
4712 'tpl-dtb': 'y',
4713 }
4714 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4715 entry_args=entry_args)
4716 image = control.images['image']
4717 entries = image.GetEntries()
4718 self.assertEqual(1, len(entries))
4719
4720 # We only have u-boot-tpl, which be expanded
4721 self.assertIn('u-boot-tpl', entries)
4722 entry = entries['u-boot-tpl']
4723 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4724 subent = entry.GetEntries()
4725 self.assertEqual(3, len(subent))
4726 self.assertIn('u-boot-tpl-nodtb', subent)
4727 self.assertIn('u-boot-tpl-bss-pad', subent)
4728 self.assertIn('u-boot-tpl-dtb', subent)
4729
4730 def testExpandedNoPad(self):
4731 """Test an expanded entry without BSS pad enabled"""
4732 self._SetupSplElf()
4733 self._SetupTplElf()
4734
4735 # SPL has a devicetree, TPL does not
4736 entry_args = {
4737 'spl-dtb': 'something',
4738 'spl-bss-pad': 'n',
4739 'tpl-dtb': '',
4740 }
4741 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4742 entry_args=entry_args)
4743 image = control.images['image']
4744 entries = image.GetEntries()
4745
4746 # Just check u-boot-spl, which should be expanded into two parts
4747 self.assertIn('u-boot-spl', entries)
4748 entry = entries['u-boot-spl']
4749 self.assertEqual('u-boot-spl-expanded', entry.etype)
4750 subent = entry.GetEntries()
4751 self.assertEqual(2, len(subent))
4752 self.assertIn('u-boot-spl-nodtb', subent)
4753 self.assertIn('u-boot-spl-dtb', subent)
4754
4755 def testExpandedTplNoPad(self):
4756 """Test that an expanded entry type with padding disabled in TPL"""
4757 self._SetupTplElf()
4758
4759 entry_args = {
4760 'tpl-bss-pad': '',
4761 'tpl-dtb': 'y',
4762 }
4763 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4764 entry_args=entry_args)
4765 image = control.images['image']
4766 entries = image.GetEntries()
4767 self.assertEqual(1, len(entries))
4768
4769 # We only have u-boot-tpl, which be expanded
4770 self.assertIn('u-boot-tpl', entries)
4771 entry = entries['u-boot-tpl']
4772 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4773 subent = entry.GetEntries()
4774 self.assertEqual(2, len(subent))
4775 self.assertIn('u-boot-tpl-nodtb', subent)
4776 self.assertIn('u-boot-tpl-dtb', subent)
4777
4778 def testFdtInclude(self):
4779 """Test that an Fdt is update within all binaries"""
4780 self._SetupSplElf()
4781 self._SetupTplElf()
4782
4783 # SPL has a devicetree, TPL does not
4784 self.maxDiff = None
4785 entry_args = {
4786 'spl-dtb': '1',
4787 'spl-bss-pad': 'y',
4788 'tpl-dtb': '',
4789 }
4790 # Build the image. It includes two separate devicetree binaries, each
4791 # with their own contents, but all contain the binman definition.
4792 data = self._DoReadFileDtb(
4793 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4794 update_dtb=True, entry_args=entry_args)[0]
4795 pad_len = 10
4796
4797 # Check the U-Boot dtb
4798 start = len(U_BOOT_NODTB_DATA)
4799 fdt_size = self.checkDtbSizes(data, pad_len, start)
4800
4801 # Now check SPL
4802 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4803 fdt_size = self.checkDtbSizes(data, pad_len, start)
4804
4805 # TPL has no devicetree
4806 start += fdt_size + len(U_BOOT_TPL_DATA)
4807 self.assertEqual(len(data), start)
Simon Glassbb395742020-10-26 17:40:14 -06004808
Simon Glass7098b7f2021-03-21 18:24:30 +13004809 def testSymbolsExpanded(self):
4810 """Test binman can assign symbols in expanded entries"""
4811 entry_args = {
4812 'spl-dtb': '1',
4813 }
4814 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4815 U_BOOT_SPL_DTB_DATA, 0x38,
4816 entry_args=entry_args, use_expanded=True)
4817
Simon Glasse1915782021-03-21 18:24:31 +13004818 def testCollection(self):
4819 """Test a collection"""
4820 data = self._DoReadFile('198_collection.dts')
4821 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004822 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
4823 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
Simon Glasse1915782021-03-21 18:24:31 +13004824 data)
4825
Simon Glass27a7f772021-03-21 18:24:32 +13004826 def testCollectionSection(self):
4827 """Test a collection where a section must be built first"""
4828 # Sections never have their contents when GetData() is called, but when
Simon Glass7e3f89f2021-11-23 11:03:47 -07004829 # BuildSectionData() is called with required=True, a section will force
Simon Glass27a7f772021-03-21 18:24:32 +13004830 # building the contents, producing an error is anything is still
4831 # missing.
4832 data = self._DoReadFile('199_collection_section.dts')
4833 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
Simon Glass80025522022-01-29 14:14:04 -07004834 self.assertEqual(section + U_BOOT_DATA + tools.get_bytes(0xff, 2) +
4835 section + tools.get_bytes(0xfe, 3) + U_BOOT_DATA,
Simon Glass27a7f772021-03-21 18:24:32 +13004836 data)
4837
Simon Glassf427c5f2021-03-21 18:24:33 +13004838 def testAlignDefault(self):
4839 """Test that default alignment works on sections"""
4840 data = self._DoReadFile('200_align_default.dts')
Simon Glass80025522022-01-29 14:14:04 -07004841 expected = (U_BOOT_DATA + tools.get_bytes(0, 8 - len(U_BOOT_DATA)) +
Simon Glassf427c5f2021-03-21 18:24:33 +13004842 U_BOOT_DATA)
4843 # Special alignment for section
Simon Glass80025522022-01-29 14:14:04 -07004844 expected += tools.get_bytes(0, 32 - len(expected))
Simon Glassf427c5f2021-03-21 18:24:33 +13004845 # No alignment within the nested section
4846 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
4847 # Now the final piece, which should be default-aligned
Simon Glass80025522022-01-29 14:14:04 -07004848 expected += tools.get_bytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
Simon Glassf427c5f2021-03-21 18:24:33 +13004849 self.assertEqual(expected, data)
Simon Glass27a7f772021-03-21 18:24:32 +13004850
Bin Mengc0b15742021-05-10 20:23:33 +08004851 def testPackOpenSBI(self):
4852 """Test that an image with an OpenSBI binary can be created"""
4853 data = self._DoReadFile('201_opensbi.dts')
4854 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
4855
Simon Glass76f496d2021-07-06 10:36:37 -06004856 def testSectionsSingleThread(self):
4857 """Test sections without multithreading"""
4858 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
Simon Glass80025522022-01-29 14:14:04 -07004859 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4860 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
4861 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glass76f496d2021-07-06 10:36:37 -06004862 self.assertEqual(expected, data)
4863
4864 def testThreadTimeout(self):
4865 """Test handling a thread that takes too long"""
4866 with self.assertRaises(ValueError) as e:
4867 self._DoTestFile('202_section_timeout.dts',
4868 test_section_timeout=True)
Simon Glass2d59d152021-10-18 12:13:15 -06004869 self.assertIn("Timed out obtaining contents", str(e.exception))
Simon Glass76f496d2021-07-06 10:36:37 -06004870
Simon Glass748a1d42021-07-06 10:36:41 -06004871 def testTiming(self):
4872 """Test output of timing information"""
4873 data = self._DoReadFile('055_sections.dts')
4874 with test_util.capture_sys_output() as (stdout, stderr):
4875 state.TimingShow()
4876 self.assertIn('read:', stdout.getvalue())
4877 self.assertIn('compress:', stdout.getvalue())
4878
Simon Glassadfb8492021-11-03 21:09:18 -06004879 def testUpdateFdtInElf(self):
4880 """Test that we can update the devicetree in an ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02004881 if not elf.ELF_TOOLS:
4882 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06004883 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4884 outfile = os.path.join(self._indir, 'u-boot.out')
4885 begin_sym = 'dtb_embed_begin'
4886 end_sym = 'dtb_embed_end'
4887 retcode = self._DoTestFile(
4888 '060_fdt_update.dts', update_dtb=True,
4889 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4890 self.assertEqual(0, retcode)
4891
4892 # Check that the output file does in fact contact a dtb with the binman
4893 # definition in the correct place
4894 syms = elf.GetSymbolFileOffset(infile,
4895 ['dtb_embed_begin', 'dtb_embed_end'])
Simon Glass80025522022-01-29 14:14:04 -07004896 data = tools.read_file(outfile)
Simon Glassadfb8492021-11-03 21:09:18 -06004897 dtb_data = data[syms['dtb_embed_begin'].offset:
4898 syms['dtb_embed_end'].offset]
4899
4900 dtb = fdt.Fdt.FromData(dtb_data)
4901 dtb.Scan()
4902 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4903 self.assertEqual({
4904 'image-pos': 0,
4905 'offset': 0,
4906 '_testing:offset': 32,
4907 '_testing:size': 2,
4908 '_testing:image-pos': 32,
4909 'section@0/u-boot:offset': 0,
4910 'section@0/u-boot:size': len(U_BOOT_DATA),
4911 'section@0/u-boot:image-pos': 0,
4912 'section@0:offset': 0,
4913 'section@0:size': 16,
4914 'section@0:image-pos': 0,
4915
4916 'section@1/u-boot:offset': 0,
4917 'section@1/u-boot:size': len(U_BOOT_DATA),
4918 'section@1/u-boot:image-pos': 16,
4919 'section@1:offset': 16,
4920 'section@1:size': 16,
4921 'section@1:image-pos': 16,
4922 'size': 40
4923 }, props)
4924
4925 def testUpdateFdtInElfInvalid(self):
4926 """Test that invalid args are detected with --update-fdt-in-elf"""
4927 with self.assertRaises(ValueError) as e:
4928 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
4929 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
4930 str(e.exception))
4931
4932 def testUpdateFdtInElfNoSyms(self):
4933 """Test that missing symbols are detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02004934 if not elf.ELF_TOOLS:
4935 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06004936 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4937 outfile = ''
4938 begin_sym = 'wrong_begin'
4939 end_sym = 'wrong_end'
4940 with self.assertRaises(ValueError) as e:
4941 self._DoTestFile(
4942 '060_fdt_update.dts',
4943 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4944 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
4945 str(e.exception))
4946
4947 def testUpdateFdtInElfTooSmall(self):
4948 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02004949 if not elf.ELF_TOOLS:
4950 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06004951 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
4952 outfile = os.path.join(self._indir, 'u-boot.out')
4953 begin_sym = 'dtb_embed_begin'
4954 end_sym = 'dtb_embed_end'
4955 with self.assertRaises(ValueError) as e:
4956 self._DoTestFile(
4957 '060_fdt_update.dts', update_dtb=True,
4958 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4959 self.assertRegex(
4960 str(e.exception),
4961 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
4962
Simon Glass88e04da2021-11-23 11:03:42 -07004963 def testVersion(self):
4964 """Test we can get the binman version"""
4965 version = '(unreleased)'
4966 self.assertEqual(version, state.GetVersion(self._indir))
4967
4968 with self.assertRaises(SystemExit):
4969 with test_util.capture_sys_output() as (_, stderr):
4970 self._DoBinman('-V')
4971 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
4972
4973 # Try running the tool too, just to be safe
4974 result = self._RunBinman('-V')
4975 self.assertEqual('Binman %s\n' % version, result.stderr)
4976
4977 # Set up a version file to make sure that works
4978 version = 'v2025.01-rc2'
Simon Glass80025522022-01-29 14:14:04 -07004979 tools.write_file(os.path.join(self._indir, 'version'), version,
Simon Glass88e04da2021-11-23 11:03:42 -07004980 binary=False)
4981 self.assertEqual(version, state.GetVersion(self._indir))
4982
Simon Glass637958f2021-11-23 21:09:50 -07004983 def testAltFormat(self):
4984 """Test that alternative formats can be used to extract"""
4985 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
4986
4987 try:
4988 tmpdir, updated_fname = self._SetupImageInTmpdir()
4989 with test_util.capture_sys_output() as (stdout, _):
4990 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
4991 self.assertEqual(
4992 '''Flag (-F) Entry type Description
4993fdt fdtmap Extract the devicetree blob from the fdtmap
4994''',
4995 stdout.getvalue())
4996
4997 dtb = os.path.join(tmpdir, 'fdt.dtb')
4998 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
4999 dtb, 'fdtmap')
5000
5001 # Check that we can read it and it can be scanning, meaning it does
5002 # not have a 16-byte fdtmap header
Simon Glass80025522022-01-29 14:14:04 -07005003 data = tools.read_file(dtb)
Simon Glass637958f2021-11-23 21:09:50 -07005004 dtb = fdt.Fdt.FromData(data)
5005 dtb.Scan()
5006
5007 # Now check u-boot which has no alt_format
5008 fname = os.path.join(tmpdir, 'fdt.dtb')
5009 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
5010 '-f', fname, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07005011 data = tools.read_file(fname)
Simon Glass637958f2021-11-23 21:09:50 -07005012 self.assertEqual(U_BOOT_DATA, data)
5013
5014 finally:
5015 shutil.rmtree(tmpdir)
5016
Simon Glass0b00ae62021-11-23 21:09:52 -07005017 def testExtblobList(self):
5018 """Test an image with an external blob list"""
5019 data = self._DoReadFile('215_blob_ext_list.dts')
5020 self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
5021
5022 def testExtblobListMissing(self):
5023 """Test an image with a missing external blob"""
5024 with self.assertRaises(ValueError) as e:
5025 self._DoReadFile('216_blob_ext_list_missing.dts')
5026 self.assertIn("Filename 'missing-file' not found in input path",
5027 str(e.exception))
5028
5029 def testExtblobListMissingOk(self):
5030 """Test an image with an missing external blob that is allowed"""
5031 with test_util.capture_sys_output() as (stdout, stderr):
5032 self._DoTestFile('216_blob_ext_list_missing.dts',
5033 allow_missing=True)
5034 err = stderr.getvalue()
5035 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
5036
Simon Glass3efb2972021-11-23 21:08:59 -07005037 def testFip(self):
5038 """Basic test of generation of an ARM Firmware Image Package (FIP)"""
5039 data = self._DoReadFile('203_fip.dts')
5040 hdr, fents = fip_util.decode_fip(data)
5041 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5042 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5043 self.assertEqual(0x123, hdr.flags)
5044
5045 self.assertEqual(2, len(fents))
5046
5047 fent = fents[0]
5048 self.assertEqual(
5049 bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
5050 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
5051 self.assertEqual('soc-fw', fent.fip_type)
5052 self.assertEqual(0x88, fent.offset)
5053 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5054 self.assertEqual(0x123456789abcdef, fent.flags)
5055 self.assertEqual(ATF_BL31_DATA, fent.data)
5056 self.assertEqual(True, fent.valid)
5057
5058 fent = fents[1]
5059 self.assertEqual(
5060 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
5061 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
5062 self.assertEqual('scp-fwu-cfg', fent.fip_type)
5063 self.assertEqual(0x8c, fent.offset)
5064 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5065 self.assertEqual(0, fent.flags)
5066 self.assertEqual(ATF_BL2U_DATA, fent.data)
5067 self.assertEqual(True, fent.valid)
5068
5069 def testFipOther(self):
5070 """Basic FIP with something that isn't a external blob"""
5071 data = self._DoReadFile('204_fip_other.dts')
5072 hdr, fents = fip_util.decode_fip(data)
5073
5074 self.assertEqual(2, len(fents))
5075 fent = fents[1]
5076 self.assertEqual('rot-cert', fent.fip_type)
5077 self.assertEqual(b'aa', fent.data)
5078
Simon Glass3efb2972021-11-23 21:08:59 -07005079 def testFipNoType(self):
5080 """FIP with an entry of an unknown type"""
5081 with self.assertRaises(ValueError) as e:
5082 self._DoReadFile('205_fip_no_type.dts')
5083 self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
5084 str(e.exception))
5085
5086 def testFipUuid(self):
5087 """Basic FIP with a manual uuid"""
5088 data = self._DoReadFile('206_fip_uuid.dts')
5089 hdr, fents = fip_util.decode_fip(data)
5090
5091 self.assertEqual(2, len(fents))
5092 fent = fents[1]
5093 self.assertEqual(None, fent.fip_type)
5094 self.assertEqual(
5095 bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
5096 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
5097 fent.uuid)
5098 self.assertEqual(U_BOOT_DATA, fent.data)
5099
5100 def testFipLs(self):
5101 """Test listing a FIP"""
5102 data = self._DoReadFileRealDtb('207_fip_ls.dts')
5103 hdr, fents = fip_util.decode_fip(data)
5104
5105 try:
5106 tmpdir, updated_fname = self._SetupImageInTmpdir()
5107 with test_util.capture_sys_output() as (stdout, stderr):
5108 self._DoBinman('ls', '-i', updated_fname)
5109 finally:
5110 shutil.rmtree(tmpdir)
5111 lines = stdout.getvalue().splitlines()
5112 expected = [
5113'Name Image-pos Size Entry-type Offset Uncomp-size',
5114'----------------------------------------------------------------',
5115'main-section 0 2d3 section 0',
5116' atf-fip 0 90 atf-fip 0',
5117' soc-fw 88 4 blob-ext 88',
5118' u-boot 8c 4 u-boot 8c',
5119' fdtmap 90 243 fdtmap 90',
5120]
5121 self.assertEqual(expected, lines)
5122
5123 image = control.images['image']
5124 entries = image.GetEntries()
5125 fdtmap = entries['fdtmap']
5126
5127 fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
5128 magic = fdtmap_data[:8]
5129 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07005130 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass3efb2972021-11-23 21:08:59 -07005131
5132 fdt_data = fdtmap_data[16:]
5133 dtb = fdt.Fdt.FromData(fdt_data)
5134 dtb.Scan()
5135 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
5136 self.assertEqual({
5137 'atf-fip/soc-fw:image-pos': 136,
5138 'atf-fip/soc-fw:offset': 136,
5139 'atf-fip/soc-fw:size': 4,
5140 'atf-fip/u-boot:image-pos': 140,
5141 'atf-fip/u-boot:offset': 140,
5142 'atf-fip/u-boot:size': 4,
5143 'atf-fip:image-pos': 0,
5144 'atf-fip:offset': 0,
5145 'atf-fip:size': 144,
5146 'image-pos': 0,
5147 'offset': 0,
5148 'fdtmap:image-pos': fdtmap.image_pos,
5149 'fdtmap:offset': fdtmap.offset,
5150 'fdtmap:size': len(fdtmap_data),
5151 'size': len(data),
5152 }, props)
5153
5154 def testFipExtractOneEntry(self):
5155 """Test extracting a single entry fron an FIP"""
5156 self._DoReadFileRealDtb('207_fip_ls.dts')
Simon Glass80025522022-01-29 14:14:04 -07005157 image_fname = tools.get_output_filename('image.bin')
Simon Glass3efb2972021-11-23 21:08:59 -07005158 fname = os.path.join(self._indir, 'output.extact')
5159 control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07005160 data = tools.read_file(fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005161 self.assertEqual(U_BOOT_DATA, data)
5162
5163 def testFipReplace(self):
5164 """Test replacing a single file in a FIP"""
Simon Glass80025522022-01-29 14:14:04 -07005165 expected = U_BOOT_DATA + tools.get_bytes(0x78, 50)
Simon Glass3efb2972021-11-23 21:08:59 -07005166 data = self._DoReadFileRealDtb('208_fip_replace.dts')
Simon Glass80025522022-01-29 14:14:04 -07005167 updated_fname = tools.get_output_filename('image-updated.bin')
5168 tools.write_file(updated_fname, data)
Simon Glass3efb2972021-11-23 21:08:59 -07005169 entry_name = 'atf-fip/u-boot'
5170 control.WriteEntry(updated_fname, entry_name, expected,
5171 allow_resize=True)
5172 actual = control.ReadEntry(updated_fname, entry_name)
5173 self.assertEqual(expected, actual)
5174
Simon Glass80025522022-01-29 14:14:04 -07005175 new_data = tools.read_file(updated_fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005176 hdr, fents = fip_util.decode_fip(new_data)
5177
5178 self.assertEqual(2, len(fents))
5179
5180 # Check that the FIP entry is updated
5181 fent = fents[1]
5182 self.assertEqual(0x8c, fent.offset)
5183 self.assertEqual(len(expected), fent.size)
5184 self.assertEqual(0, fent.flags)
5185 self.assertEqual(expected, fent.data)
5186 self.assertEqual(True, fent.valid)
5187
5188 def testFipMissing(self):
5189 with test_util.capture_sys_output() as (stdout, stderr):
5190 self._DoTestFile('209_fip_missing.dts', allow_missing=True)
5191 err = stderr.getvalue()
5192 self.assertRegex(err, "Image 'main-section'.*missing.*: rmm-fw")
5193
5194 def testFipSize(self):
5195 """Test a FIP with a size property"""
5196 data = self._DoReadFile('210_fip_size.dts')
5197 self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
5198 hdr, fents = fip_util.decode_fip(data)
5199 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5200 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5201
5202 self.assertEqual(1, len(fents))
5203
5204 fent = fents[0]
5205 self.assertEqual('soc-fw', fent.fip_type)
5206 self.assertEqual(0x60, fent.offset)
5207 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5208 self.assertEqual(ATF_BL31_DATA, fent.data)
5209 self.assertEqual(True, fent.valid)
5210
5211 rest = data[0x60 + len(ATF_BL31_DATA):0x100]
Simon Glass80025522022-01-29 14:14:04 -07005212 self.assertEqual(tools.get_bytes(0xff, len(rest)), rest)
Simon Glass3efb2972021-11-23 21:08:59 -07005213
5214 def testFipBadAlign(self):
5215 """Test that an invalid alignment value in a FIP is detected"""
5216 with self.assertRaises(ValueError) as e:
5217 self._DoTestFile('211_fip_bad_align.dts')
5218 self.assertIn(
5219 "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
5220 str(e.exception))
5221
5222 def testFipCollection(self):
5223 """Test using a FIP in a collection"""
5224 data = self._DoReadFile('212_fip_collection.dts')
5225 entry1 = control.images['image'].GetEntries()['collection']
5226 data1 = data[:entry1.size]
5227 hdr1, fents2 = fip_util.decode_fip(data1)
5228
5229 entry2 = control.images['image'].GetEntries()['atf-fip']
5230 data2 = data[entry2.offset:entry2.offset + entry2.size]
5231 hdr1, fents2 = fip_util.decode_fip(data2)
5232
5233 # The 'collection' entry should have U-Boot included at the end
5234 self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
5235 self.assertEqual(data1, data2 + U_BOOT_DATA)
5236 self.assertEqual(U_BOOT_DATA, data1[-4:])
5237
5238 # There should be a U-Boot after the final FIP
5239 self.assertEqual(U_BOOT_DATA, data[-4:])
Simon Glass76f496d2021-07-06 10:36:37 -06005240
Simon Glassccae6862022-01-12 13:10:35 -07005241 def testFakeBlob(self):
5242 """Test handling of faking an external blob"""
5243 with test_util.capture_sys_output() as (stdout, stderr):
5244 self._DoTestFile('217_fake_blob.dts', allow_missing=True,
5245 allow_fake_blobs=True)
5246 err = stderr.getvalue()
5247 self.assertRegex(
5248 err,
5249 "Image '.*' has faked external blobs and is non-functional: .*")
Simon Glassccae6862022-01-12 13:10:35 -07005250
Simon Glassceb5f912022-01-09 20:13:46 -07005251 def testExtblobListFaked(self):
5252 """Test an extblob with missing external blob that are faked"""
5253 with test_util.capture_sys_output() as (stdout, stderr):
5254 self._DoTestFile('216_blob_ext_list_missing.dts',
5255 allow_fake_blobs=True)
5256 err = stderr.getvalue()
5257 self.assertRegex(err, "Image 'main-section'.*faked.*: blob-ext-list")
5258
Simon Glass162017b2022-01-09 20:13:57 -07005259 def testListBintools(self):
5260 args = ['tool', '--list']
5261 with test_util.capture_sys_output() as (stdout, _):
5262 self._DoBinman(*args)
5263 out = stdout.getvalue().splitlines()
5264 self.assertTrue(len(out) >= 2)
5265
5266 def testFetchBintools(self):
5267 def fail_download(url):
Simon Glass80025522022-01-29 14:14:04 -07005268 """Take the tools.download() function by raising an exception"""
Simon Glass162017b2022-01-09 20:13:57 -07005269 raise urllib.error.URLError('my error')
5270
5271 args = ['tool']
5272 with self.assertRaises(ValueError) as e:
5273 self._DoBinman(*args)
5274 self.assertIn("Invalid arguments to 'tool' subcommand",
5275 str(e.exception))
5276
5277 args = ['tool', '--fetch']
5278 with self.assertRaises(ValueError) as e:
5279 self._DoBinman(*args)
5280 self.assertIn('Please specify bintools to fetch', str(e.exception))
5281
5282 args = ['tool', '--fetch', '_testing']
Simon Glass80025522022-01-29 14:14:04 -07005283 with unittest.mock.patch.object(tools, 'download',
Simon Glass162017b2022-01-09 20:13:57 -07005284 side_effect=fail_download):
5285 with test_util.capture_sys_output() as (stdout, _):
5286 self._DoBinman(*args)
5287 self.assertIn('failed to fetch with all methods', stdout.getvalue())
5288
Simon Glass620c4462022-01-09 20:14:11 -07005289 def testBintoolDocs(self):
5290 """Test for creation of bintool documentation"""
5291 with test_util.capture_sys_output() as (stdout, stderr):
5292 control.write_bintool_docs(control.bintool.Bintool.get_tool_list())
5293 self.assertTrue(len(stdout.getvalue()) > 0)
5294
5295 def testBintoolDocsMissing(self):
5296 """Test handling of missing bintool documentation"""
5297 with self.assertRaises(ValueError) as e:
5298 with test_util.capture_sys_output() as (stdout, stderr):
5299 control.write_bintool_docs(
5300 control.bintool.Bintool.get_tool_list(), 'mkimage')
5301 self.assertIn('Documentation is missing for modules: mkimage',
5302 str(e.exception))
5303
Jan Kiszka58c407f2022-01-28 20:37:53 +01005304 def testListWithGenNode(self):
5305 """Check handling of an FDT map when the section cannot be found"""
5306 entry_args = {
5307 'of-list': 'test-fdt1 test-fdt2',
5308 }
5309 data = self._DoReadFileDtb(
5310 '219_fit_gennode.dts',
5311 entry_args=entry_args,
5312 use_real_dtb=True,
5313 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])
5314
5315 try:
5316 tmpdir, updated_fname = self._SetupImageInTmpdir()
5317 with test_util.capture_sys_output() as (stdout, stderr):
5318 self._RunBinman('ls', '-i', updated_fname)
5319 finally:
5320 shutil.rmtree(tmpdir)
5321
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005322 def testFitSubentryUsesBintool(self):
5323 """Test that binman FIT subentries can use bintools"""
5324 command.test_result = self._HandleGbbCommand
5325 entry_args = {
5326 'keydir': 'devkeys',
5327 'bmpblk': 'bmpblk.bin',
5328 }
5329 data, _, _, _ = self._DoReadFileDtb('220_fit_subentry_bintool.dts',
5330 entry_args=entry_args)
5331
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03005332 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
5333 tools.get_bytes(0, 0x2180 - 16))
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005334 self.assertIn(expected, data)
5335
5336 def testFitSubentryMissingBintool(self):
5337 """Test that binman reports missing bintools for FIT subentries"""
5338 entry_args = {
5339 'keydir': 'devkeys',
5340 }
5341 with test_util.capture_sys_output() as (_, stderr):
5342 self._DoTestFile('220_fit_subentry_bintool.dts',
5343 force_missing_bintools='futility', entry_args=entry_args)
5344 err = stderr.getvalue()
5345 self.assertRegex(err,
5346 "Image 'main-section'.*missing bintools.*: futility")
Simon Glassccae6862022-01-12 13:10:35 -07005347
Alper Nebi Yasak1e4ffd82022-02-09 22:02:35 +03005348 def testFitSubentryHashSubnode(self):
5349 """Test an image with a FIT inside"""
5350 data, _, _, out_dtb_name = self._DoReadFileDtb(
5351 '221_fit_subentry_hash.dts', use_real_dtb=True, update_dtb=True)
5352
5353 mkimage_dtb = fdt.Fdt.FromData(data)
5354 mkimage_dtb.Scan()
5355 binman_dtb = fdt.Fdt(out_dtb_name)
5356 binman_dtb.Scan()
5357
5358 # Check that binman didn't add hash values
5359 fnode = binman_dtb.GetNode('/binman/fit/images/kernel/hash')
5360 self.assertNotIn('value', fnode.props)
5361
5362 fnode = binman_dtb.GetNode('/binman/fit/images/fdt-1/hash')
5363 self.assertNotIn('value', fnode.props)
5364
5365 # Check that mkimage added hash values
5366 fnode = mkimage_dtb.GetNode('/images/kernel/hash')
5367 self.assertIn('value', fnode.props)
5368
5369 fnode = mkimage_dtb.GetNode('/images/fdt-1/hash')
5370 self.assertIn('value', fnode.props)
5371
Roger Quadros5cdcea02022-02-19 20:50:04 +02005372 def testPackTeeOs(self):
5373 """Test that an image with an TEE binary can be created"""
5374 data = self._DoReadFile('222_tee_os.dts')
5375 self.assertEqual(TEE_OS_DATA, data[:len(TEE_OS_DATA)])
5376
Simon Glass912339f2022-02-08 11:50:03 -07005377 def testFitFdtOper(self):
5378 """Check handling of a specified FIT operation"""
5379 entry_args = {
5380 'of-list': 'test-fdt1 test-fdt2',
5381 'default-dt': 'test-fdt2',
5382 }
5383 self._DoReadFileDtb(
5384 '223_fit_fdt_oper.dts',
5385 entry_args=entry_args,
5386 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
5387
5388 def testFitFdtBadOper(self):
5389 """Check handling of an FDT map when the section cannot be found"""
5390 with self.assertRaises(ValueError) as exc:
5391 self._DoReadFileDtb('224_fit_bad_oper.dts')
Simon Glass05f71dc2022-03-05 20:19:09 -07005392 self.assertIn("Node '/binman/fit': subnode 'images/@fdt-SEQ': Unknown operation 'unknown'",
Simon Glass912339f2022-02-08 11:50:03 -07005393 str(exc.exception))
5394
Simon Glassdd156a42022-03-05 20:18:59 -07005395 def test_uses_expand_size(self):
5396 """Test that the 'expand-size' property cannot be used anymore"""
5397 with self.assertRaises(ValueError) as e:
5398 data = self._DoReadFile('225_expand_size_bad.dts')
5399 self.assertIn(
5400 "Node '/binman/u-boot': Please use 'extend-size' instead of 'expand-size'",
5401 str(e.exception))
5402
Simon Glass5f423422022-03-05 20:19:12 -07005403 def testFitSplitElf(self):
5404 """Test an image with an FIT with an split-elf operation"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005405 if not elf.ELF_TOOLS:
5406 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005407 entry_args = {
5408 'of-list': 'test-fdt1 test-fdt2',
5409 'default-dt': 'test-fdt2',
5410 'atf-bl31-path': 'bl31.elf',
5411 'tee-os-path': 'tee.elf',
5412 }
5413 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5414 data = self._DoReadFileDtb(
5415 '226_fit_split_elf.dts',
5416 entry_args=entry_args,
5417 extra_indirs=[test_subdir])[0]
5418
5419 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
5420 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
5421
5422 base_keys = {'description', 'type', 'arch', 'os', 'compression',
5423 'data', 'load'}
5424 dtb = fdt.Fdt.FromData(fit_data)
5425 dtb.Scan()
5426
5427 elf_data = tools.read_file(os.path.join(self._indir, 'bl31.elf'))
5428 segments, entry = elf.read_loadable_segments(elf_data)
5429
5430 # We assume there are two segments
5431 self.assertEquals(2, len(segments))
5432
5433 atf1 = dtb.GetNode('/images/atf-1')
5434 _, start, data = segments[0]
5435 self.assertEqual(base_keys | {'entry'}, atf1.props.keys())
5436 self.assertEqual(entry,
5437 fdt_util.fdt32_to_cpu(atf1.props['entry'].value))
5438 self.assertEqual(start,
5439 fdt_util.fdt32_to_cpu(atf1.props['load'].value))
5440 self.assertEqual(data, atf1.props['data'].bytes)
5441
5442 atf2 = dtb.GetNode('/images/atf-2')
5443 self.assertEqual(base_keys, atf2.props.keys())
5444 _, start, data = segments[1]
5445 self.assertEqual(start,
5446 fdt_util.fdt32_to_cpu(atf2.props['load'].value))
5447 self.assertEqual(data, atf2.props['data'].bytes)
5448
5449 conf = dtb.GetNode('/configurations')
5450 self.assertEqual({'default'}, conf.props.keys())
5451
5452 for subnode in conf.subnodes:
5453 self.assertEqual({'description', 'fdt', 'loadables'},
5454 subnode.props.keys())
5455 self.assertEqual(
5456 ['atf-1', 'atf-2', 'tee-1', 'tee-2'],
5457 fdt_util.GetStringList(subnode, 'loadables'))
5458
5459 def _check_bad_fit(self, dts):
5460 """Check a bad FIT
5461
5462 This runs with the given dts and returns the assertion raised
5463
5464 Args:
5465 dts (str): dts filename to use
5466
5467 Returns:
5468 str: Assertion string raised
5469 """
5470 entry_args = {
5471 'of-list': 'test-fdt1 test-fdt2',
5472 'default-dt': 'test-fdt2',
5473 'atf-bl31-path': 'bl31.elf',
5474 'tee-os-path': 'tee.elf',
5475 }
5476 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5477 with self.assertRaises(ValueError) as exc:
5478 self._DoReadFileDtb(dts, entry_args=entry_args,
5479 extra_indirs=[test_subdir])[0]
5480 return str(exc.exception)
5481
5482 def testFitSplitElfBadElf(self):
5483 """Test a FIT split-elf operation with an invalid ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005484 if not elf.ELF_TOOLS:
5485 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005486 TestFunctional._MakeInputFile('bad.elf', tools.get_bytes(100, 100))
5487 entry_args = {
5488 'of-list': 'test-fdt1 test-fdt2',
5489 'default-dt': 'test-fdt2',
5490 'atf-bl31-path': 'bad.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(
5496 '226_fit_split_elf.dts',
5497 entry_args=entry_args,
5498 extra_indirs=[test_subdir])[0]
5499 self.assertIn(
5500 "Node '/binman/fit': subnode 'images/@atf-SEQ': Failed to read ELF file: Magic number does not match",
5501 str(exc.exception))
5502
Simon Glass5f423422022-03-05 20:19:12 -07005503 def checkFitSplitElf(self, **kwargs):
Simon Glass7d3e4072022-08-07 09:46:46 -06005504 """Test an split-elf FIT with a missing ELF file
5505
5506 Args:
5507 kwargs (dict of str): Arguments to pass to _DoTestFile()
5508
5509 Returns:
5510 tuple:
5511 str: stdout result
5512 str: stderr result
5513 """
Simon Glass5f423422022-03-05 20:19:12 -07005514 entry_args = {
5515 'of-list': 'test-fdt1 test-fdt2',
5516 'default-dt': 'test-fdt2',
5517 'atf-bl31-path': 'bl31.elf',
5518 'tee-os-path': 'missing.elf',
5519 }
5520 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5521 with test_util.capture_sys_output() as (stdout, stderr):
5522 self._DoTestFile(
5523 '226_fit_split_elf.dts', entry_args=entry_args,
Simon Glass7d3e4072022-08-07 09:46:46 -06005524 extra_indirs=[test_subdir], verbosity=3, **kwargs)
5525 out = stdout.getvalue()
5526 err = stderr.getvalue()
5527 return out, err
Simon Glass5f423422022-03-05 20:19:12 -07005528
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005529 def testFitSplitElfBadDirective(self):
5530 """Test a FIT split-elf invalid fit,xxx directive in an image node"""
5531 if not elf.ELF_TOOLS:
5532 self.skipTest('Python elftools not available')
5533 err = self._check_bad_fit('227_fit_bad_dir.dts')
5534 self.assertIn(
5535 "Node '/binman/fit': subnode 'images/@atf-SEQ': Unknown directive 'fit,something'",
5536 err)
5537
5538 def testFitSplitElfBadDirectiveConfig(self):
5539 """Test a FIT split-elf with invalid fit,xxx directive in config"""
5540 if not elf.ELF_TOOLS:
5541 self.skipTest('Python elftools not available')
5542 err = self._check_bad_fit('228_fit_bad_dir_config.dts')
5543 self.assertEqual(
5544 "Node '/binman/fit': subnode 'configurations/@config-SEQ': Unknown directive 'fit,config'",
5545 err)
5546
5547
Simon Glass5f423422022-03-05 20:19:12 -07005548 def testFitSplitElfMissing(self):
5549 """Test an split-elf FIT with a missing ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005550 if not elf.ELF_TOOLS:
5551 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005552 out, err = self.checkFitSplitElf(allow_missing=True)
Simon Glass5f423422022-03-05 20:19:12 -07005553 self.assertRegex(
5554 err,
5555 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005556 self.assertNotRegex(out, '.*Faked blob.*')
5557 fname = tools.get_output_filename('binman-fake/missing.elf')
5558 self.assertFalse(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005559
5560 def testFitSplitElfFaked(self):
5561 """Test an split-elf FIT with faked ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005562 if not elf.ELF_TOOLS:
5563 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005564 out, err = self.checkFitSplitElf(allow_missing=True, allow_fake_blobs=True)
Simon Glass5f423422022-03-05 20:19:12 -07005565 self.assertRegex(
5566 err,
5567 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005568 self.assertRegex(
5569 out,
5570 "Entry '/binman/fit/images/@tee-SEQ/tee-os': Faked blob '.*binman-fake/missing.elf")
5571 fname = tools.get_output_filename('binman-fake/missing.elf')
5572 self.assertTrue(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005573
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005574 def testMkimageMissingBlob(self):
5575 """Test using mkimage to build an image"""
5576 with test_util.capture_sys_output() as (stdout, stderr):
5577 self._DoTestFile('229_mkimage_missing.dts', allow_missing=True,
5578 allow_fake_blobs=True)
5579 err = stderr.getvalue()
5580 self.assertRegex(
5581 err,
5582 "Image '.*' has faked external blobs and is non-functional: .*")
5583
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005584 def testPreLoad(self):
5585 """Test an image with a pre-load header"""
5586 entry_args = {
5587 'pre-load-key-path': '.',
5588 }
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005589 data, _, _, _ = self._DoReadFileDtb('230_pre_load.dts',
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005590 entry_args=entry_args)
5591 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5592 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5593 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005594 data = self._DoReadFile('230_pre_load.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005595 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5596 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5597 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5598
5599 def testPreLoadPkcs(self):
5600 """Test an image with a pre-load header with padding pkcs"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005601 data = self._DoReadFile('231_pre_load_pkcs.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005602 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5603 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5604 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5605
5606 def testPreLoadPss(self):
5607 """Test an image with a pre-load header with padding pss"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005608 data = self._DoReadFile('232_pre_load_pss.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005609 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5610 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5611 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5612
5613 def testPreLoadInvalidPadding(self):
5614 """Test an image with a pre-load header with an invalid padding"""
5615 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005616 data = self._DoReadFile('233_pre_load_invalid_padding.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005617
5618 def testPreLoadInvalidSha(self):
5619 """Test an image with a pre-load header with an invalid hash"""
5620 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005621 data = self._DoReadFile('234_pre_load_invalid_sha.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005622
5623 def testPreLoadInvalidAlgo(self):
5624 """Test an image with a pre-load header with an invalid algo"""
5625 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005626 data = self._DoReadFile('235_pre_load_invalid_algo.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005627
5628 def testPreLoadInvalidKey(self):
5629 """Test an image with a pre-load header with an invalid key"""
5630 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005631 data = self._DoReadFile('236_pre_load_invalid_key.dts')
Roger Quadros5cdcea02022-02-19 20:50:04 +02005632
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005633 def _CheckSafeUniqueNames(self, *images):
5634 """Check all entries of given images for unsafe unique names"""
5635 for image in images:
5636 entries = {}
5637 image._CollectEntries(entries, {}, image)
5638 for entry in entries.values():
5639 uniq = entry.GetUniqueName()
5640
5641 # Used as part of a filename, so must not be absolute paths.
5642 self.assertFalse(os.path.isabs(uniq))
5643
5644 def testSafeUniqueNames(self):
5645 """Test entry unique names are safe in single image configuration"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005646 data = self._DoReadFileRealDtb('237_unique_names.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005647
5648 orig_image = control.images['image']
5649 image_fname = tools.get_output_filename('image.bin')
5650 image = Image.FromFile(image_fname)
5651
5652 self._CheckSafeUniqueNames(orig_image, image)
5653
5654 def testSafeUniqueNamesMulti(self):
5655 """Test entry unique names are safe with multiple images"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005656 data = self._DoReadFileRealDtb('238_unique_names_multi.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005657
5658 orig_image = control.images['image']
5659 image_fname = tools.get_output_filename('image.bin')
5660 image = Image.FromFile(image_fname)
5661
5662 self._CheckSafeUniqueNames(orig_image, image)
5663
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005664 def testReplaceCmdWithBintool(self):
5665 """Test replacing an entry that needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005666 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005667 expected = U_BOOT_DATA + b'aa'
5668 self.assertEqual(expected, data[:len(expected)])
5669
5670 try:
5671 tmpdir, updated_fname = self._SetupImageInTmpdir()
5672 fname = os.path.join(tmpdir, 'update-testing.bin')
5673 tools.write_file(fname, b'zz')
5674 self._DoBinman('replace', '-i', updated_fname,
5675 '_testing', '-f', fname)
5676
5677 data = tools.read_file(updated_fname)
5678 expected = U_BOOT_DATA + b'zz'
5679 self.assertEqual(expected, data[:len(expected)])
5680 finally:
5681 shutil.rmtree(tmpdir)
5682
5683 def testReplaceCmdOtherWithBintool(self):
5684 """Test replacing an entry when another needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005685 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005686 expected = U_BOOT_DATA + b'aa'
5687 self.assertEqual(expected, data[:len(expected)])
5688
5689 try:
5690 tmpdir, updated_fname = self._SetupImageInTmpdir()
5691 fname = os.path.join(tmpdir, 'update-u-boot.bin')
5692 tools.write_file(fname, b'x' * len(U_BOOT_DATA))
5693 self._DoBinman('replace', '-i', updated_fname,
5694 'u-boot', '-f', fname)
5695
5696 data = tools.read_file(updated_fname)
5697 expected = b'x' * len(U_BOOT_DATA) + b'aa'
5698 self.assertEqual(expected, data[:len(expected)])
5699 finally:
5700 shutil.rmtree(tmpdir)
5701
Alper Nebi Yasak00c68f12022-03-27 18:31:46 +03005702 def testReplaceResizeNoRepackSameSize(self):
5703 """Test replacing entries with same-size data without repacking"""
5704 expected = b'x' * len(U_BOOT_DATA)
5705 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected)
5706 self.assertEqual(expected, data)
5707
5708 path, fdtmap = state.GetFdtContents('fdtmap')
5709 self.assertIsNotNone(path)
5710 self.assertEqual(expected_fdtmap, fdtmap)
5711
5712 def testReplaceResizeNoRepackSmallerSize(self):
5713 """Test replacing entries with smaller-size data without repacking"""
5714 new_data = b'x'
5715 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', new_data)
5716 expected = new_data.ljust(len(U_BOOT_DATA), b'\0')
5717 self.assertEqual(expected, data)
5718
5719 path, fdtmap = state.GetFdtContents('fdtmap')
5720 self.assertIsNotNone(path)
5721 self.assertEqual(expected_fdtmap, fdtmap)
5722
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005723 def testExtractFit(self):
5724 """Test extracting a FIT section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005725 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005726 image_fname = tools.get_output_filename('image.bin')
5727
5728 fit_data = control.ReadEntry(image_fname, 'fit')
5729 fit = fdt.Fdt.FromData(fit_data)
5730 fit.Scan()
5731
5732 # Check subentry data inside the extracted fit
5733 for node_path, expected in [
5734 ('/images/kernel', U_BOOT_DATA),
5735 ('/images/fdt-1', U_BOOT_NODTB_DATA),
5736 ('/images/scr-1', COMPRESS_DATA),
5737 ]:
5738 node = fit.GetNode(node_path)
5739 data = fit.GetProps(node)['data'].bytes
5740 self.assertEqual(expected, data)
5741
5742 def testExtractFitSubentries(self):
5743 """Test extracting FIT section subentries"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005744 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005745 image_fname = tools.get_output_filename('image.bin')
5746
5747 for entry_path, expected in [
5748 ('fit/kernel', U_BOOT_DATA),
5749 ('fit/kernel/u-boot', U_BOOT_DATA),
5750 ('fit/fdt-1', U_BOOT_NODTB_DATA),
5751 ('fit/fdt-1/u-boot-nodtb', U_BOOT_NODTB_DATA),
5752 ('fit/scr-1', COMPRESS_DATA),
5753 ('fit/scr-1/blob', COMPRESS_DATA),
5754 ]:
5755 data = control.ReadEntry(image_fname, entry_path)
5756 self.assertEqual(expected, data)
5757
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005758 def testReplaceFitSubentryLeafSameSize(self):
5759 """Test replacing a FIT leaf subentry with same-size data"""
5760 new_data = b'x' * len(U_BOOT_DATA)
5761 data, expected_fdtmap, _ = self._RunReplaceCmd(
5762 'fit/kernel/u-boot', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005763 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005764 self.assertEqual(new_data, data)
5765
5766 path, fdtmap = state.GetFdtContents('fdtmap')
5767 self.assertIsNotNone(path)
5768 self.assertEqual(expected_fdtmap, fdtmap)
5769
5770 def testReplaceFitSubentryLeafBiggerSize(self):
5771 """Test replacing a FIT leaf subentry with bigger-size data"""
5772 new_data = b'ub' * len(U_BOOT_NODTB_DATA)
5773 data, expected_fdtmap, _ = self._RunReplaceCmd(
5774 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005775 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005776 self.assertEqual(new_data, data)
5777
5778 # Will be repacked, so fdtmap must change
5779 path, fdtmap = state.GetFdtContents('fdtmap')
5780 self.assertIsNotNone(path)
5781 self.assertNotEqual(expected_fdtmap, fdtmap)
5782
5783 def testReplaceFitSubentryLeafSmallerSize(self):
5784 """Test replacing a FIT leaf subentry with smaller-size data"""
5785 new_data = b'x'
5786 expected = new_data.ljust(len(U_BOOT_NODTB_DATA), b'\0')
5787 data, expected_fdtmap, _ = self._RunReplaceCmd(
5788 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005789 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005790 self.assertEqual(expected, data)
5791
5792 path, fdtmap = state.GetFdtContents('fdtmap')
5793 self.assertIsNotNone(path)
5794 self.assertEqual(expected_fdtmap, fdtmap)
5795
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03005796 def testReplaceSectionSimple(self):
5797 """Test replacing a simple section with arbitrary data"""
5798 new_data = b'w' * len(COMPRESS_DATA + U_BOOT_DATA)
Simon Glassc6b283f2022-08-13 11:40:46 -06005799 with self.assertRaises(ValueError) as exc:
5800 self._RunReplaceCmd('section', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005801 dts='241_replace_section_simple.dts')
Simon Glassc6b283f2022-08-13 11:40:46 -06005802 self.assertIn(
5803 "Node '/section': Replacing sections is not implemented yet",
5804 str(exc.exception))
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03005805
Simon Glass8fbca772022-08-13 11:40:48 -06005806 def testMkimageImagename(self):
5807 """Test using mkimage with -n holding the data too"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005808 data = self._DoReadFile('242_mkimage_name.dts')
Simon Glass8fbca772022-08-13 11:40:48 -06005809
5810 # Check that the data appears in the file somewhere
5811 self.assertIn(U_BOOT_SPL_DATA, data)
5812
Simon Glassbb7d3bb2022-09-06 20:26:52 -06005813 # Get struct legacy_img_hdr -> ih_name
Simon Glass8fbca772022-08-13 11:40:48 -06005814 name = data[0x20:0x40]
5815
5816 # Build the filename that we expect to be placed in there, by virtue of
5817 # the -n paraameter
5818 expect = os.path.join(tools.get_output_dir(), 'mkimage.mkimage')
5819
5820 # Check that the image name is set to the temporary filename used
5821 self.assertEqual(expect.encode('utf-8')[:0x20], name)
5822
Simon Glassb1669752022-08-13 11:40:49 -06005823 def testMkimageImage(self):
5824 """Test using mkimage with -n holding the data too"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005825 data = self._DoReadFile('243_mkimage_image.dts')
Simon Glassb1669752022-08-13 11:40:49 -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 Glassb1669752022-08-13 11:40:49 -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-n.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
5840 # Check the corect data is in the imagename file
5841 self.assertEqual(U_BOOT_DATA, tools.read_file(expect))
5842
5843 def testMkimageImageNoContent(self):
5844 """Test using mkimage with -n and no data"""
5845 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005846 self._DoReadFile('244_mkimage_image_no_content.dts')
Simon Glassb1669752022-08-13 11:40:49 -06005847 self.assertIn('Could not complete processing of contents',
5848 str(exc.exception))
5849
5850 def testMkimageImageBad(self):
5851 """Test using mkimage with imagename node and data-to-imagename"""
5852 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005853 self._DoReadFile('245_mkimage_image_bad.dts')
Simon Glassb1669752022-08-13 11:40:49 -06005854 self.assertIn('Cannot use both imagename node and data-to-imagename',
5855 str(exc.exception))
5856
Simon Glassbd5cd882022-08-13 11:40:50 -06005857 def testCollectionOther(self):
5858 """Test a collection where the data comes from another section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005859 data = self._DoReadFile('246_collection_other.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06005860 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
5861 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
5862 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
5863 data)
5864
5865 def testMkimageCollection(self):
5866 """Test using a collection referring to an entry in a mkimage entry"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005867 data = self._DoReadFile('247_mkimage_coll.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06005868 expect = U_BOOT_SPL_DATA + U_BOOT_DATA
5869 self.assertEqual(expect, data[:len(expect)])
5870
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02005871 def testCompressDtbPrependInvalid(self):
5872 """Test that invalid header is detected"""
5873 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005874 self._DoReadFileDtb('248_compress_dtb_prepend_invalid.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02005875 self.assertIn("Node '/binman/u-boot-dtb': Invalid prepend in "
5876 "'u-boot-dtb': 'invalid'", str(e.exception))
5877
5878 def testCompressDtbPrependLength(self):
5879 """Test that compress with length header works as expected"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005880 data = self._DoReadFileRealDtb('249_compress_dtb_prepend_length.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02005881 image = control.images['image']
5882 entries = image.GetEntries()
5883 self.assertIn('u-boot-dtb', entries)
5884 u_boot_dtb = entries['u-boot-dtb']
5885 self.assertIn('fdtmap', entries)
5886 fdtmap = entries['fdtmap']
5887
5888 image_fname = tools.get_output_filename('image.bin')
5889 orig = control.ReadEntry(image_fname, 'u-boot-dtb')
5890 dtb = fdt.Fdt.FromData(orig)
5891 dtb.Scan()
5892 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
5893 expected = {
5894 'u-boot:size': len(U_BOOT_DATA),
5895 'u-boot-dtb:uncomp-size': len(orig),
5896 'u-boot-dtb:size': u_boot_dtb.size,
5897 'fdtmap:size': fdtmap.size,
5898 'size': len(data),
5899 }
5900 self.assertEqual(expected, props)
5901
5902 # Check implementation
5903 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
5904 rest = data[len(U_BOOT_DATA):]
5905 comp_data_len = struct.unpack('<I', rest[:4])[0]
5906 comp_data = rest[4:4 + comp_data_len]
5907 orig2 = self._decompress(comp_data)
5908 self.assertEqual(orig, orig2)
5909
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02005910 def testInvalidCompress(self):
5911 """Test that invalid compress algorithm is detected"""
5912 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005913 self._DoTestFile('250_compress_dtb_invalid.dts')
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02005914 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
5915
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02005916 def testCompUtilCompressions(self):
5917 """Test compression algorithms"""
5918 for bintool in self.comp_bintools.values():
5919 self._CheckBintool(bintool)
5920 data = bintool.compress(COMPRESS_DATA)
5921 self.assertNotEqual(COMPRESS_DATA, data)
5922 orig = bintool.decompress(data)
5923 self.assertEquals(COMPRESS_DATA, orig)
5924
5925 def testCompUtilVersions(self):
5926 """Test tool version of compression algorithms"""
5927 for bintool in self.comp_bintools.values():
5928 self._CheckBintool(bintool)
5929 version = bintool.version()
5930 self.assertRegex(version, '^v?[0-9]+[0-9.]*')
5931
5932 def testCompUtilPadding(self):
5933 """Test padding of compression algorithms"""
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02005934 # Skip zstd because it doesn't support padding
5935 for bintool in [v for k,v in self.comp_bintools.items() if k != 'zstd']:
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02005936 self._CheckBintool(bintool)
5937 data = bintool.compress(COMPRESS_DATA)
5938 self.assertNotEqual(COMPRESS_DATA, data)
5939 data += tools.get_bytes(0, 64)
5940 orig = bintool.decompress(data)
5941 self.assertEquals(COMPRESS_DATA, orig)
5942
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02005943 def testCompressDtbZstd(self):
5944 """Test that zstd compress of device-tree files failed"""
5945 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005946 self._DoTestFile('251_compress_dtb_zstd.dts')
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02005947 self.assertIn("Node '/binman/u-boot-dtb': The zstd compression "
5948 "requires a length header", str(e.exception))
5949
Quentin Schulz9b5c6482022-09-02 15:10:48 +02005950 def testMkimageMultipleDataFiles(self):
5951 """Test passing multiple files to mkimage in a mkimage entry"""
5952 data = self._DoReadFile('252_mkimage_mult_data.dts')
5953 # Size of files are packed in their 4B big-endian format
5954 expect = struct.pack('>I', len(U_BOOT_TPL_DATA))
5955 expect += struct.pack('>I', len(U_BOOT_SPL_DATA))
5956 # Size info is always followed by a 4B zero value.
5957 expect += tools.get_bytes(0, 4)
5958 expect += U_BOOT_TPL_DATA
5959 # All but last files are 4B-aligned
5960 align_pad = len(U_BOOT_TPL_DATA) % 4
5961 if align_pad:
5962 expect += tools.get_bytes(0, align_pad)
5963 expect += U_BOOT_SPL_DATA
5964 self.assertEqual(expect, data[-len(expect):])
5965
5966 def testMkimageMultipleNoContent(self):
5967 """Test passing multiple data files to mkimage with one data file having no content"""
5968 with self.assertRaises(ValueError) as exc:
5969 self._DoReadFile('253_mkimage_mult_no_content.dts')
5970 self.assertIn('Could not complete processing of contents',
5971 str(exc.exception))
5972
Quentin Schulz0d3a9262022-09-02 15:10:49 +02005973 def testMkimageFilename(self):
5974 """Test using mkimage to build a binary with a filename"""
5975 retcode = self._DoTestFile('254_mkimage_filename.dts')
5976 self.assertEqual(0, retcode)
5977 fname = tools.get_output_filename('mkimage-test.bin')
5978 self.assertTrue(os.path.exists(fname))
5979
Simon Glass56d05412022-02-28 07:16:54 -07005980 def testVpl(self):
5981 """Test that an image with VPL and its device tree can be created"""
5982 # ELF file with a '__bss_size' symbol
5983 self._SetupVplElf()
5984 data = self._DoReadFile('255_u_boot_vpl.dts')
5985 self.assertEqual(U_BOOT_VPL_DATA + U_BOOT_VPL_DTB_DATA, data)
5986
5987 def testVplNoDtb(self):
5988 """Test that an image with vpl/u-boot-vpl-nodtb.bin can be created"""
5989 self._SetupVplElf()
5990 data = self._DoReadFile('256_u_boot_vpl_nodtb.dts')
5991 self.assertEqual(U_BOOT_VPL_NODTB_DATA,
5992 data[:len(U_BOOT_VPL_NODTB_DATA)])
5993
5994 def testExpandedVpl(self):
5995 """Test that an expanded entry type is selected for TPL when needed"""
5996 self._SetupVplElf()
5997
5998 entry_args = {
5999 'vpl-bss-pad': 'y',
6000 'vpl-dtb': 'y',
6001 }
6002 self._DoReadFileDtb('257_fdt_incl_vpl.dts', use_expanded=True,
6003 entry_args=entry_args)
6004 image = control.images['image']
6005 entries = image.GetEntries()
6006 self.assertEqual(1, len(entries))
6007
6008 # We only have u-boot-vpl, which be expanded
6009 self.assertIn('u-boot-vpl', entries)
6010 entry = entries['u-boot-vpl']
6011 self.assertEqual('u-boot-vpl-expanded', entry.etype)
6012 subent = entry.GetEntries()
6013 self.assertEqual(3, len(subent))
6014 self.assertIn('u-boot-vpl-nodtb', subent)
6015 self.assertIn('u-boot-vpl-bss-pad', subent)
6016 self.assertIn('u-boot-vpl-dtb', subent)
6017
6018 def testVplBssPadMissing(self):
6019 """Test that a missing symbol is detected"""
6020 self._SetupVplElf('u_boot_ucode_ptr')
6021 with self.assertRaises(ValueError) as e:
6022 self._DoReadFile('258_vpl_bss_pad.dts')
6023 self.assertIn('Expected __bss_size symbol in vpl/u-boot-vpl',
6024 str(e.exception))
6025
Neha Malcom Francis3eb4be32022-10-17 16:36:25 +05306026 def testSymlink(self):
6027 """Test that image files can be named"""
6028 retcode = self._DoTestFile('259_symlink.dts', debug=True, map=True)
6029 self.assertEqual(0, retcode)
6030 image = control.images['test_image']
6031 fname = tools.get_output_filename('test_image.bin')
6032 sname = tools.get_output_filename('symlink_to_test.bin')
6033 self.assertTrue(os.path.islink(sname))
6034 self.assertEqual(os.readlink(sname), fname)
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03006035
Simon Glass37f85de2022-10-20 18:22:47 -06006036 def testSymbolsElf(self):
6037 """Test binman can assign symbols embedded in an ELF file"""
6038 if not elf.ELF_TOOLS:
6039 self.skipTest('Python elftools not available')
6040 self._SetupTplElf('u_boot_binman_syms')
6041 self._SetupVplElf('u_boot_binman_syms')
6042 self._SetupSplElf('u_boot_binman_syms')
6043 data = self._DoReadFileDtb('260_symbols_elf.dts')[0]
6044 image_fname = tools.get_output_filename('image.bin')
6045
6046 image = control.images['image']
6047 entries = image.GetEntries()
6048
6049 for entry in entries.values():
6050 # No symbols in u-boot and it has faked contents anyway
6051 if entry.name == 'u-boot':
6052 continue
6053 edata = data[entry.image_pos:entry.image_pos + entry.size]
6054 efname = tools.get_output_filename(f'edata-{entry.name}')
6055 tools.write_file(efname, edata)
6056
6057 syms = elf.GetSymbolFileOffset(efname, ['_binman_u_boot'])
6058 re_name = re.compile('_binman_(u_boot_(.*))_prop_(.*)')
6059 for name, sym in syms.items():
6060 msg = 'test'
6061 val = elf.GetSymbolValue(sym, edata, msg)
6062 entry_m = re_name.match(name)
6063 if entry_m:
6064 ename, prop = entry_m.group(1), entry_m.group(3)
6065 entry, entry_name, prop_name = image.LookupEntry(entries,
6066 name, msg)
6067 if prop_name == 'offset':
6068 expect_val = entry.offset
6069 elif prop_name == 'image_pos':
6070 expect_val = entry.image_pos
6071 elif prop_name == 'size':
6072 expect_val = entry.size
6073 self.assertEqual(expect_val, val)
6074
6075 def testSymbolsElfBad(self):
6076 """Check error when trying to write symbols without the elftools lib"""
6077 if not elf.ELF_TOOLS:
6078 self.skipTest('Python elftools not available')
6079 self._SetupTplElf('u_boot_binman_syms')
6080 self._SetupVplElf('u_boot_binman_syms')
6081 self._SetupSplElf('u_boot_binman_syms')
6082 try:
6083 elf.ELF_TOOLS = False
6084 with self.assertRaises(ValueError) as exc:
6085 self._DoReadFileDtb('260_symbols_elf.dts')
6086 finally:
6087 elf.ELF_TOOLS = True
6088 self.assertIn(
6089 "Section '/binman': entry '/binman/u-boot-spl-elf': "
6090 'Cannot write symbols to an ELF file without Python elftools',
6091 str(exc.exception))
6092
Simon Glassde244162023-01-07 14:07:08 -07006093 def testSectionFilename(self):
6094 """Check writing of section contents to a file"""
6095 data = self._DoReadFile('261_section_fname.dts')
6096 expected = (b'&&' + U_BOOT_DATA + b'&&&' +
6097 tools.get_bytes(ord('!'), 7) +
6098 U_BOOT_DATA + tools.get_bytes(ord('&'), 12))
6099 self.assertEqual(expected, data)
6100
6101 sect_fname = tools.get_output_filename('outfile.bin')
6102 self.assertTrue(os.path.exists(sect_fname))
6103 sect_data = tools.read_file(sect_fname)
6104 self.assertEqual(U_BOOT_DATA, sect_data)
6105
Simon Glass1e9e61c2023-01-07 14:07:12 -07006106 def testAbsent(self):
6107 """Check handling of absent entries"""
6108 data = self._DoReadFile('262_absent.dts')
6109 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6110
Simon Glassad5cfe12023-01-07 14:07:14 -07006111 def testPackTeeOsOptional(self):
6112 """Test that an image with an optional TEE binary can be created"""
6113 entry_args = {
6114 'tee-os-path': 'tee.elf',
6115 }
6116 data = self._DoReadFileDtb('263_tee_os_opt.dts',
6117 entry_args=entry_args)[0]
6118 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6119
6120 def checkFitTee(self, dts, tee_fname):
6121 """Check that a tee-os entry works and returns data
6122
6123 Args:
6124 dts (str): Device tree filename to use
6125 tee_fname (str): filename containing tee-os
6126
6127 Returns:
6128 bytes: Image contents
6129 """
6130 if not elf.ELF_TOOLS:
6131 self.skipTest('Python elftools not available')
6132 entry_args = {
6133 'of-list': 'test-fdt1 test-fdt2',
6134 'default-dt': 'test-fdt2',
6135 'tee-os-path': tee_fname,
6136 }
6137 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
6138 data = self._DoReadFileDtb(dts, entry_args=entry_args,
6139 extra_indirs=[test_subdir])[0]
6140 return data
6141
6142 def testFitTeeOsOptionalFit(self):
6143 """Test an image with a FIT with an optional OP-TEE binary"""
6144 data = self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bin')
6145
6146 # There should be only one node, holding the data set up in SetUpClass()
6147 # for tee.bin
6148 dtb = fdt.Fdt.FromData(data)
6149 dtb.Scan()
6150 node = dtb.GetNode('/images/tee-1')
6151 self.assertEqual(TEE_ADDR,
6152 fdt_util.fdt32_to_cpu(node.props['load'].value))
6153 self.assertEqual(TEE_ADDR,
6154 fdt_util.fdt32_to_cpu(node.props['entry'].value))
6155 self.assertEqual(U_BOOT_DATA, node.props['data'].bytes)
6156
6157 def testFitTeeOsOptionalFitBad(self):
6158 """Test an image with a FIT with an optional OP-TEE binary"""
6159 with self.assertRaises(ValueError) as exc:
6160 self.checkFitTee('265_tee_os_opt_fit_bad.dts', 'tee.bin')
6161 self.assertIn(
6162 "Node '/binman/fit': subnode 'images/@tee-SEQ': Failed to read ELF file: Magic number does not match",
6163 str(exc.exception))
6164
6165 def testFitTeeOsBad(self):
6166 """Test an OP-TEE binary with wrong formats"""
6167 self.make_tee_bin('tee.bad1', 123)
6168 with self.assertRaises(ValueError) as exc:
6169 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad1')
6170 self.assertIn(
6171 "Node '/binman/fit/images/@tee-SEQ/tee-os': OP-TEE paged mode not supported",
6172 str(exc.exception))
6173
6174 self.make_tee_bin('tee.bad2', 0, b'extra data')
6175 with self.assertRaises(ValueError) as exc:
6176 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad2')
6177 self.assertIn(
6178 "Node '/binman/fit/images/@tee-SEQ/tee-os': Invalid OP-TEE file: size mismatch (expected 0x4, have 0xe)",
6179 str(exc.exception))
6180
Simon Glass63328f12023-01-07 14:07:15 -07006181 def testExtblobOptional(self):
6182 """Test an image with an external blob that is optional"""
6183 with test_util.capture_sys_output() as (stdout, stderr):
6184 data = self._DoReadFile('266_blob_ext_opt.dts')
6185 self.assertEqual(REFCODE_DATA, data)
6186 err = stderr.getvalue()
6187 self.assertRegex(
6188 err,
6189 "Image '.*' is missing external blobs but is still functional: missing")
6190
Simon Glass7447a9d2023-01-11 16:10:12 -07006191 def testSectionInner(self):
6192 """Test an inner section with a size"""
6193 data = self._DoReadFile('267_section_inner.dts')
6194 expected = U_BOOT_DATA + tools.get_bytes(0, 12)
6195 self.assertEqual(expected, data)
6196
Simon Glassa4948b22023-01-11 16:10:14 -07006197 def testNull(self):
6198 """Test an image with a null entry"""
6199 data = self._DoReadFile('268_null.dts')
6200 self.assertEqual(U_BOOT_DATA + b'\xff\xff\xff\xff' + U_BOOT_IMG_DATA, data)
6201
Simon Glassf1ee03b2023-01-11 16:10:16 -07006202 def testOverlap(self):
6203 """Test an image with a overlapping entry"""
6204 data = self._DoReadFile('269_overlap.dts')
6205 self.assertEqual(U_BOOT_DATA[:1] + b'aa' + U_BOOT_DATA[3:], data)
6206
6207 image = control.images['image']
6208 entries = image.GetEntries()
6209
6210 self.assertIn('inset', entries)
6211 inset = entries['inset']
6212 self.assertEqual(1, inset.offset);
6213 self.assertEqual(1, inset.image_pos);
6214 self.assertEqual(2, inset.size);
6215
6216 def testOverlapNull(self):
6217 """Test an image with a null overlap"""
6218 data = self._DoReadFile('270_overlap_null.dts')
6219 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6220
6221 # Check the FMAP
6222 fhdr, fentries = fmap_util.DecodeFmap(data[len(U_BOOT_DATA):])
6223 self.assertEqual(4, fhdr.nareas)
6224 fiter = iter(fentries)
6225
6226 fentry = next(fiter)
6227 self.assertEqual(b'SECTION', fentry.name)
6228 self.assertEqual(0, fentry.offset)
6229 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6230 self.assertEqual(0, fentry.flags)
6231
6232 fentry = next(fiter)
6233 self.assertEqual(b'U_BOOT', fentry.name)
6234 self.assertEqual(0, fentry.offset)
6235 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6236 self.assertEqual(0, fentry.flags)
6237
6238 # Make sure that the NULL entry appears in the FMAP
6239 fentry = next(fiter)
6240 self.assertEqual(b'NULL', fentry.name)
6241 self.assertEqual(1, fentry.offset)
6242 self.assertEqual(2, fentry.size)
6243 self.assertEqual(0, fentry.flags)
6244
6245 fentry = next(fiter)
6246 self.assertEqual(b'FMAP', fentry.name)
6247 self.assertEqual(len(U_BOOT_DATA), fentry.offset)
6248
6249 def testOverlapBad(self):
6250 """Test an image with a bad overlapping entry"""
6251 with self.assertRaises(ValueError) as exc:
6252 self._DoReadFile('271_overlap_bad.dts')
6253 self.assertIn(
6254 "Node '/binman/inset': Offset 0x10 (16) ending at 0x12 (18) must overlap with existing entries",
6255 str(exc.exception))
6256
6257 def testOverlapNoOffset(self):
6258 """Test an image with a bad overlapping entry"""
6259 with self.assertRaises(ValueError) as exc:
6260 self._DoReadFile('272_overlap_no_size.dts')
6261 self.assertIn(
6262 "Node '/binman/inset': 'fill' entry is missing properties: size",
6263 str(exc.exception))
6264
Simon Glasse0035c92023-01-11 16:10:17 -07006265 def testBlobSymbol(self):
6266 """Test a blob with symbols read from an ELF file"""
6267 elf_fname = self.ElfTestFile('blob_syms')
6268 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6269 TestFunctional._MakeInputFile('blob_syms.bin',
6270 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6271
6272 data = self._DoReadFile('273_blob_symbol.dts')
6273
6274 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6275 addr = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6276 self.assertEqual(syms['_binman_sym_magic'].address, addr)
6277 self.assertEqual(syms['_binman_inset_prop_offset'].address, addr + 4)
6278 self.assertEqual(syms['_binman_inset_prop_size'].address, addr + 8)
6279
6280 sym_values = struct.pack('<LLL', elf.BINMAN_SYM_MAGIC_VALUE, 4, 8)
6281 expected = sym_values
6282 self.assertEqual(expected, data[:len(expected)])
6283
Simon Glass49e9c002023-01-11 16:10:19 -07006284 def testOffsetFromElf(self):
6285 """Test a blob with symbols read from an ELF file"""
6286 elf_fname = self.ElfTestFile('blob_syms')
6287 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6288 TestFunctional._MakeInputFile('blob_syms.bin',
6289 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6290
6291 data = self._DoReadFile('274_offset_from_elf.dts')
6292
6293 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6294 base = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6295
6296 image = control.images['image']
6297 entries = image.GetEntries()
6298
6299 self.assertIn('inset', entries)
6300 inset = entries['inset']
6301
6302 self.assertEqual(base + 4, inset.offset);
6303 self.assertEqual(base + 4, inset.image_pos);
6304 self.assertEqual(4, inset.size);
6305
6306 self.assertIn('inset2', entries)
6307 inset = entries['inset2']
6308 self.assertEqual(base + 8, inset.offset);
6309 self.assertEqual(base + 8, inset.image_pos);
6310 self.assertEqual(4, inset.size);
6311
Simon Glassde244162023-01-07 14:07:08 -07006312
Simon Glassac599912017-11-12 21:52:22 -07006313if __name__ == "__main__":
6314 unittest.main()