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