blob: 76445969201d543f57068a9ab5f2a20f346f6fd2 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001# SPDX-License-Identifier: GPL-2.0+
Simon Glass4f443042016-11-25 20:15:52 -07002# Copyright (c) 2016 Google, Inc
3# Written by Simon Glass <sjg@chromium.org>
4#
Simon Glass4f443042016-11-25 20:15:52 -07005# To run a single test, change to this directory, and:
6#
7# python -m unittest func_test.TestFunctional.testHelp
8
Simon Glassfdc34362020-07-09 18:39:45 -06009import collections
Simon Glass16287932020-04-17 18:09:03 -060010import gzip
Simon Glasse0e5df92018-09-14 04:57:31 -060011import hashlib
Simon Glass4f443042016-11-25 20:15:52 -070012from optparse import OptionParser
13import os
Simon Glassfdc34362020-07-09 18:39:45 -060014import re
Simon Glass4f443042016-11-25 20:15:52 -070015import shutil
16import struct
17import sys
18import tempfile
19import unittest
Simon Glass56ee85e2022-01-09 20:13:57 -070020import unittest.mock
21import urllib.error
Simon Glass4f443042016-11-25 20:15:52 -070022
Simon Glass386c63c2022-01-09 20:13:50 -070023from binman import bintool
Simon Glass16287932020-04-17 18:09:03 -060024from binman import cbfs_util
25from binman import cmdline
26from binman import control
27from binman import elf
28from binman import elf_test
Simon Glass75989722021-11-23 21:08:59 -070029from binman import fip_util
Simon Glass16287932020-04-17 18:09:03 -060030from binman import fmap_util
Simon Glass16287932020-04-17 18:09:03 -060031from binman import state
32from dtoc import fdt
33from dtoc import fdt_util
34from binman.etype import fdtmap
35from binman.etype import image_header
Simon Glass07237982020-08-05 13:27:47 -060036from binman.image import Image
Simon Glass4583c002023-02-23 18:18:04 -070037from u_boot_pylib import command
38from u_boot_pylib import test_util
39from u_boot_pylib import tools
40from u_boot_pylib import tout
Simon Glass4f443042016-11-25 20:15:52 -070041
42# Contents of test files, corresponding to different entry types
Simon Glassc6c10e72019-05-17 22:00:46 -060043U_BOOT_DATA = b'1234'
44U_BOOT_IMG_DATA = b'img'
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +030045U_BOOT_SPL_DATA = b'56780123456789abcdefghijklm'
46U_BOOT_TPL_DATA = b'tpl9876543210fedcbazywvuts'
Simon Glass6ad24522022-02-28 07:16:54 -070047U_BOOT_VPL_DATA = b'vpl76543210fedcbazywxyz_'
Simon Glassc6c10e72019-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 Glass6ad24522022-02-28 07:16:54 -070054U_BOOT_VPL_DTB_DATA = b'vpldtb'
Simon Glassc6c10e72019-05-17 22:00:46 -060055X86_START16_DATA = b'start16'
56X86_START16_SPL_DATA = b'start16spl'
57X86_START16_TPL_DATA = b'start16tpl'
Simon Glass2250ee62019-08-24 07:22:48 -060058X86_RESET16_DATA = b'reset16'
59X86_RESET16_SPL_DATA = b'reset16spl'
60X86_RESET16_TPL_DATA = b'reset16tpl'
Simon Glassc6c10e72019-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 Glass6ad24522022-02-28 07:16:54 -070065U_BOOT_VPL_NODTB_DATA = b'vplnodtb'
Alper Nebi Yasak21353312022-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 Glassc6c10e72019-05-17 22:00:46 -060069FSP_DATA = b'fsp'
70CMC_DATA = b'cmc'
71VBT_DATA = b'vbt'
72MRC_DATA = b'mrc'
Simon Glassbb748372018-07-17 13:25:33 -060073TEXT_DATA = 'text'
74TEXT_DATA2 = 'text2'
75TEXT_DATA3 = 'text3'
Simon Glassc6c10e72019-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 Glassff5c7e32019-07-08 13:18:42 -060082COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
Simon Glass8f5ef892020-10-26 17:40:25 -060083COMPRESS_DATA_BIG = COMPRESS_DATA * 2
Simon Glassc6c10e72019-05-17 22:00:46 -060084REFCODE_DATA = b'refcode'
Simon Glassea0fff92019-08-24 07:23:07 -060085FSP_M_DATA = b'fsp_m'
Simon Glassbc6a88f2019-10-20 21:31:35 -060086FSP_S_DATA = b'fsp_s'
Simon Glass998d1482019-10-20 21:31:36 -060087FSP_T_DATA = b'fsp_t'
Simon Glassdc2f81a2020-09-01 05:13:58 -060088ATF_BL31_DATA = b'bl31'
Roger Quadros47f420a2022-02-19 20:50:04 +020089TEE_OS_DATA = b'this is some tee OS data'
Simon Glass75989722021-11-23 21:08:59 -070090ATF_BL2U_DATA = b'bl2u'
Bin Meng4c4d6072021-05-10 20:23:33 +080091OPENSBI_DATA = b'opensbi'
Samuel Holland18bd4552020-10-21 21:12:15 -050092SCP_DATA = b'scp'
Simon Glass6cf99532020-09-01 05:13:59 -060093TEST_FDT1_DATA = b'fdt1'
94TEST_FDT2_DATA = b'test-fdt2'
Simon Glassfb91d562020-09-06 10:35:33 -060095ENV_DATA = b'var1=1\nvar2="2"'
Philippe Reynesb1c50932022-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 Glass6cf99532020-09-01 05:13:59 -060099
100# Subdirectory of the input dir to use to put test FDTs
101TEST_FDT_SUBDIR = 'fdts'
Simon Glassec127af2018-07-17 13:25:39 -0600102
Simon Glass6ccbfcd2019-07-20 12:23:47 -0600103# The expected size for the device tree in some tests
Simon Glassf667e452019-07-08 14:25:50 -0600104EXTRACT_DTB_SIZE = 0x3c9
105
Simon Glass6ccbfcd2019-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 Glass12bb1a92019-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 Herbrechtsmeiercbe2e752022-08-19 16:25:28 +0200112# Supported compression bintools
Stefan Herbrechtsmeiercd15b642022-08-19 16:25:38 +0200113COMP_BINTOOLS = ['bzip2', 'gzip', 'lz4', 'lzma_alone', 'lzop', 'xz', 'zstd']
Simon Glass4f443042016-11-25 20:15:52 -0700114
Simon Glass2f80c5e2023-01-07 14:07:14 -0700115TEE_ADDR = 0x5678
116
Simon Glass4f443042016-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 Glassb986b3b2019-08-24 07:22:43 -0600132 def setUpClass(cls):
Simon Glass4d5994f2017-11-12 21:52:20 -0700133 global entry
Simon Glass16287932020-04-17 18:09:03 -0600134 from binman import entry
Simon Glass4d5994f2017-11-12 21:52:20 -0700135
Simon Glass4f443042016-11-25 20:15:52 -0700136 # Handle the case where argv[0] is 'python'
Simon Glassb986b3b2019-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 Glass4f443042016-11-25 20:15:52 -0700139
140 # Create a temporary directory for input files
Simon Glassb986b3b2019-08-24 07:22:43 -0600141 cls._indir = tempfile.mkdtemp(prefix='binmant.')
Simon Glass4f443042016-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 Glassb8ef5b62018-07-17 13:25:48 -0600147 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass6ad24522022-02-28 07:16:54 -0700148 TestFunctional._MakeInputFile('vpl/u-boot-vpl.bin', U_BOOT_VPL_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700149 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -0700150 TestFunctional._MakeInputFile('me.bin', ME_DATA)
151 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glassb986b3b2019-08-24 07:22:43 -0600152 cls._ResetDtbs()
Simon Glass2250ee62019-08-24 07:22:48 -0600153
Jagdish Gediya9d368f32018-09-03 21:35:08 +0530154 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glass2250ee62019-08-24 07:22:48 -0600155
Simon Glass5e239182019-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 Glass87722132017-11-12 21:52:26 -0700158 X86_START16_SPL_DATA)
Simon Glass5e239182019-08-24 07:22:49 -0600159 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
Simon Glass35b384c2018-09-14 04:57:10 -0600160 X86_START16_TPL_DATA)
Simon Glass2250ee62019-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 Glass4f443042016-11-25 20:15:52 -0700169 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass6b187df2017-11-12 21:52:27 -0700170 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
171 U_BOOT_SPL_NODTB_DATA)
Simon Glassf0253632018-09-14 04:57:32 -0600172 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
173 U_BOOT_TPL_NODTB_DATA)
Simon Glass6ad24522022-02-28 07:16:54 -0700174 TestFunctional._MakeInputFile('vpl/u-boot-vpl-nodtb.bin',
175 U_BOOT_VPL_NODTB_DATA)
Simon Glassda229092016-11-25 20:15:56 -0700176 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
177 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Meng59ea8c22017-08-15 22:41:54 -0700178 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassca4f4ff2017-11-12 21:52:28 -0700179 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassec127af2018-07-17 13:25:39 -0600180 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glass0ef87aa2018-07-17 13:25:44 -0600181 TestFunctional._MakeInputDir('devkeys')
182 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass3ae192c2018-10-01 12:22:31 -0600183 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glassea0fff92019-08-24 07:23:07 -0600184 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
Simon Glassbc6a88f2019-10-20 21:31:35 -0600185 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
Simon Glass998d1482019-10-20 21:31:36 -0600186 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700187
Simon Glass53e22bf2019-08-24 07:22:53 -0600188 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
189 elf_test.BuildElfTestFiles(cls._elf_testdir)
190
Simon Glasse0ff8552016-11-25 20:15:53 -0700191 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glassf514d8f2019-08-24 07:22:54 -0600192 TestFunctional._MakeInputFile('u-boot',
Simon Glassc1aa66e2022-01-29 14:14:04 -0700193 tools.read_file(cls.ElfTestFile('u_boot_ucode_ptr')))
Simon Glasse0ff8552016-11-25 20:15:53 -0700194
195 # Intel flash descriptor file
Simon Glass0ba4b3d2020-07-09 18:39:41 -0600196 cls._SetupDescriptor()
Simon Glasse0ff8552016-11-25 20:15:53 -0700197
Simon Glassb986b3b2019-08-24 07:22:43 -0600198 shutil.copytree(cls.TestFile('files'),
199 os.path.join(cls._indir, 'files'))
Simon Glass0a98b282018-09-14 04:57:28 -0600200
Simon Glass83d73c22018-09-14 04:57:26 -0600201 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
Simon Glass8f5ef892020-10-26 17:40:25 -0600202 TestFunctional._MakeInputFile('compress_big', COMPRESS_DATA_BIG)
Simon Glassdc2f81a2020-09-01 05:13:58 -0600203 TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
Roger Quadros47f420a2022-02-19 20:50:04 +0200204 TestFunctional._MakeInputFile('tee-pager.bin', TEE_OS_DATA)
Simon Glass75989722021-11-23 21:08:59 -0700205 TestFunctional._MakeInputFile('bl2u.bin', ATF_BL2U_DATA)
Bin Meng4c4d6072021-05-10 20:23:33 +0800206 TestFunctional._MakeInputFile('fw_dynamic.bin', OPENSBI_DATA)
Samuel Holland18bd4552020-10-21 21:12:15 -0500207 TestFunctional._MakeInputFile('scp.bin', SCP_DATA)
Simon Glass83d73c22018-09-14 04:57:26 -0600208
Simon Glass6cf99532020-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 Glassfb91d562020-09-06 10:35:33 -0600215 TestFunctional._MakeInputFile('env.txt', ENV_DATA)
216
Simon Glass40c8bdd2022-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 Glass2f80c5e2023-01-07 14:07:14 -0700224 # Newer OP_TEE file in v1 binary format
225 cls.make_tee_bin('tee.bin')
226
Stefan Herbrechtsmeiercbe2e752022-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 Glassac62fba2019-07-08 13:18:53 -0600230
Simon Glass4f443042016-11-25 20:15:52 -0700231 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600232 def tearDownClass(cls):
Simon Glass4f443042016-11-25 20:15:52 -0700233 """Remove the temporary input directory and its contents"""
Simon Glassb986b3b2019-08-24 07:22:43 -0600234 if cls.preserve_indir:
235 print('Preserving input dir: %s' % cls._indir)
Simon Glassd5164a72019-07-08 13:18:49 -0600236 else:
Simon Glassb986b3b2019-08-24 07:22:43 -0600237 if cls._indir:
238 shutil.rmtree(cls._indir)
239 cls._indir = None
Simon Glass4f443042016-11-25 20:15:52 -0700240
Simon Glassd5164a72019-07-08 13:18:49 -0600241 @classmethod
Simon Glass8acce602019-07-08 13:18:50 -0600242 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
Simon Glass53cd5d92019-07-08 14:25:29 -0600243 toolpath=None, verbosity=None):
Simon Glassd5164a72019-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 Glass8acce602019-07-08 13:18:50 -0600252 toolpath: ist of paths to use for tools
Simon Glassd5164a72019-07-08 13:18:49 -0600253 """
254 cls.preserve_indir = preserve_indir
255 cls.preserve_outdirs = preserve_outdirs
Simon Glass8acce602019-07-08 13:18:50 -0600256 cls.toolpath = toolpath
Simon Glass53cd5d92019-07-08 14:25:29 -0600257 cls.verbosity = verbosity
Simon Glassd5164a72019-07-08 13:18:49 -0600258
Stefan Herbrechtsmeiercbe2e752022-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 Glassac62fba2019-07-08 13:18:53 -0600263 def _CheckLz4(self):
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +0200264 bintool = self.comp_bintools['lz4']
265 self._CheckBintool(bintool)
Simon Glassac62fba2019-07-08 13:18:53 -0600266
Simon Glassbf574f12019-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 Glassc1aa66e2022-01-29 14:14:04 -0700272 tools._finalise_for_test()
Simon Glassbf574f12019-07-20 12:24:09 -0600273
Simon Glass4f443042016-11-25 20:15:52 -0700274 def setUp(self):
275 # Enable this to turn on debugging output
Simon Glassf3385a52022-01-29 14:14:15 -0700276 # tout.init(tout.DEBUG)
Simon Glass4f443042016-11-25 20:15:52 -0700277 command.test_result = None
278
279 def tearDown(self):
280 """Remove the temporary output directory"""
Simon Glassbf574f12019-07-20 12:24:09 -0600281 self._CleanupOutputDir()
Simon Glass4f443042016-11-25 20:15:52 -0700282
Simon Glassf86a7362019-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 Glassc1aa66e2022-01-29 14:14:04 -0700298 image_fname = tools.get_output_filename('image.bin')
Simon Glassf86a7362019-07-20 12:24:10 -0600299 tmpdir = tempfile.mkdtemp(prefix='binman.')
300 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
Simon Glassc1aa66e2022-01-29 14:14:04 -0700301 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassf86a7362019-07-20 12:24:10 -0600302 self._CleanupOutputDir()
303 return tmpdir, updated_fname
304
Simon Glassb8ef5b62018-07-17 13:25:48 -0600305 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600306 def _ResetDtbs(cls):
Simon Glassb8ef5b62018-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 Glass6ad24522022-02-28 07:16:54 -0700310 TestFunctional._MakeInputFile('vpl/u-boot-vpl.dtb', U_BOOT_VPL_DTB_DATA)
Simon Glassb8ef5b62018-07-17 13:25:48 -0600311
Simon Glass4f443042016-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 Glassd9800692022-01-29 14:14:05 -0700319 result = command.run_pipe([[self._binman_pathname] + list(args)],
Simon Glass4f443042016-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 Glass53cd5d92019-07-08 14:25:29 -0600326 def _DoBinman(self, *argv):
Simon Glass4f443042016-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 Glass53cd5d92019-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 Glass4f443042016-11-25 20:15:52 -0700338
339 # For testing, you can force an increase in verbosity here
Simon Glass53cd5d92019-07-08 14:25:29 -0600340 # args.verbosity = tout.DEBUG
341 return control.Binman(args)
Simon Glass4f443042016-11-25 20:15:52 -0700342
Simon Glass53af22a2018-07-17 13:25:32 -0600343 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glasseb833d82019-04-25 21:58:34 -0600344 entry_args=None, images=None, use_real_dtb=False,
Simon Glass63aeaeb2021-03-18 20:25:05 +1300345 use_expanded=False, verbosity=None, allow_missing=False,
Heiko Thierya89c8f22022-01-06 11:49:41 +0100346 allow_fake_blobs=False, extra_indirs=None, threads=None,
Simon Glass4f9ee832022-01-09 20:14:09 -0700347 test_section_timeout=False, update_fdt_in_elf=None,
Simon Glassb38da152022-11-09 19:14:42 -0700348 force_missing_bintools='', ignore_missing=False):
Simon Glass4f443042016-11-25 20:15:52 -0700349 """Run binman with a given test file
350
351 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600352 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600353 debug: True to enable debugging output
Simon Glass3b0c38212018-06-01 09:38:20 -0600354 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600355 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600356 tree before packing it into the image
Simon Glass0bfa7b02018-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 Glasse9d336d2020-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 Glass63aeaeb2021-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 Glasse9d336d2020-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 Thierya89c8f22022-01-06 11:49:41 +0100370 allow_fake_blobs: Set the '--fake-ext-blobs' flag
Simon Glass6cf99532020-09-01 05:13:59 -0600371 extra_indirs: Extra input directories to add using -I
Simon Glassc69d19c2021-07-06 10:36:37 -0600372 threads: Number of threads to use (None for default, 0 for
373 single-threaded)
Simon Glass7115f002021-11-03 21:09:17 -0600374 test_section_timeout: True to force the first time to timeout, as
375 used in testThreadTimeout()
Simon Glass0427bed2021-11-03 21:09:18 -0600376 update_fdt_in_elf: Value to pass with --update-fdt-in-elf=xxx
Simon Glass4f9ee832022-01-09 20:14:09 -0700377 force_missing_tools (str): comma-separated list of bintools to
378 regard as missing
Simon Glass7115f002021-11-03 21:09:17 -0600379
380 Returns:
381 int return code, 0 on success
Simon Glass4f443042016-11-25 20:15:52 -0700382 """
Simon Glass53cd5d92019-07-08 14:25:29 -0600383 args = []
Simon Glass7fe91732017-11-13 18:55:00 -0700384 if debug:
385 args.append('-D')
Simon Glass53cd5d92019-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 Glassc69d19c2021-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 Glass53cd5d92019-07-08 14:25:29 -0600397 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass3b0c38212018-06-01 09:38:20 -0600398 if map:
399 args.append('-m')
Simon Glass16b8d6b2018-07-06 10:27:42 -0600400 if update_dtb:
Simon Glass2569e102019-07-08 13:18:47 -0600401 args.append('-u')
Simon Glass93d17412018-09-14 04:57:23 -0600402 if not use_real_dtb:
403 args.append('--fake-dtb')
Simon Glass63aeaeb2021-03-18 20:25:05 +1300404 if not use_expanded:
405 args.append('--no-expanded')
Simon Glass53af22a2018-07-17 13:25:32 -0600406 if entry_args:
Simon Glass50979152019-05-14 15:53:41 -0600407 for arg, value in entry_args.items():
Simon Glass53af22a2018-07-17 13:25:32 -0600408 args.append('-a%s=%s' % (arg, value))
Simon Glass4f9f1052020-07-09 18:39:38 -0600409 if allow_missing:
410 args.append('-M')
Simon Glassb38da152022-11-09 19:14:42 -0700411 if ignore_missing:
412 args.append('-W')
Heiko Thierya89c8f22022-01-06 11:49:41 +0100413 if allow_fake_blobs:
414 args.append('--fake-ext-blobs')
Simon Glass4f9ee832022-01-09 20:14:09 -0700415 if force_missing_bintools:
416 args += ['--force-missing-bintools', force_missing_bintools]
Simon Glass0427bed2021-11-03 21:09:18 -0600417 if update_fdt_in_elf:
418 args += ['--update-fdt-in-elf', update_fdt_in_elf]
Simon Glass0bfa7b02018-09-14 04:57:12 -0600419 if images:
420 for image in images:
421 args += ['-i', image]
Simon Glass6cf99532020-09-01 05:13:59 -0600422 if extra_indirs:
423 for indir in extra_indirs:
424 args += ['-I', indir]
Simon Glass7fe91732017-11-13 18:55:00 -0700425 return self._DoBinman(*args)
Simon Glass4f443042016-11-25 20:15:52 -0700426
427 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glasse0ff8552016-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 Glass7ae5f312018-06-01 09:38:19 -0600435 outfile: Output filename for compiled device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700436
437 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600438 Contents of device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700439 """
Simon Glassa004f292019-07-20 12:23:49 -0600440 tmpdir = tempfile.mkdtemp(prefix='binmant.')
441 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
Simon Glass1d0ebf72019-05-14 15:53:42 -0600442 with open(dtb, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700443 data = fd.read()
444 TestFunctional._MakeInputFile(outfile, data)
Simon Glassa004f292019-07-20 12:23:49 -0600445 shutil.rmtree(tmpdir)
Simon Glasse0e62752018-10-01 21:12:41 -0600446 return data
Simon Glass4f443042016-11-25 20:15:52 -0700447
Simon Glass6ad24522022-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 Glass6ed45ba2018-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 Glasse9d336d2020-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 Glass6ed45ba2018-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 Glass63aeaeb2021-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 Glassc69d19c2021-07-06 10:36:37 -0600475 reset_dtbs=True, extra_indirs=None, threads=None):
Simon Glass4f443042016-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 Glass741f2d62018-10-01 12:22:30 -0600485 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass4f443042016-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 Glass63aeaeb2021-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 Glass3b0c38212018-06-01 09:38:20 -0600492 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600493 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600494 tree before packing it into the image
Simon Glasse9d336d2020-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 Glass6cf99532020-09-01 05:13:59 -0600501 extra_indirs: Extra input directories to add using -I
Simon Glassc69d19c2021-07-06 10:36:37 -0600502 threads: Number of threads to use (None for default, 0 for
503 single-threaded)
Simon Glasse0ff8552016-11-25 20:15:53 -0700504
505 Returns:
506 Tuple:
507 Resulting image contents
508 Device tree contents
Simon Glass3b0c38212018-06-01 09:38:20 -0600509 Map data showing contents of image (or None if none)
Simon Glassea6922e2018-07-17 13:25:27 -0600510 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass4f443042016-11-25 20:15:52 -0700511 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700512 dtb_data = None
Simon Glass4f443042016-11-25 20:15:52 -0700513 # Use the compiled test file as the u-boot-dtb input
514 if use_real_dtb:
Simon Glasse0ff8552016-11-25 20:15:53 -0700515 dtb_data = self._SetupDtb(fname)
Simon Glass6ed45ba2018-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 Glass6ad24522022-02-28 07:16:54 -0700519 for name in ['spl', 'tpl', 'vpl']:
Simon Glass6ed45ba2018-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 Glass6ad24522022-02-28 07:16:54 -0700523 self._GetDtbContentsForSpls(dtb_data, name))
Simon Glass4f443042016-11-25 20:15:52 -0700524
525 try:
Simon Glass53af22a2018-07-17 13:25:32 -0600526 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glass6cf99532020-09-01 05:13:59 -0600527 entry_args=entry_args, use_real_dtb=use_real_dtb,
Simon Glassc69d19c2021-07-06 10:36:37 -0600528 use_expanded=use_expanded, extra_indirs=extra_indirs,
529 threads=threads)
Simon Glass4f443042016-11-25 20:15:52 -0700530 self.assertEqual(0, retcode)
Simon Glassc1aa66e2022-01-29 14:14:04 -0700531 out_dtb_fname = tools.get_output_filename('u-boot.dtb.out')
Simon Glass4f443042016-11-25 20:15:52 -0700532
533 # Find the (only) image, read it and return its contents
534 image = control.images['image']
Simon Glassc1aa66e2022-01-29 14:14:04 -0700535 image_fname = tools.get_output_filename('image.bin')
Simon Glass16b8d6b2018-07-06 10:27:42 -0600536 self.assertTrue(os.path.exists(image_fname))
Simon Glass3b0c38212018-06-01 09:38:20 -0600537 if map:
Simon Glassc1aa66e2022-01-29 14:14:04 -0700538 map_fname = tools.get_output_filename('image.map')
Simon Glass3b0c38212018-06-01 09:38:20 -0600539 with open(map_fname) as fd:
540 map_data = fd.read()
541 else:
542 map_data = None
Simon Glass1d0ebf72019-05-14 15:53:42 -0600543 with open(image_fname, 'rb') as fd:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600544 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass4f443042016-11-25 20:15:52 -0700545 finally:
546 # Put the test file back
Simon Glass6ed45ba2018-09-14 04:57:24 -0600547 if reset_dtbs and use_real_dtb:
Simon Glassb8ef5b62018-07-17 13:25:48 -0600548 self._ResetDtbs()
Simon Glass4f443042016-11-25 20:15:52 -0700549
Simon Glass3c081312019-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 Glasse0ff8552016-11-25 20:15:53 -0700561 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass7ae5f312018-06-01 09:38:19 -0600562 """Helper function which discards the device-tree binary
563
564 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600565 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-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 Glassea6922e2018-07-17 13:25:27 -0600570
571 Returns:
572 Resulting image contents
Simon Glass7ae5f312018-06-01 09:38:19 -0600573 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700574 return self._DoReadFileDtb(fname, use_real_dtb)[0]
575
Simon Glass4f443042016-11-25 20:15:52 -0700576 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600577 def _MakeInputFile(cls, fname, contents):
Simon Glass4f443042016-11-25 20:15:52 -0700578 """Create a new test input file, creating directories as needed
579
580 Args:
Simon Glass3ab95982018-08-01 15:22:37 -0600581 fname: Filename to create
Simon Glass4f443042016-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 Glassb986b3b2019-08-24 07:22:43 -0600586 pathname = os.path.join(cls._indir, fname)
Simon Glass4f443042016-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 Glassb986b3b2019-08-24 07:22:43 -0600595 def _MakeInputDir(cls, dirname):
Simon Glass0ef87aa2018-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 Glassb986b3b2019-08-24 07:22:43 -0600604 pathname = os.path.join(cls._indir, dirname)
Simon Glass0ef87aa2018-07-17 13:25:44 -0600605 if not os.path.exists(pathname):
606 os.makedirs(pathname)
607 return pathname
608
609 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600610 def _SetupSplElf(cls, src_fname='bss_data'):
Simon Glass11ae93e2018-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 Glassc9a0b272019-08-24 07:22:59 -0600616 TestFunctional._MakeInputFile('spl/u-boot-spl',
Simon Glassc1aa66e2022-01-29 14:14:04 -0700617 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass11ae93e2018-10-01 21:12:47 -0600618
619 @classmethod
Simon Glass2090f1e2019-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 Glassc1aa66e2022-01-29 14:14:04 -0700627 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass2090f1e2019-08-24 07:23:00 -0600628
629 @classmethod
Simon Glass6ad24522022-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 Glass0ba4b3d2020-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 Glassb986b3b2019-08-24 07:22:43 -0600645 def TestFile(cls, fname):
646 return os.path.join(cls._binman_dir, 'test', fname)
Simon Glass4f443042016-11-25 20:15:52 -0700647
Simon Glass53e22bf2019-08-24 07:22:53 -0600648 @classmethod
649 def ElfTestFile(cls, fname):
650 return os.path.join(cls._elf_testdir, fname)
651
Simon Glass2f80c5e2023-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 Glass4f443042016-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 Glass1fc62de2019-05-17 22:00:50 -0600670 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass4f443042016-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 Glass3ab95982018-08-01 15:22:37 -0600678 offset = 0
Simon Glass4f443042016-11-25 20:15:52 -0700679 for entry in entries.values():
Simon Glass3ab95982018-08-01 15:22:37 -0600680 self.assertEqual(offset, entry.offset)
681 offset += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700682
Simon Glasse0ff8552016-11-25 20:15:53 -0700683 def GetFdtLen(self, dtb):
Simon Glass7ae5f312018-06-01 09:38:19 -0600684 """Get the totalsize field from a device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700685
686 Args:
Simon Glass7ae5f312018-06-01 09:38:19 -0600687 dtb: Device-tree binary contents
Simon Glasse0ff8552016-11-25 20:15:53 -0700688
689 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600690 Total size of device-tree binary, from the header
Simon Glasse0ff8552016-11-25 20:15:53 -0700691 """
692 return struct.unpack('>L', dtb[4:8])[0]
693
Simon Glass086cec92019-07-08 14:25:27 -0600694 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glass16b8d6b2018-07-06 10:27:42 -0600695 def AddNode(node, path):
696 if node.name != '/':
697 path += '/' + node.name
Simon Glass086cec92019-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 Glass16b8d6b2018-07-06 10:27:42 -0600703 for subnode in node.subnodes:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600704 AddNode(subnode, path)
705
706 tree = {}
Simon Glass16b8d6b2018-07-06 10:27:42 -0600707 AddNode(dtb.GetRoot(), '')
708 return tree
709
Simon Glass4f443042016-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 Glass61adb2d2021-03-18 20:25:13 +1300717 help_file = os.path.join(self._binman_dir, 'README.rst')
Tom Rini3759df02018-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 Glass4f443042016-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 Glass61adb2d2021-03-18 20:25:13 +1300730 help_file = os.path.join(self._binman_dir, 'README.rst')
Simon Glass4f443042016-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 Glass4f443042016-11-25 20:15:52 -0700741 def testBoard(self):
742 """Test that we can run it with a specific board"""
Simon Glass741f2d62018-10-01 12:22:30 -0600743 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass4f443042016-11-25 20:15:52 -0700744 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glass63aeaeb2021-03-18 20:25:05 +1300745 result = self._DoBinman('build', '-n', '-b', 'sandbox')
Simon Glass4f443042016-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 Glass53cd5d92019-07-08 14:25:29 -0600751 result = self._DoBinman('build')
Simon Glass4f443042016-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 Glass7ae5f312018-06-01 09:38:19 -0600756 """Test that an invalid device-tree file generates an error"""
Simon Glass4f443042016-11-25 20:15:52 -0700757 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600758 self._RunBinman('build', '-d', 'missing_file')
Simon Glass4f443042016-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 Glass7ae5f312018-06-01 09:38:19 -0600764 """Test that an invalid device-tree source file generates an error
Simon Glass4f443042016-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 Glass53cd5d92019-07-08 14:25:29 -0600770 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass4f443042016-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 Glass53cd5d92019-07-08 14:25:29 -0600777 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass4f443042016-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 Glass53cd5d92019-07-08 14:25:29 -0600782 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass4f443042016-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 Glass53cd5d92019-07-08 14:25:29 -0600789 result = self._RunBinman('build', '-d',
Simon Glass741f2d62018-10-01 12:22:30 -0600790 self.TestFile('004_invalid_entry.dts'))
Simon Glass4f443042016-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 Glass741f2d62018-10-01 12:22:30 -0600796 data = self._DoReadFile('005_simple.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700797 self.assertEqual(U_BOOT_DATA, data)
798
Simon Glass7fe91732017-11-13 18:55:00 -0700799 def testSimpleDebug(self):
800 """Test a simple binman run with debugging enabled"""
Simon Glasse2705fa2019-07-08 14:25:53 -0600801 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass7fe91732017-11-13 18:55:00 -0700802
Simon Glass4f443042016-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 Glass741f2d62018-10-01 12:22:30 -0600808 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700809 self.assertEqual(0, retcode)
810
811 image = control.images['image1']
Simon Glass8beb11e2019-07-08 14:25:47 -0600812 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glassc1aa66e2022-01-29 14:14:04 -0700813 fname = tools.get_output_filename('image1.bin')
Simon Glass4f443042016-11-25 20:15:52 -0700814 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600815 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700816 data = fd.read()
817 self.assertEqual(U_BOOT_DATA, data)
818
819 image = control.images['image2']
Simon Glass8beb11e2019-07-08 14:25:47 -0600820 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glassc1aa66e2022-01-29 14:14:04 -0700821 fname = tools.get_output_filename('image2.bin')
Simon Glass4f443042016-11-25 20:15:52 -0700822 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600823 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700824 data = fd.read()
825 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glassc1aa66e2022-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 Glass4f443042016-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 Glass741f2d62018-10-01 12:22:30 -0600832 self._DoTestFile('007_bad_align.dts')
Simon Glass4f443042016-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 Glass741f2d62018-10-01 12:22:30 -0600838 retcode = self._DoTestFile('008_pack.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700839 self.assertEqual(0, retcode)
840 self.assertIn('image', control.images)
841 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600842 entries = image.GetEntries()
Simon Glass4f443042016-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 Glass3ab95982018-08-01 15:22:37 -0600848 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-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 Glass3ab95982018-08-01 15:22:37 -0600854 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-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 Glass3ab95982018-08-01 15:22:37 -0600860 self.assertEqual(20, entry.offset)
Simon Glass4f443042016-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 Glass3ab95982018-08-01 15:22:37 -0600867 self.assertEqual(43, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700868 self.assertEqual(len(U_BOOT_DATA), entry.size)
869
Simon Glass3ab95982018-08-01 15:22:37 -0600870 # Fifth u-boot, placed at a fixed offset
Simon Glass4f443042016-11-25 20:15:52 -0700871 self.assertIn('u-boot-fixed', entries)
872 entry = entries['u-boot-fixed']
Simon Glass3ab95982018-08-01 15:22:37 -0600873 self.assertEqual(61, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700874 self.assertEqual(len(U_BOOT_DATA), entry.size)
875
Simon Glass8beb11e2019-07-08 14:25:47 -0600876 self.assertEqual(65, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700877
878 def testPackExtra(self):
879 """Test that extra packing feature works as expected"""
Simon Glass4eec34c2020-10-26 17:40:10 -0600880 data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
881 update_dtb=True)
Simon Glass4f443042016-11-25 20:15:52 -0700882
Simon Glass4f443042016-11-25 20:15:52 -0700883 self.assertIn('image', control.images)
884 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600885 entries = image.GetEntries()
Samuel Hollandb01ae032023-01-21 17:25:16 -0600886 self.assertEqual(6, len(entries))
Simon Glass4f443042016-11-25 20:15:52 -0700887
Samuel Hollandb01ae032023-01-21 17:25:16 -0600888 # First u-boot with padding before and after (included in minimum size)
Simon Glass4f443042016-11-25 20:15:52 -0700889 self.assertIn('u-boot', entries)
890 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600891 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700892 self.assertEqual(3, entry.pad_before)
893 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600894 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassc1aa66e2022-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 Glassef439ed2020-10-26 17:40:08 -0600897 pos = entry.size
Simon Glass4f443042016-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 Glassef439ed2020-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 Glass4f443042016-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 Glassef439ed2020-10-26 17:40:08 -0600911 self.assertEqual(pos, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700912 self.assertEqual(32, entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600913 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassc1aa66e2022-01-29 14:14:04 -0700914 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
Simon Glassef439ed2020-10-26 17:40:08 -0600915 data[pos:pos + entry.size])
916 pos += entry.size
Simon Glass4f443042016-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 Glass3ab95982018-08-01 15:22:37 -0600921 self.assertEqual(48, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700922 self.assertEqual(16, entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600923 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glassc1aa66e2022-01-29 14:14:04 -0700924 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 16 - len(U_BOOT_DATA)),
Simon Glassef439ed2020-10-26 17:40:08 -0600925 data[pos:pos + entry.size])
926 pos += entry.size
Simon Glass4f443042016-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 Glass3ab95982018-08-01 15:22:37 -0600931 self.assertEqual(64, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700932 self.assertEqual(64, entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600933 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glassc1aa66e2022-01-29 14:14:04 -0700934 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 64 - len(U_BOOT_DATA)),
Simon Glassef439ed2020-10-26 17:40:08 -0600935 data[pos:pos + entry.size])
Simon Glass4f443042016-11-25 20:15:52 -0700936
Samuel Hollandb01ae032023-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 Glass4f443042016-11-25 20:15:52 -0700946 self.CheckNoGaps(entries)
Samuel Hollandb01ae032023-01-21 17:25:16 -0600947 self.assertEqual(160, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700948
Simon Glass4eec34c2020-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 Hollandb01ae032023-01-21 17:25:16 -0600955 'size': 160,
Simon Glass4eec34c2020-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 Hollandb01ae032023-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 Glass4eec34c2020-10-26 17:40:10 -0600980 }
981 self.assertEqual(expected, props)
982
Simon Glass4f443042016-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 Glass741f2d62018-10-01 12:22:30 -0600986 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass4f443042016-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 Glass741f2d62018-10-01 12:22:30 -0600993 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass4f443042016-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 Glass3ab95982018-08-01 15:22:37 -0600998 """Test detection of an offset that does not match its alignment"""
Simon Glass4f443042016-11-25 20:15:52 -0700999 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001000 self._DoTestFile('012_pack_inv_align.dts')
Simon Glass3ab95982018-08-01 15:22:37 -06001001 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass4f443042016-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 Glass741f2d62018-10-01 12:22:30 -06001007 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass4f443042016-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 Glass741f2d62018-10-01 12:22:30 -06001014 self._DoTestFile('014_pack_overlap.dts')
Simon Glass3ab95982018-08-01 15:22:37 -06001015 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass4f443042016-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 Glass741f2d62018-10-01 12:22:30 -06001022 self._DoTestFile('015_pack_overflow.dts')
Simon Glass4f443042016-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 Glass741f2d62018-10-01 12:22:30 -06001029 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glass8f1da502018-06-01 09:38:12 -06001030 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass4f443042016-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 Glass741f2d62018-10-01 12:22:30 -06001035 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001036 self.assertEqual(0, retcode)
1037 self.assertIn('image', control.images)
1038 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -06001039 self.assertEqual(7, image.size)
Simon Glass4f443042016-11-25 20:15:52 -07001040
1041 def testPackImageSizeAlign(self):
1042 """Test that image size alignemnt works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -06001043 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001044 self.assertEqual(0, retcode)
1045 self.assertIn('image', control.images)
1046 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -06001047 self.assertEqual(16, image.size)
Simon Glass4f443042016-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 Glass741f2d62018-10-01 12:22:30 -06001052 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glass8f1da502018-06-01 09:38:12 -06001053 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass4f443042016-11-25 20:15:52 -07001054 "align-size 0x8 (8)", str(e.exception))
1055
Simon Glass8d2ef3e2022-02-11 13:23:21 -07001056 def testPackAlignPowerOf2Inv(self):
Simon Glass4f443042016-11-25 20:15:52 -07001057 """Test that invalid image alignment is detected"""
1058 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001059 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -06001060 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass4f443042016-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 Glass11ae93e2018-10-01 21:12:47 -06001065 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001066 data = self._DoReadFile('021_image_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001067 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0xff, 1) +
Simon Glasse6d85ff2019-05-14 15:53:47 -06001068 U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -07001069
1070 def testImageName(self):
1071 """Test that image files can be named"""
Simon Glass741f2d62018-10-01 12:22:30 -06001072 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001073 self.assertEqual(0, retcode)
1074 image = control.images['image1']
Simon Glassc1aa66e2022-01-29 14:14:04 -07001075 fname = tools.get_output_filename('test-name')
Simon Glass4f443042016-11-25 20:15:52 -07001076 self.assertTrue(os.path.exists(fname))
1077
1078 image = control.images['image2']
Simon Glassc1aa66e2022-01-29 14:14:04 -07001079 fname = tools.get_output_filename('test-name.xx')
Simon Glass4f443042016-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 Glass741f2d62018-10-01 12:22:30 -06001084 data = self._DoReadFile('023_blob.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001085 self.assertEqual(BLOB_DATA, data)
1086
1087 def testPackSorted(self):
1088 """Test that entries can be sorted"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001089 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001090 data = self._DoReadFile('024_sorted.dts')
Simon Glassc1aa66e2022-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 Glass4f443042016-11-25 20:15:52 -07001093
Simon Glass3ab95982018-08-01 15:22:37 -06001094 def testPackZeroOffset(self):
1095 """Test that an entry at offset 0 is not given a new offset"""
Simon Glass4f443042016-11-25 20:15:52 -07001096 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001097 self._DoTestFile('025_pack_zero_size.dts')
Simon Glass3ab95982018-08-01 15:22:37 -06001098 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass4f443042016-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 Glass741f2d62018-10-01 12:22:30 -06001104 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001105 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glasse0ff8552016-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 Glass741f2d62018-10-01 12:22:30 -06001110 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -06001111 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glasse0ff8552016-11-25 20:15:53 -07001112 "using end-at-4gb", str(e.exception))
1113
Jagdish Gediya94b57db2018-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 Glassdfdd2b62019-08-24 07:23:02 -06001118 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -06001119 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya94b57db2018-09-03 21:35:07 +05301120 "'skip-at-start'", str(e.exception))
1121
Simon Glasse0ff8552016-11-25 20:15:53 -07001122 def testPackX86RomOutside(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001123 """Test that the end-at-4gb property checks for offset boundaries"""
Simon Glasse0ff8552016-11-25 20:15:53 -07001124 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001125 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glasse6bed4f2020-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 Glasse0ff8552016-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 Glass11ae93e2018-10-01 21:12:47 -06001133 self._SetupSplElf()
Simon Glass9255f3c2019-08-24 07:23:01 -06001134 data = self._DoReadFile('029_x86_rom.dts')
Simon Glassc1aa66e2022-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 Glasse0ff8552016-11-25 20:15:53 -07001137
1138 def testPackX86RomMeNoDesc(self):
1139 """Test that an invalid Intel descriptor entry is detected"""
Simon Glass0ba4b3d2020-07-09 18:39:41 -06001140 try:
Simon Glass52b10dd2020-07-25 15:11:19 -06001141 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
Simon Glass0ba4b3d2020-07-09 18:39:41 -06001142 with self.assertRaises(ValueError) as e:
Simon Glass52b10dd2020-07-25 15:11:19 -06001143 self._DoTestFile('163_x86_rom_me_empty.dts')
Simon Glass0ba4b3d2020-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 Glasse0ff8552016-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 Glass9255f3c2019-08-24 07:23:01 -06001152 self._DoTestFile('030_x86_rom_me_no_desc.dts')
Simon Glass3ab95982018-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 Glasse0ff8552016-11-25 20:15:53 -07001156
1157 def testPackX86RomMe(self):
1158 """Test that an x86 ROM with an ME region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001159 data = self._DoReadFile('031_x86_rom_me.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001160 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glassc5ac1382019-07-08 13:18:54 -06001161 if data[:0x1000] != expected_desc:
1162 self.fail('Expected descriptor binary at start of image')
Simon Glasse0ff8552016-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 Glass9255f3c2019-08-24 07:23:01 -06001167 data = self._DoReadFile('032_intel_vga.dts')
Simon Glasse0ff8552016-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 Glass9255f3c2019-08-24 07:23:01 -06001172 data = self._DoReadFile('033_x86_start16.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -07001173 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1174
Jagdish Gediya9d368f32018-09-03 21:35:08 +05301175 def testPackPowerpcMpc85xxBootpgResetvec(self):
1176 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1177 created"""
Simon Glassdfdd2b62019-08-24 07:23:02 -06001178 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
Jagdish Gediya9d368f32018-09-03 21:35:08 +05301179 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1180
Simon Glass736bb0a2018-07-06 10:27:17 -06001181 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glassadc57012018-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 Glass736bb0a2018-07-06 10:27:17 -06001187 ucode_second: True if the microsecond entry is second instead of
1188 third
Simon Glassadc57012018-07-06 10:27:16 -06001189
1190 Returns:
1191 Tuple:
1192 Contents of first region (U-Boot or SPL)
Simon Glass3ab95982018-08-01 15:22:37 -06001193 Offset and size components of microcode pointer, as inserted
Simon Glassadc57012018-07-06 10:27:16 -06001194 in the above (two 4-byte words)
1195 """
Simon Glass6b187df2017-11-12 21:52:27 -07001196 data = self._DoReadFile(dts_fname, True)
Simon Glasse0ff8552016-11-25 20:15:53 -07001197
1198 # Now check the device tree has no microcode
Simon Glass736bb0a2018-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 Glassc1aa66e2022-01-29 14:14:04 -07001209 fname = tools.get_output_filename('test.dtb')
Simon Glasse0ff8552016-11-25 20:15:53 -07001210 with open(fname, 'wb') as fd:
Simon Glassadc57012018-07-06 10:27:16 -06001211 fd.write(dtb_with_ucode)
Simon Glassec3f3782017-05-27 07:38:29 -06001212 dtb = fdt.FdtScan(fname)
1213 ucode = dtb.GetNode('/microcode')
Simon Glasse0ff8552016-11-25 20:15:53 -07001214 self.assertTrue(ucode)
1215 for node in ucode.subnodes:
1216 self.assertFalse(node.props.get('data'))
1217
Simon Glasse0ff8552016-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 Glass87722132017-11-12 21:52:26 -07001220 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glasse0ff8552016-11-25 20:15:53 -07001221 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1222 0x78235609)
Simon Glassadc57012018-07-06 10:27:16 -06001223 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glasse0ff8552016-11-25 20:15:53 -07001224
1225 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -06001226 # expected offset and size
Simon Glasse0ff8552016-11-25 20:15:53 -07001227 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1228 len(ucode_data))
Simon Glass736bb0a2018-07-06 10:27:17 -06001229 u_boot = data[:len(nodtb_data)]
1230 return u_boot, pos_and_size
Simon Glass6b187df2017-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 Glass741f2d62018-10-01 12:22:30 -06001241 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass6b187df2017-11-12 21:52:27 -07001242 U_BOOT_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001243 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1244 b' somewhere in here', first)
Simon Glasse0ff8552016-11-25 20:15:53 -07001245
Simon Glass160a7662017-05-27 07:38:26 -06001246 def _RunPackUbootSingleMicrocode(self):
Simon Glasse0ff8552016-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 Glass741f2d62018-10-01 12:22:30 -06001258 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glasse0ff8552016-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 Glass160a7662017-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 Glasse0ff8552016-11-25 20:15:53 -07001269
Simon Glass160a7662017-05-27 07:38:26 -06001270 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -06001271 # expected offset and size
Simon Glass160a7662017-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 Glassc6c10e72019-05-17 22:00:46 -06001275 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1276 b' somewhere in here', first)
Simon Glassc49deb82016-11-25 20:15:54 -07001277
Simon Glass75db0862016-11-25 20:15:55 -07001278 def testPackUbootSingleMicrocode(self):
1279 """Test that x86 microcode can be handled correctly with fdt_normal.
1280 """
Simon Glass160a7662017-05-27 07:38:26 -06001281 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001282
Simon Glassc49deb82016-11-25 20:15:54 -07001283 def testUBootImg(self):
1284 """Test that u-boot.img can be put in a file"""
Simon Glass741f2d62018-10-01 12:22:30 -06001285 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glassc49deb82016-11-25 20:15:54 -07001286 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glass75db0862016-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 Glass741f2d62018-10-01 12:22:30 -06001291 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glass75db0862016-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 Glass741f2d62018-10-01 12:22:30 -06001298 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glass75db0862016-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 Glass741f2d62018-10-01 12:22:30 -06001305 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glass75db0862016-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 Glass75db0862016-11-25 20:15:55 -07001312 try:
Simon Glassbccd91d2019-08-24 07:22:55 -06001313 TestFunctional._MakeInputFile('u-boot',
Simon Glassc1aa66e2022-01-29 14:14:04 -07001314 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass75db0862016-11-25 20:15:55 -07001315
1316 with self.assertRaises(ValueError) as e:
Simon Glass160a7662017-05-27 07:38:26 -06001317 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-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 Glassf514d8f2019-08-24 07:22:54 -06001323 TestFunctional._MakeInputFile('u-boot',
Simon Glassc1aa66e2022-01-29 14:14:04 -07001324 tools.read_file(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glass75db0862016-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 Glass741f2d62018-10-01 12:22:30 -06001329 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glass75db0862016-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 Glass25ac0e62018-06-01 09:38:14 -06001332 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glass75db0862016-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 Glassbccd91d2019-08-24 07:22:55 -06001336 TestFunctional._MakeInputFile('u-boot',
Simon Glassc1aa66e2022-01-29 14:14:04 -07001337 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass741f2d62018-10-01 12:22:30 -06001338 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glass75db0862016-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 Glassc1aa66e2022-01-29 14:14:04 -07001349 self.assertEqual(tools.get_bytes(0, 0x200 - used_len), third)
Simon Glass75db0862016-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 Glass741f2d62018-10-01 12:22:30 -06001354 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glass3ab95982018-08-01 15:22:37 -06001355 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glass75db0862016-11-25 20:15:55 -07001356 "entry 'invalid-entry'", str(e.exception))
Simon Glassda229092016-11-25 20:15:56 -07001357
1358 def testPackFsp(self):
1359 """Test that an image with a FSP binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001360 data = self._DoReadFile('042_intel_fsp.dts')
Simon Glassda229092016-11-25 20:15:56 -07001361 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1362
1363 def testPackCmc(self):
Bin Meng59ea8c22017-08-15 22:41:54 -07001364 """Test that an image with a CMC binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001365 data = self._DoReadFile('043_intel_cmc.dts')
Simon Glassda229092016-11-25 20:15:56 -07001366 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Meng59ea8c22017-08-15 22:41:54 -07001367
1368 def testPackVbt(self):
1369 """Test that an image with a VBT binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001370 data = self._DoReadFile('046_intel_vbt.dts')
Bin Meng59ea8c22017-08-15 22:41:54 -07001371 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glass9fc60b42017-11-12 21:52:22 -07001372
Simon Glass56509842017-11-12 21:52:25 -07001373 def testSplBssPad(self):
1374 """Test that we can pad SPL's BSS with zeros"""
Simon Glass6b187df2017-11-12 21:52:27 -07001375 # ELF file with a '__bss_size' symbol
Simon Glass11ae93e2018-10-01 21:12:47 -06001376 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001377 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001378 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glasse6d85ff2019-05-14 15:53:47 -06001379 data)
Simon Glass56509842017-11-12 21:52:25 -07001380
Simon Glass86af5112018-10-01 21:12:42 -06001381 def testSplBssPadMissing(self):
1382 """Test that a missing symbol is detected"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001383 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glassb50e5612017-11-13 18:54:54 -07001384 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001385 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassb50e5612017-11-13 18:54:54 -07001386 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1387 str(e.exception))
1388
Simon Glass87722132017-11-12 21:52:26 -07001389 def testPackStart16Spl(self):
Simon Glass35b384c2018-09-14 04:57:10 -06001390 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001391 data = self._DoReadFile('048_x86_start16_spl.dts')
Simon Glass87722132017-11-12 21:52:26 -07001392 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1393
Simon Glass736bb0a2018-07-06 10:27:17 -06001394 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1395 """Helper function for microcode tests
Simon Glass6b187df2017-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 Glass736bb0a2018-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 Glass6b187df2017-11-12 21:52:27 -07001407 """
Simon Glass11ae93e2018-10-01 21:12:47 -06001408 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass736bb0a2018-07-06 10:27:17 -06001409 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1410 ucode_second=ucode_second)
Simon Glassc6c10e72019-05-17 22:00:46 -06001411 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1412 b'ter somewhere in here', first)
Simon Glass6b187df2017-11-12 21:52:27 -07001413
Simon Glass736bb0a2018-07-06 10:27:17 -06001414 def testPackUbootSplMicrocode(self):
1415 """Test that x86 microcode can be handled correctly in SPL"""
Simon Glass741f2d62018-10-01 12:22:30 -06001416 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass736bb0a2018-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 Glass741f2d62018-10-01 12:22:30 -06001425 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass736bb0a2018-07-06 10:27:17 -06001426 ucode_second=True)
1427
Simon Glassca4f4ff2017-11-12 21:52:28 -07001428 def testPackMrc(self):
1429 """Test that an image with an MRC binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001430 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassca4f4ff2017-11-12 21:52:28 -07001431 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1432
Simon Glass47419ea2017-11-13 18:54:55 -07001433 def testSplDtb(self):
1434 """Test that an image with spl/u-boot-spl.dtb can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001435 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass47419ea2017-11-13 18:54:55 -07001436 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1437
Simon Glass4e6fdbe2017-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 Glass0fe44dc2021-04-25 08:39:32 +12001440 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001441 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001442 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1443
Simon Glass3d433382021-03-21 18:24:30 +13001444 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
1445 use_expanded=False):
Simon Glassf5898822021-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 Glass3d433382021-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 Glassf5898822021-03-18 20:24:56 +13001457 """
Simon Glass1542c8b2019-08-24 07:22:56 -06001458 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass19790632017-11-13 18:55:01 -07001459 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1460 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03001461 self.assertEqual(syms['_binman_sym_magic'].address, addr)
Simon Glassf5898822021-03-18 20:24:56 +13001462 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03001463 addr + 4)
Simon Glass19790632017-11-13 18:55:01 -07001464
Simon Glass11ae93e2018-10-01 21:12:47 -06001465 self._SetupSplElf('u_boot_binman_syms')
Simon Glass3d433382021-03-21 18:24:30 +13001466 data = self._DoReadFileDtb(dts, entry_args=entry_args,
1467 use_expanded=use_expanded)[0]
Simon Glassf5898822021-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 Yasak367ecbf2022-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 Glassf5898822021-03-18 20:24:56 +13001473 0x10 + u_boot_offset, 0x04)
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03001474 expected = (sym_values + base_data[24:] +
Simon Glassc1aa66e2022-01-29 14:14:04 -07001475 tools.get_bytes(0xff, 1) + U_BOOT_DATA + sym_values +
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03001476 base_data[24:])
Simon Glass19790632017-11-13 18:55:01 -07001477 self.assertEqual(expected, data)
1478
Simon Glassf5898822021-03-18 20:24:56 +13001479 def testSymbols(self):
1480 """Test binman can assign symbols embedded in U-Boot"""
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03001481 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glassf5898822021-03-18 20:24:56 +13001482
1483 def testSymbolsNoDtb(self):
1484 """Test binman can assign symbols embedded in U-Boot SPL"""
Simon Glasse9e0db82021-03-21 18:24:29 +13001485 self.checkSymbols('196_symbols_nodtb.dts',
Simon Glassf5898822021-03-18 20:24:56 +13001486 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1487 0x38)
1488
Simon Glassdd57c132018-06-01 09:38:11 -06001489 def testPackUnitAddress(self):
1490 """Test that we support multiple binaries with the same name"""
Simon Glass741f2d62018-10-01 12:22:30 -06001491 data = self._DoReadFile('054_unit_address.dts')
Simon Glassdd57c132018-06-01 09:38:11 -06001492 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1493
Simon Glass18546952018-06-01 09:38:16 -06001494 def testSections(self):
1495 """Basic test of sections"""
Simon Glass741f2d62018-10-01 12:22:30 -06001496 data = self._DoReadFile('055_sections.dts')
Simon Glassc1aa66e2022-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 Glass18546952018-06-01 09:38:16 -06001500 self.assertEqual(expected, data)
Simon Glass9fc60b42017-11-12 21:52:22 -07001501
Simon Glass3b0c38212018-06-01 09:38:20 -06001502 def testMap(self):
1503 """Tests outputting a map of the images"""
Simon Glass741f2d62018-10-01 12:22:30 -06001504 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001505 self.assertEqual('''ImagePos Offset Size Name
Simon Glass193d3db2023-02-07 14:34:18 -0700150600000000 00000000 00000028 image
Simon Glass1be70d22018-07-17 13:25:49 -0600150700000000 00000000 00000010 section@0
150800000000 00000000 00000004 u-boot
150900000010 00000010 00000010 section@1
151000000010 00000000 00000004 u-boot
151100000020 00000020 00000004 section@2
151200000020 00000000 00000004 u-boot
Simon Glass3b0c38212018-06-01 09:38:20 -06001513''', map_data)
1514
Simon Glassc8d48ef2018-06-01 09:38:21 -06001515 def testNamePrefix(self):
1516 """Tests that name prefixes are used"""
Simon Glass741f2d62018-10-01 12:22:30 -06001517 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001518 self.assertEqual('''ImagePos Offset Size Name
Simon Glass193d3db2023-02-07 14:34:18 -0700151900000000 00000000 00000028 image
Simon Glass1be70d22018-07-17 13:25:49 -0600152000000000 00000000 00000010 section@0
152100000000 00000000 00000004 ro-u-boot
152200000010 00000010 00000010 section@1
152300000010 00000000 00000004 rw-u-boot
Simon Glassc8d48ef2018-06-01 09:38:21 -06001524''', map_data)
1525
Simon Glass736bb0a2018-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 Glass741f2d62018-10-01 12:22:30 -06001529 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass8beb11e2019-07-08 14:25:47 -06001530 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glass16287932020-04-17 18:09:03 -06001531 "processing of contents: remaining ["
1532 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass736bb0a2018-07-06 10:27:17 -06001533
Simon Glass5c890232018-07-06 10:27:19 -06001534 def testBadChangeSize(self):
1535 """Test that trying to change the size of an entry fails"""
Simon Glassc52c9e72019-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 Glass79d3c582019-07-20 12:23:57 -06001540 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glassc52c9e72019-07-08 14:25:37 -06001541 str(e.exception))
1542 finally:
1543 state.SetAllowEntryExpansion(True)
Simon Glass5c890232018-07-06 10:27:19 -06001544
Simon Glass16b8d6b2018-07-06 10:27:42 -06001545 def testUpdateFdt(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001546 """Test that we can update the device tree with offset/size info"""
Simon Glass741f2d62018-10-01 12:22:30 -06001547 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glass16b8d6b2018-07-06 10:27:42 -06001548 update_dtb=True)
Simon Glasscee02e62018-07-17 13:25:52 -06001549 dtb = fdt.Fdt(out_dtb_fname)
1550 dtb.Scan()
Simon Glass12bb1a92019-07-20 12:23:51 -06001551 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001552 self.assertEqual({
Simon Glassdbf6be92018-08-01 15:22:42 -06001553 'image-pos': 0,
Simon Glass8122f392018-07-17 13:25:28 -06001554 'offset': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001555 '_testing:offset': 32,
Simon Glass79d3c582019-07-20 12:23:57 -06001556 '_testing:size': 2,
Simon Glassdbf6be92018-08-01 15:22:42 -06001557 '_testing:image-pos': 32,
Simon Glass3ab95982018-08-01 15:22:37 -06001558 'section@0/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001559 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001560 'section@0/u-boot:image-pos': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001561 'section@0:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001562 'section@0:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001563 'section@0:image-pos': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001564
Simon Glass3ab95982018-08-01 15:22:37 -06001565 'section@1/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001566 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001567 'section@1/u-boot:image-pos': 16,
Simon Glass3ab95982018-08-01 15:22:37 -06001568 'section@1:offset': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001569 'section@1:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001570 'section@1:image-pos': 16,
Simon Glass16b8d6b2018-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 Glass741f2d62018-10-01 12:22:30 -06001577 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001578 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glass16287932020-04-17 18:09:03 -06001579 '[<binman.etype._testing.Entry__testing',
1580 str(e.exception))
Simon Glass5c890232018-07-06 10:27:19 -06001581
Simon Glass53af22a2018-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 Glass741f2d62018-10-01 12:22:30 -06001588 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-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 Glass741f2d62018-10-01 12:22:30 -06001601 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass53af22a2018-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 Glass741f2d62018-10-01 12:22:30 -06001614 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass3decfa32020-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 Glass53af22a2018-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 Glass53cd5d92019-07-08 14:25:29 -06001622 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1623 '-ano-value']
Simon Glass53af22a2018-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 Glass741f2d62018-10-01 12:22:30 -06001634 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-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 Glass741f2d62018-10-01 12:22:30 -06001650 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass53af22a2018-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 Glassbb748372018-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 Glass741f2d62018-10-01 12:22:30 -06001662 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glassbb748372018-07-17 13:25:33 -06001663 entry_args=entry_args)
Simon Glassc1aa66e2022-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 Glassaa88b502019-07-08 13:18:40 -06001667 b'some text' + b'more text')
Simon Glassbb748372018-07-17 13:25:33 -06001668 self.assertEqual(expected, data)
1669
Simon Glassfd8d1f72018-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 Glass87d43322020-08-05 13:27:46 -06001673 control.WriteEntryDocs(control.GetEntryModules())
Simon Glassfd8d1f72018-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 Glass87d43322020-08-05 13:27:46 -06001680 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glassfd8d1f72018-07-17 13:25:36 -06001681 self.assertIn('Documentation is missing for modules: u_boot',
1682 str(e.exception))
1683
Simon Glass11e36cc2018-07-17 13:25:38 -06001684 def testFmap(self):
1685 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001686 data = self._DoReadFile('067_fmap.dts')
Simon Glass11e36cc2018-07-17 13:25:38 -06001687 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc1aa66e2022-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 Glass11e36cc2018-07-17 13:25:38 -06001690 self.assertEqual(expected, data[:32])
Simon Glassc6c10e72019-05-17 22:00:46 -06001691 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass11e36cc2018-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 Glass17365752021-04-03 11:05:10 +13001695 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 5
Simon Glassc7722e82021-04-03 11:05:09 +13001696 self.assertEqual(16 + 16 + expect_size, fhdr.image_size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001697 self.assertEqual(b'FMAP', fhdr.name)
Simon Glass17365752021-04-03 11:05:10 +13001698 self.assertEqual(5, fhdr.nareas)
Simon Glassc7722e82021-04-03 11:05:09 +13001699 fiter = iter(fentries)
Simon Glass11e36cc2018-07-17 13:25:38 -06001700
Simon Glassc7722e82021-04-03 11:05:09 +13001701 fentry = next(fiter)
Simon Glass17365752021-04-03 11:05:10 +13001702 self.assertEqual(b'SECTION0', fentry.name)
1703 self.assertEqual(0, fentry.offset)
1704 self.assertEqual(16, fentry.size)
Simon Glass9dbb02b2023-02-12 17:11:15 -07001705 self.assertEqual(fmap_util.FMAP_AREA_PRESERVE, fentry.flags)
Simon Glass17365752021-04-03 11:05:10 +13001706
1707 fentry = next(fiter)
Simon Glassc7722e82021-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 Glass11e36cc2018-07-17 13:25:38 -06001712
Simon Glassc7722e82021-04-03 11:05:09 +13001713 fentry = next(fiter)
Simon Glass17365752021-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 Glassc7722e82021-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 Glass11e36cc2018-07-17 13:25:38 -06001724
Simon Glassc7722e82021-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 Glass11e36cc2018-07-17 13:25:38 -06001730
Simon Glassec127af2018-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 Glass3decfa32020-09-01 05:13:54 -06001736 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassec127af2018-07-17 13:25:39 -06001737
Simon Glass3af8e492018-07-17 13:25:40 -06001738 def testFill(self):
1739 """Test for an fill entry type"""
Simon Glass741f2d62018-10-01 12:22:30 -06001740 data = self._DoReadFile('069_fill.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001741 expected = tools.get_bytes(0xff, 8) + tools.get_bytes(0, 8)
Simon Glass3af8e492018-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 Glass741f2d62018-10-01 12:22:30 -06001747 self._DoReadFile('070_fill_no_size.dts')
Simon Glasscdadada2022-08-13 11:40:44 -06001748 self.assertIn("'fill' entry is missing properties: size",
Simon Glass3af8e492018-07-17 13:25:40 -06001749 str(e.exception))
1750
Simon Glass0ef87aa2018-07-17 13:25:44 -06001751 def _HandleGbbCommand(self, pipe_list):
1752 """Fake calls to the futility utility"""
Simon Glassfe7e9242023-02-22 12:14:49 -07001753 if 'futility' in pipe_list[0][0]:
Simon Glass0ef87aa2018-07-17 13:25:44 -06001754 fname = pipe_list[0][-1]
1755 # Append our GBB data to the file, which will happen every time the
1756 # futility command is called.
Simon Glass1d0ebf72019-05-14 15:53:42 -06001757 with open(fname, 'ab') as fd:
Simon Glass0ef87aa2018-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 Glass741f2d62018-10-01 12:22:30 -06001768 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glass0ef87aa2018-07-17 13:25:44 -06001769
1770 # Since futility
Simon Glassc1aa66e2022-01-29 14:14:04 -07001771 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
1772 tools.get_bytes(0, 0x2180 - 16))
Simon Glass0ef87aa2018-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 Glass741f2d62018-10-01 12:22:30 -06001778 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glass0ef87aa2018-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 Glass741f2d62018-10-01 12:22:30 -06001785 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001786 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1787 str(e.exception))
1788
Simon Glass4f9ee832022-01-09 20:14:09 -07001789 def testGbbMissing(self):
1790 """Test that binman still produces an image if futility is missing"""
1791 entry_args = {
1792 'keydir': 'devkeys',
1793 }
1794 with test_util.capture_sys_output() as (_, stderr):
1795 self._DoTestFile('071_gbb.dts', force_missing_bintools='futility',
1796 entry_args=entry_args)
1797 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07001798 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass4f9ee832022-01-09 20:14:09 -07001799
Simon Glass24d0d3c2018-07-17 13:25:47 -06001800 def _HandleVblockCommand(self, pipe_list):
Simon Glass5af9ebc2021-01-06 21:35:17 -07001801 """Fake calls to the futility utility
1802
1803 The expected pipe is:
1804
1805 [('futility', 'vbutil_firmware', '--vblock',
1806 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1807 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1808 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1809 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1810
1811 This writes to the output file (here, 'vblock.vblock'). If
1812 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1813 of the input data (here, 'input.vblock').
1814 """
Simon Glassfe7e9242023-02-22 12:14:49 -07001815 if 'futility' in pipe_list[0][0]:
Simon Glass24d0d3c2018-07-17 13:25:47 -06001816 fname = pipe_list[0][3]
Simon Glassa326b492018-09-14 04:57:11 -06001817 with open(fname, 'wb') as fd:
Simon Glass5af9ebc2021-01-06 21:35:17 -07001818 if self._hash_data:
1819 infile = pipe_list[0][11]
1820 m = hashlib.sha256()
Simon Glassc1aa66e2022-01-29 14:14:04 -07001821 data = tools.read_file(infile)
Simon Glass5af9ebc2021-01-06 21:35:17 -07001822 m.update(data)
1823 fd.write(m.digest())
1824 else:
1825 fd.write(VBLOCK_DATA)
1826
Simon Glass24d0d3c2018-07-17 13:25:47 -06001827 return command.CommandResult()
1828
1829 def testVblock(self):
1830 """Test for the Chromium OS Verified Boot Block"""
Simon Glass5af9ebc2021-01-06 21:35:17 -07001831 self._hash_data = False
Simon Glass24d0d3c2018-07-17 13:25:47 -06001832 command.test_result = self._HandleVblockCommand
1833 entry_args = {
1834 'keydir': 'devkeys',
1835 }
Simon Glass741f2d62018-10-01 12:22:30 -06001836 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass24d0d3c2018-07-17 13:25:47 -06001837 entry_args=entry_args)
1838 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1839 self.assertEqual(expected, data)
1840
1841 def testVblockNoContent(self):
1842 """Test we detect a vblock which has no content to sign"""
1843 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001844 self._DoReadFile('075_vblock_no_content.dts')
Simon Glass189f2912021-03-21 18:24:31 +13001845 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
Simon Glass24d0d3c2018-07-17 13:25:47 -06001846 'property', str(e.exception))
1847
1848 def testVblockBadPhandle(self):
1849 """Test that we detect a vblock with an invalid phandle in contents"""
1850 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001851 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001852 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1853 '1000', str(e.exception))
1854
1855 def testVblockBadEntry(self):
1856 """Test that we detect an entry that points to a non-entry"""
1857 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001858 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001859 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1860 "'other'", str(e.exception))
1861
Simon Glass5af9ebc2021-01-06 21:35:17 -07001862 def testVblockContent(self):
1863 """Test that the vblock signs the right data"""
1864 self._hash_data = True
1865 command.test_result = self._HandleVblockCommand
1866 entry_args = {
1867 'keydir': 'devkeys',
1868 }
1869 data = self._DoReadFileDtb(
1870 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1871 entry_args=entry_args)[0]
1872 hashlen = 32 # SHA256 hash is 32 bytes
1873 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1874 hashval = data[-hashlen:]
1875 dtb = data[len(U_BOOT_DATA):-hashlen]
1876
1877 expected_data = U_BOOT_DATA + dtb
1878
1879 # The hashval should be a hash of the dtb
1880 m = hashlib.sha256()
1881 m.update(expected_data)
1882 expected_hashval = m.digest()
1883 self.assertEqual(expected_hashval, hashval)
1884
Simon Glass4f9ee832022-01-09 20:14:09 -07001885 def testVblockMissing(self):
1886 """Test that binman still produces an image if futility is missing"""
1887 entry_args = {
1888 'keydir': 'devkeys',
1889 }
1890 with test_util.capture_sys_output() as (_, stderr):
1891 self._DoTestFile('074_vblock.dts',
1892 force_missing_bintools='futility',
1893 entry_args=entry_args)
1894 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07001895 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass4f9ee832022-01-09 20:14:09 -07001896
Simon Glassb8ef5b62018-07-17 13:25:48 -06001897 def testTpl(self):
Simon Glass2090f1e2019-08-24 07:23:00 -06001898 """Test that an image with TPL and its device tree can be created"""
Simon Glassb8ef5b62018-07-17 13:25:48 -06001899 # ELF file with a '__bss_size' symbol
Simon Glass2090f1e2019-08-24 07:23:00 -06001900 self._SetupTplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001901 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glassb8ef5b62018-07-17 13:25:48 -06001902 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1903
Simon Glass15a587c2018-07-17 13:25:51 -06001904 def testUsesPos(self):
1905 """Test that the 'pos' property cannot be used anymore"""
1906 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001907 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass15a587c2018-07-17 13:25:51 -06001908 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1909 "'pos'", str(e.exception))
1910
Simon Glassd178eab2018-09-14 04:57:08 -06001911 def testFillZero(self):
1912 """Test for an fill entry type with a size of 0"""
Simon Glass741f2d62018-10-01 12:22:30 -06001913 data = self._DoReadFile('080_fill_empty.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001914 self.assertEqual(tools.get_bytes(0, 16), data)
Simon Glassd178eab2018-09-14 04:57:08 -06001915
Simon Glass0b489362018-09-14 04:57:09 -06001916 def testTextMissing(self):
1917 """Test for a text entry type where there is no text"""
1918 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001919 self._DoReadFileDtb('066_text.dts',)
Simon Glass0b489362018-09-14 04:57:09 -06001920 self.assertIn("Node '/binman/text': No value provided for text label "
1921 "'test-id'", str(e.exception))
1922
Simon Glass35b384c2018-09-14 04:57:10 -06001923 def testPackStart16Tpl(self):
1924 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001925 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glass35b384c2018-09-14 04:57:10 -06001926 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1927
Simon Glass0bfa7b02018-09-14 04:57:12 -06001928 def testSelectImage(self):
1929 """Test that we can select which images to build"""
Simon Glasseb833d82019-04-25 21:58:34 -06001930 expected = 'Skipping images: image1'
Simon Glass0bfa7b02018-09-14 04:57:12 -06001931
Simon Glasseb833d82019-04-25 21:58:34 -06001932 # We should only get the expected message in verbose mode
Simon Glassee0c9a72019-07-08 13:18:48 -06001933 for verbosity in (0, 2):
Simon Glasseb833d82019-04-25 21:58:34 -06001934 with test_util.capture_sys_output() as (stdout, stderr):
1935 retcode = self._DoTestFile('006_dual_image.dts',
1936 verbosity=verbosity,
1937 images=['image2'])
1938 self.assertEqual(0, retcode)
1939 if verbosity:
1940 self.assertIn(expected, stdout.getvalue())
1941 else:
1942 self.assertNotIn(expected, stdout.getvalue())
1943
Simon Glassc1aa66e2022-01-29 14:14:04 -07001944 self.assertFalse(os.path.exists(tools.get_output_filename('image1.bin')))
1945 self.assertTrue(os.path.exists(tools.get_output_filename('image2.bin')))
Simon Glassf86a7362019-07-20 12:24:10 -06001946 self._CleanupOutputDir()
Simon Glass0bfa7b02018-09-14 04:57:12 -06001947
Simon Glass6ed45ba2018-09-14 04:57:24 -06001948 def testUpdateFdtAll(self):
1949 """Test that all device trees are updated with offset/size info"""
Simon Glass3c081312019-07-08 14:25:26 -06001950 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glass6ed45ba2018-09-14 04:57:24 -06001951
1952 base_expected = {
Simon Glass6ed45ba2018-09-14 04:57:24 -06001953 'offset': 0,
Simon Glass6ad24522022-02-28 07:16:54 -07001954 'image-pos': 0,
1955 'size': 2320,
Simon Glass6ed45ba2018-09-14 04:57:24 -06001956 'section:offset': 0,
Simon Glass6ad24522022-02-28 07:16:54 -07001957 'section:image-pos': 0,
1958 'section:size': 565,
1959 'section/u-boot-dtb:offset': 0,
1960 'section/u-boot-dtb:image-pos': 0,
1961 'section/u-boot-dtb:size': 565,
1962 'u-boot-spl-dtb:offset': 565,
1963 'u-boot-spl-dtb:image-pos': 565,
1964 'u-boot-spl-dtb:size': 585,
1965 'u-boot-tpl-dtb:offset': 1150,
1966 'u-boot-tpl-dtb:image-pos': 1150,
1967 'u-boot-tpl-dtb:size': 585,
1968 'u-boot-vpl-dtb:image-pos': 1735,
1969 'u-boot-vpl-dtb:offset': 1735,
1970 'u-boot-vpl-dtb:size': 585,
Simon Glass6ed45ba2018-09-14 04:57:24 -06001971 }
1972
1973 # We expect three device-tree files in the output, one after the other.
1974 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1975 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1976 # main U-Boot tree. All three should have the same postions and offset.
1977 start = 0
Simon Glass6ad24522022-02-28 07:16:54 -07001978 self.maxDiff = None
1979 for item in ['', 'spl', 'tpl', 'vpl']:
Simon Glass6ed45ba2018-09-14 04:57:24 -06001980 dtb = fdt.Fdt.FromData(data[start:])
1981 dtb.Scan()
Simon Glass12bb1a92019-07-20 12:23:51 -06001982 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
Simon Glass6ad24522022-02-28 07:16:54 -07001983 ['spl', 'tpl', 'vpl'])
Simon Glass6ed45ba2018-09-14 04:57:24 -06001984 expected = dict(base_expected)
1985 if item:
1986 expected[item] = 0
1987 self.assertEqual(expected, props)
1988 start += dtb._fdt_obj.totalsize()
1989
1990 def testUpdateFdtOutput(self):
1991 """Test that output DTB files are updated"""
1992 try:
Simon Glass741f2d62018-10-01 12:22:30 -06001993 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glass6ed45ba2018-09-14 04:57:24 -06001994 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1995
1996 # Unfortunately, compiling a source file always results in a file
1997 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass741f2d62018-10-01 12:22:30 -06001998 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glass6ed45ba2018-09-14 04:57:24 -06001999 # binman as a file called u-boot.dtb. To fix this, copy the file
2000 # over to the expected place.
Simon Glass6ed45ba2018-09-14 04:57:24 -06002001 start = 0
2002 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
Simon Glass6ad24522022-02-28 07:16:54 -07002003 'tpl/u-boot-tpl.dtb.out', 'vpl/u-boot-vpl.dtb.out']:
Simon Glass6ed45ba2018-09-14 04:57:24 -06002004 dtb = fdt.Fdt.FromData(data[start:])
2005 size = dtb._fdt_obj.totalsize()
Simon Glassc1aa66e2022-01-29 14:14:04 -07002006 pathname = tools.get_output_filename(os.path.split(fname)[1])
2007 outdata = tools.read_file(pathname)
Simon Glass6ed45ba2018-09-14 04:57:24 -06002008 name = os.path.split(fname)[0]
2009
2010 if name:
Simon Glass6ad24522022-02-28 07:16:54 -07002011 orig_indata = self._GetDtbContentsForSpls(dtb_data, name)
Simon Glass6ed45ba2018-09-14 04:57:24 -06002012 else:
2013 orig_indata = dtb_data
2014 self.assertNotEqual(outdata, orig_indata,
2015 "Expected output file '%s' be updated" % pathname)
2016 self.assertEqual(outdata, data[start:start + size],
2017 "Expected output file '%s' to match output image" %
2018 pathname)
2019 start += size
2020 finally:
2021 self._ResetDtbs()
2022
Simon Glass83d73c22018-09-14 04:57:26 -06002023 def _decompress(self, data):
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +02002024 bintool = self.comp_bintools['lz4']
2025 return bintool.decompress(data)
Simon Glass83d73c22018-09-14 04:57:26 -06002026
2027 def testCompress(self):
2028 """Test compression of blobs"""
Simon Glassac62fba2019-07-08 13:18:53 -06002029 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06002030 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass83d73c22018-09-14 04:57:26 -06002031 use_real_dtb=True, update_dtb=True)
2032 dtb = fdt.Fdt(out_dtb_fname)
2033 dtb.Scan()
2034 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2035 orig = self._decompress(data)
2036 self.assertEquals(COMPRESS_DATA, orig)
Simon Glass97c3e9a2020-10-26 17:40:15 -06002037
2038 # Do a sanity check on various fields
2039 image = control.images['image']
2040 entries = image.GetEntries()
2041 self.assertEqual(1, len(entries))
2042
2043 entry = entries['blob']
2044 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
2045 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
2046 orig = self._decompress(entry.data)
2047 self.assertEqual(orig, entry.uncomp_data)
2048
Simon Glass63e7ba62020-10-26 17:40:16 -06002049 self.assertEqual(image.data, entry.data)
2050
Simon Glass83d73c22018-09-14 04:57:26 -06002051 expected = {
2052 'blob:uncomp-size': len(COMPRESS_DATA),
2053 'blob:size': len(data),
2054 'size': len(data),
2055 }
2056 self.assertEqual(expected, props)
2057
Simon Glass0a98b282018-09-14 04:57:28 -06002058 def testFiles(self):
2059 """Test bringing in multiple files"""
Simon Glass741f2d62018-10-01 12:22:30 -06002060 data = self._DoReadFile('084_files.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06002061 self.assertEqual(FILES_DATA, data)
2062
2063 def testFilesCompress(self):
2064 """Test bringing in multiple files and compressing them"""
Simon Glassac62fba2019-07-08 13:18:53 -06002065 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06002066 data = self._DoReadFile('085_files_compress.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06002067
2068 image = control.images['image']
2069 entries = image.GetEntries()
2070 files = entries['files']
Simon Glass8beb11e2019-07-08 14:25:47 -06002071 entries = files._entries
Simon Glass0a98b282018-09-14 04:57:28 -06002072
Simon Glassc6c10e72019-05-17 22:00:46 -06002073 orig = b''
Simon Glass0a98b282018-09-14 04:57:28 -06002074 for i in range(1, 3):
2075 key = '%d.dat' % i
2076 start = entries[key].image_pos
2077 len = entries[key].size
2078 chunk = data[start:start + len]
2079 orig += self._decompress(chunk)
2080
2081 self.assertEqual(FILES_DATA, orig)
2082
2083 def testFilesMissing(self):
2084 """Test missing files"""
2085 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002086 data = self._DoReadFile('086_files_none.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06002087 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
2088 'no files', str(e.exception))
2089
2090 def testFilesNoPattern(self):
2091 """Test missing files"""
2092 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002093 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06002094 self.assertIn("Node '/binman/files': Missing 'pattern' property",
2095 str(e.exception))
2096
Simon Glass80a66ae2022-03-05 20:18:59 -07002097 def testExtendSize(self):
2098 """Test an extending entry"""
2099 data, _, map_data, _ = self._DoReadFileDtb('088_extend_size.dts',
Simon Glassba64a0b2018-09-14 04:57:29 -06002100 map=True)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002101 expect = (tools.get_bytes(ord('a'), 8) + U_BOOT_DATA +
2102 MRC_DATA + tools.get_bytes(ord('b'), 1) + U_BOOT_DATA +
2103 tools.get_bytes(ord('c'), 8) + U_BOOT_DATA +
2104 tools.get_bytes(ord('d'), 8))
Simon Glassba64a0b2018-09-14 04:57:29 -06002105 self.assertEqual(expect, data)
2106 self.assertEqual('''ImagePos Offset Size Name
Simon Glass193d3db2023-02-07 14:34:18 -0700210700000000 00000000 00000028 image
Simon Glassba64a0b2018-09-14 04:57:29 -0600210800000000 00000000 00000008 fill
210900000008 00000008 00000004 u-boot
21100000000c 0000000c 00000004 section
21110000000c 00000000 00000003 intel-mrc
211200000010 00000010 00000004 u-boot2
211300000014 00000014 0000000c section2
211400000014 00000000 00000008 fill
21150000001c 00000008 00000004 u-boot
211600000020 00000020 00000008 fill2
2117''', map_data)
2118
Simon Glass80a66ae2022-03-05 20:18:59 -07002119 def testExtendSizeBad(self):
2120 """Test an extending entry which fails to provide contents"""
Simon Glass163ed6c2018-09-14 04:57:36 -06002121 with test_util.capture_sys_output() as (stdout, stderr):
2122 with self.assertRaises(ValueError) as e:
Simon Glass80a66ae2022-03-05 20:18:59 -07002123 self._DoReadFileDtb('089_extend_size_bad.dts', map=True)
Simon Glassba64a0b2018-09-14 04:57:29 -06002124 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
2125 'expanding entry', str(e.exception))
2126
Simon Glasse0e5df92018-09-14 04:57:31 -06002127 def testHash(self):
2128 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06002129 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06002130 use_real_dtb=True, update_dtb=True)
2131 dtb = fdt.Fdt(out_dtb_fname)
2132 dtb.Scan()
2133 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
2134 m = hashlib.sha256()
2135 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06002136 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06002137
2138 def testHashNoAlgo(self):
2139 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002140 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06002141 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2142 'hash node', str(e.exception))
2143
2144 def testHashBadAlgo(self):
2145 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002146 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glass8db1f992022-02-08 10:59:44 -07002147 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm 'invalid'",
Simon Glasse0e5df92018-09-14 04:57:31 -06002148 str(e.exception))
2149
2150 def testHashSection(self):
2151 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06002152 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06002153 use_real_dtb=True, update_dtb=True)
2154 dtb = fdt.Fdt(out_dtb_fname)
2155 dtb.Scan()
2156 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2157 m = hashlib.sha256()
2158 m.update(U_BOOT_DATA)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002159 m.update(tools.get_bytes(ord('a'), 16))
Simon Glassc6c10e72019-05-17 22:00:46 -06002160 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06002161
Simon Glassf0253632018-09-14 04:57:32 -06002162 def testPackUBootTplMicrocode(self):
2163 """Test that x86 microcode can be handled correctly in TPL
2164
2165 We expect to see the following in the image, in order:
2166 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2167 place
2168 u-boot-tpl.dtb with the microcode removed
2169 the microcode
2170 """
Simon Glass2090f1e2019-08-24 07:23:00 -06002171 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass741f2d62018-10-01 12:22:30 -06002172 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glassf0253632018-09-14 04:57:32 -06002173 U_BOOT_TPL_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06002174 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2175 b'ter somewhere in here', first)
Simon Glassf0253632018-09-14 04:57:32 -06002176
Simon Glassf8f8df62018-09-14 04:57:34 -06002177 def testFmapX86(self):
2178 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06002179 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassf8f8df62018-09-14 04:57:34 -06002180 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc1aa66e2022-01-29 14:14:04 -07002181 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('a'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06002182 self.assertEqual(expected, data[:32])
2183 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2184
2185 self.assertEqual(0x100, fhdr.image_size)
2186
2187 self.assertEqual(0, fentries[0].offset)
2188 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06002189 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06002190
2191 self.assertEqual(4, fentries[1].offset)
2192 self.assertEqual(3, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06002193 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06002194
2195 self.assertEqual(32, fentries[2].offset)
2196 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2197 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06002198 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06002199
2200 def testFmapX86Section(self):
2201 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06002202 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002203 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('b'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06002204 self.assertEqual(expected, data[:32])
2205 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2206
Simon Glass17365752021-04-03 11:05:10 +13002207 self.assertEqual(0x180, fhdr.image_size)
2208 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
Simon Glassc7722e82021-04-03 11:05:09 +13002209 fiter = iter(fentries)
Simon Glassf8f8df62018-09-14 04:57:34 -06002210
Simon Glassc7722e82021-04-03 11:05:09 +13002211 fentry = next(fiter)
2212 self.assertEqual(b'U_BOOT', fentry.name)
2213 self.assertEqual(0, fentry.offset)
2214 self.assertEqual(4, fentry.size)
Simon Glassf8f8df62018-09-14 04:57:34 -06002215
Simon Glassc7722e82021-04-03 11:05:09 +13002216 fentry = next(fiter)
Simon Glass17365752021-04-03 11:05:10 +13002217 self.assertEqual(b'SECTION', fentry.name)
2218 self.assertEqual(4, fentry.offset)
2219 self.assertEqual(0x20 + expect_size, fentry.size)
2220
2221 fentry = next(fiter)
Simon Glassc7722e82021-04-03 11:05:09 +13002222 self.assertEqual(b'INTEL_MRC', fentry.name)
2223 self.assertEqual(4, fentry.offset)
2224 self.assertEqual(3, fentry.size)
Simon Glassf8f8df62018-09-14 04:57:34 -06002225
Simon Glassc7722e82021-04-03 11:05:09 +13002226 fentry = next(fiter)
2227 self.assertEqual(b'FMAP', fentry.name)
2228 self.assertEqual(36, fentry.offset)
2229 self.assertEqual(expect_size, fentry.size)
Simon Glassf8f8df62018-09-14 04:57:34 -06002230
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002231 def testElf(self):
2232 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06002233 self._SetupSplElf()
Simon Glass2090f1e2019-08-24 07:23:00 -06002234 self._SetupTplElf()
Simon Glass53e22bf2019-08-24 07:22:53 -06002235 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002236 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06002237 data = self._DoReadFile('096_elf.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002238
Simon Glass093d1682019-07-08 13:18:25 -06002239 def testElfStrip(self):
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002240 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06002241 self._SetupSplElf()
Simon Glass53e22bf2019-08-24 07:22:53 -06002242 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002243 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06002244 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002245
Simon Glass163ed6c2018-09-14 04:57:36 -06002246 def testPackOverlapMap(self):
2247 """Test that overlapping regions are detected"""
2248 with test_util.capture_sys_output() as (stdout, stderr):
2249 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002250 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002251 map_fname = tools.get_output_filename('image.map')
Simon Glass163ed6c2018-09-14 04:57:36 -06002252 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2253 stdout.getvalue())
2254
2255 # We should not get an inmage, but there should be a map file
Simon Glassc1aa66e2022-01-29 14:14:04 -07002256 self.assertFalse(os.path.exists(tools.get_output_filename('image.bin')))
Simon Glass163ed6c2018-09-14 04:57:36 -06002257 self.assertTrue(os.path.exists(map_fname))
Simon Glassc1aa66e2022-01-29 14:14:04 -07002258 map_data = tools.read_file(map_fname, binary=False)
Simon Glass163ed6c2018-09-14 04:57:36 -06002259 self.assertEqual('''ImagePos Offset Size Name
Simon Glass193d3db2023-02-07 14:34:18 -07002260<none> 00000000 00000008 image
Simon Glass163ed6c2018-09-14 04:57:36 -06002261<none> 00000000 00000004 u-boot
2262<none> 00000003 00000004 u-boot-align
2263''', map_data)
2264
Simon Glass093d1682019-07-08 13:18:25 -06002265 def testPackRefCode(self):
Simon Glass3ae192c2018-10-01 12:22:31 -06002266 """Test that an image with an Intel Reference code binary works"""
2267 data = self._DoReadFile('100_intel_refcode.dts')
2268 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2269
Simon Glass9481c802019-04-25 21:58:39 -06002270 def testSectionOffset(self):
2271 """Tests use of a section with an offset"""
2272 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2273 map=True)
2274 self.assertEqual('''ImagePos Offset Size Name
Simon Glass193d3db2023-02-07 14:34:18 -0700227500000000 00000000 00000038 image
Simon Glass9481c802019-04-25 21:58:39 -0600227600000004 00000004 00000010 section@0
227700000004 00000000 00000004 u-boot
227800000018 00000018 00000010 section@1
227900000018 00000000 00000004 u-boot
22800000002c 0000002c 00000004 section@2
22810000002c 00000000 00000004 u-boot
2282''', map_data)
2283 self.assertEqual(data,
Simon Glassc1aa66e2022-01-29 14:14:04 -07002284 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2285 tools.get_bytes(0x21, 12) +
2286 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2287 tools.get_bytes(0x61, 12) +
2288 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2289 tools.get_bytes(0x26, 8))
Simon Glass9481c802019-04-25 21:58:39 -06002290
Simon Glassac62fba2019-07-08 13:18:53 -06002291 def testCbfsRaw(self):
2292 """Test base handling of a Coreboot Filesystem (CBFS)
2293
2294 The exact contents of the CBFS is verified by similar tests in
2295 cbfs_util_test.py. The tests here merely check that the files added to
2296 the CBFS can be found in the final image.
2297 """
2298 data = self._DoReadFile('102_cbfs_raw.dts')
2299 size = 0xb0
2300
2301 cbfs = cbfs_util.CbfsReader(data)
2302 self.assertEqual(size, cbfs.rom_size)
2303
2304 self.assertIn('u-boot-dtb', cbfs.files)
2305 cfile = cbfs.files['u-boot-dtb']
2306 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2307
2308 def testCbfsArch(self):
2309 """Test on non-x86 architecture"""
2310 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2311 size = 0x100
2312
2313 cbfs = cbfs_util.CbfsReader(data)
2314 self.assertEqual(size, cbfs.rom_size)
2315
2316 self.assertIn('u-boot-dtb', cbfs.files)
2317 cfile = cbfs.files['u-boot-dtb']
2318 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2319
2320 def testCbfsStage(self):
2321 """Tests handling of a Coreboot Filesystem (CBFS)"""
2322 if not elf.ELF_TOOLS:
2323 self.skipTest('Python elftools not available')
2324 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2325 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2326 size = 0xb0
2327
2328 data = self._DoReadFile('104_cbfs_stage.dts')
2329 cbfs = cbfs_util.CbfsReader(data)
2330 self.assertEqual(size, cbfs.rom_size)
2331
2332 self.assertIn('u-boot', cbfs.files)
2333 cfile = cbfs.files['u-boot']
2334 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2335
2336 def testCbfsRawCompress(self):
2337 """Test handling of compressing raw files"""
2338 self._CheckLz4()
2339 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2340 size = 0x140
2341
2342 cbfs = cbfs_util.CbfsReader(data)
2343 self.assertIn('u-boot', cbfs.files)
2344 cfile = cbfs.files['u-boot']
2345 self.assertEqual(COMPRESS_DATA, cfile.data)
2346
2347 def testCbfsBadArch(self):
2348 """Test handling of a bad architecture"""
2349 with self.assertRaises(ValueError) as e:
2350 self._DoReadFile('106_cbfs_bad_arch.dts')
2351 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2352
2353 def testCbfsNoSize(self):
2354 """Test handling of a missing size property"""
2355 with self.assertRaises(ValueError) as e:
2356 self._DoReadFile('107_cbfs_no_size.dts')
2357 self.assertIn('entry must have a size property', str(e.exception))
2358
Simon Glasse2f04742021-11-23 11:03:54 -07002359 def testCbfsNoContents(self):
Simon Glassac62fba2019-07-08 13:18:53 -06002360 """Test handling of a CBFS entry which does not provide contentsy"""
2361 with self.assertRaises(ValueError) as e:
2362 self._DoReadFile('108_cbfs_no_contents.dts')
2363 self.assertIn('Could not complete processing of contents',
2364 str(e.exception))
2365
2366 def testCbfsBadCompress(self):
2367 """Test handling of a bad architecture"""
2368 with self.assertRaises(ValueError) as e:
2369 self._DoReadFile('109_cbfs_bad_compress.dts')
2370 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2371 str(e.exception))
2372
2373 def testCbfsNamedEntries(self):
2374 """Test handling of named entries"""
2375 data = self._DoReadFile('110_cbfs_name.dts')
2376
2377 cbfs = cbfs_util.CbfsReader(data)
2378 self.assertIn('FRED', cbfs.files)
2379 cfile1 = cbfs.files['FRED']
2380 self.assertEqual(U_BOOT_DATA, cfile1.data)
2381
2382 self.assertIn('hello', cbfs.files)
2383 cfile2 = cbfs.files['hello']
2384 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2385
Simon Glassc5ac1382019-07-08 13:18:54 -06002386 def _SetupIfwi(self, fname):
2387 """Set up to run an IFWI test
2388
2389 Args:
2390 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2391 """
2392 self._SetupSplElf()
Simon Glass2090f1e2019-08-24 07:23:00 -06002393 self._SetupTplElf()
Simon Glassc5ac1382019-07-08 13:18:54 -06002394
2395 # Intel Integrated Firmware Image (IFWI) file
2396 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2397 data = fd.read()
2398 TestFunctional._MakeInputFile(fname,data)
2399
2400 def _CheckIfwi(self, data):
2401 """Check that an image with an IFWI contains the correct output
2402
2403 Args:
2404 data: Conents of output file
2405 """
Simon Glassc1aa66e2022-01-29 14:14:04 -07002406 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glassc5ac1382019-07-08 13:18:54 -06002407 if data[:0x1000] != expected_desc:
2408 self.fail('Expected descriptor binary at start of image')
2409
2410 # We expect to find the TPL wil in subpart IBBP entry IBBL
Simon Glassc1aa66e2022-01-29 14:14:04 -07002411 image_fname = tools.get_output_filename('image.bin')
2412 tpl_fname = tools.get_output_filename('tpl.out')
Simon Glass532ae702022-01-09 20:14:01 -07002413 ifwitool = bintool.Bintool.create('ifwitool')
2414 ifwitool.extract(image_fname, 'IBBP', 'IBBL', tpl_fname)
Simon Glassc5ac1382019-07-08 13:18:54 -06002415
Simon Glassc1aa66e2022-01-29 14:14:04 -07002416 tpl_data = tools.read_file(tpl_fname)
Simon Glasse95be632019-08-24 07:22:51 -06002417 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glassc5ac1382019-07-08 13:18:54 -06002418
2419 def testPackX86RomIfwi(self):
2420 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2421 self._SetupIfwi('fitimage.bin')
Simon Glass9255f3c2019-08-24 07:23:01 -06002422 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002423 self._CheckIfwi(data)
2424
2425 def testPackX86RomIfwiNoDesc(self):
2426 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2427 self._SetupIfwi('ifwi.bin')
Simon Glass9255f3c2019-08-24 07:23:01 -06002428 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002429 self._CheckIfwi(data)
2430
2431 def testPackX86RomIfwiNoData(self):
2432 """Test that an x86 ROM with IFWI handles missing data"""
2433 self._SetupIfwi('ifwi.bin')
2434 with self.assertRaises(ValueError) as e:
Simon Glass9255f3c2019-08-24 07:23:01 -06002435 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002436 self.assertIn('Could not complete processing of contents',
2437 str(e.exception))
Simon Glass53af22a2018-07-17 13:25:32 -06002438
Simon Glass4f9ee832022-01-09 20:14:09 -07002439 def testIfwiMissing(self):
2440 """Test that binman still produces an image if ifwitool is missing"""
2441 self._SetupIfwi('fitimage.bin')
2442 with test_util.capture_sys_output() as (_, stderr):
2443 self._DoTestFile('111_x86_rom_ifwi.dts',
2444 force_missing_bintools='ifwitool')
2445 err = stderr.getvalue()
2446 self.assertRegex(err,
Simon Glass193d3db2023-02-07 14:34:18 -07002447 "Image 'image'.*missing bintools.*: ifwitool")
Simon Glass4f9ee832022-01-09 20:14:09 -07002448
Simon Glasse073d4e2019-07-08 13:18:56 -06002449 def testCbfsOffset(self):
2450 """Test a CBFS with files at particular offsets
2451
2452 Like all CFBS tests, this is just checking the logic that calls
2453 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2454 """
2455 data = self._DoReadFile('114_cbfs_offset.dts')
2456 size = 0x200
2457
2458 cbfs = cbfs_util.CbfsReader(data)
2459 self.assertEqual(size, cbfs.rom_size)
2460
2461 self.assertIn('u-boot', cbfs.files)
2462 cfile = cbfs.files['u-boot']
2463 self.assertEqual(U_BOOT_DATA, cfile.data)
2464 self.assertEqual(0x40, cfile.cbfs_offset)
2465
2466 self.assertIn('u-boot-dtb', cbfs.files)
2467 cfile2 = cbfs.files['u-boot-dtb']
2468 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2469 self.assertEqual(0x140, cfile2.cbfs_offset)
2470
Simon Glass086cec92019-07-08 14:25:27 -06002471 def testFdtmap(self):
2472 """Test an FDT map can be inserted in the image"""
2473 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2474 fdtmap_data = data[len(U_BOOT_DATA):]
2475 magic = fdtmap_data[:8]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002476 self.assertEqual(b'_FDTMAP_', magic)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002477 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass086cec92019-07-08 14:25:27 -06002478
2479 fdt_data = fdtmap_data[16:]
2480 dtb = fdt.Fdt.FromData(fdt_data)
2481 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002482 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass086cec92019-07-08 14:25:27 -06002483 self.assertEqual({
2484 'image-pos': 0,
2485 'offset': 0,
2486 'u-boot:offset': 0,
2487 'u-boot:size': len(U_BOOT_DATA),
2488 'u-boot:image-pos': 0,
2489 'fdtmap:image-pos': 4,
2490 'fdtmap:offset': 4,
2491 'fdtmap:size': len(fdtmap_data),
2492 'size': len(data),
2493 }, props)
2494
2495 def testFdtmapNoMatch(self):
2496 """Check handling of an FDT map when the section cannot be found"""
2497 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2498
2499 # Mangle the section name, which should cause a mismatch between the
2500 # correct FDT path and the one expected by the section
2501 image = control.images['image']
Simon Glasscf228942019-07-08 14:25:28 -06002502 image._node.path += '-suffix'
Simon Glass086cec92019-07-08 14:25:27 -06002503 entries = image.GetEntries()
2504 fdtmap = entries['fdtmap']
2505 with self.assertRaises(ValueError) as e:
2506 fdtmap._GetFdtmap()
2507 self.assertIn("Cannot locate node for path '/binman-suffix'",
2508 str(e.exception))
2509
Simon Glasscf228942019-07-08 14:25:28 -06002510 def testFdtmapHeader(self):
2511 """Test an FDT map and image header can be inserted in the image"""
2512 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2513 fdtmap_pos = len(U_BOOT_DATA)
2514 fdtmap_data = data[fdtmap_pos:]
2515 fdt_data = fdtmap_data[16:]
2516 dtb = fdt.Fdt.FromData(fdt_data)
2517 fdt_size = dtb.GetFdtObj().totalsize()
2518 hdr_data = data[-8:]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002519 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002520 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2521 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2522
2523 def testFdtmapHeaderStart(self):
2524 """Test an image header can be inserted at the image start"""
2525 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2526 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2527 hdr_data = data[:8]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002528 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002529 offset = struct.unpack('<I', hdr_data[4:])[0]
2530 self.assertEqual(fdtmap_pos, offset)
2531
2532 def testFdtmapHeaderPos(self):
2533 """Test an image header can be inserted at a chosen position"""
2534 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2535 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2536 hdr_data = data[0x80:0x88]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002537 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002538 offset = struct.unpack('<I', hdr_data[4:])[0]
2539 self.assertEqual(fdtmap_pos, offset)
2540
2541 def testHeaderMissingFdtmap(self):
2542 """Test an image header requires an fdtmap"""
2543 with self.assertRaises(ValueError) as e:
2544 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2545 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2546 str(e.exception))
2547
2548 def testHeaderNoLocation(self):
2549 """Test an image header with a no specified location is detected"""
2550 with self.assertRaises(ValueError) as e:
2551 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2552 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2553 str(e.exception))
2554
Simon Glassc52c9e72019-07-08 14:25:37 -06002555 def testEntryExpand(self):
Simon Glass80a66ae2022-03-05 20:18:59 -07002556 """Test extending an entry after it is packed"""
2557 data = self._DoReadFile('121_entry_extend.dts')
Simon Glass79d3c582019-07-20 12:23:57 -06002558 self.assertEqual(b'aaa', data[:3])
2559 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2560 self.assertEqual(b'aaa', data[-3:])
Simon Glassc52c9e72019-07-08 14:25:37 -06002561
Simon Glass80a66ae2022-03-05 20:18:59 -07002562 def testEntryExtendBad(self):
2563 """Test extending an entry after it is packed, twice"""
Simon Glassc52c9e72019-07-08 14:25:37 -06002564 with self.assertRaises(ValueError) as e:
Simon Glass80a66ae2022-03-05 20:18:59 -07002565 self._DoReadFile('122_entry_extend_twice.dts')
Simon Glass61ec04f2019-07-20 12:23:58 -06002566 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glassc52c9e72019-07-08 14:25:37 -06002567 str(e.exception))
2568
Simon Glass80a66ae2022-03-05 20:18:59 -07002569 def testEntryExtendSection(self):
2570 """Test extending an entry within a section after it is packed"""
2571 data = self._DoReadFile('123_entry_extend_section.dts')
Simon Glass79d3c582019-07-20 12:23:57 -06002572 self.assertEqual(b'aaa', data[:3])
2573 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2574 self.assertEqual(b'aaa', data[-3:])
Simon Glassc52c9e72019-07-08 14:25:37 -06002575
Simon Glass6c223fd2019-07-08 14:25:38 -06002576 def testCompressDtb(self):
2577 """Test that compress of device-tree files is supported"""
2578 self._CheckLz4()
2579 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2580 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2581 comp_data = data[len(U_BOOT_DATA):]
2582 orig = self._decompress(comp_data)
2583 dtb = fdt.Fdt.FromData(orig)
2584 dtb.Scan()
2585 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2586 expected = {
2587 'u-boot:size': len(U_BOOT_DATA),
2588 'u-boot-dtb:uncomp-size': len(orig),
2589 'u-boot-dtb:size': len(comp_data),
2590 'size': len(data),
2591 }
2592 self.assertEqual(expected, props)
2593
Simon Glass69f7cb32019-07-08 14:25:41 -06002594 def testCbfsUpdateFdt(self):
2595 """Test that we can update the device tree with CBFS offset/size info"""
2596 self._CheckLz4()
2597 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2598 update_dtb=True)
2599 dtb = fdt.Fdt(out_dtb_fname)
2600 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002601 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass69f7cb32019-07-08 14:25:41 -06002602 del props['cbfs/u-boot:size']
2603 self.assertEqual({
2604 'offset': 0,
2605 'size': len(data),
2606 'image-pos': 0,
2607 'cbfs:offset': 0,
2608 'cbfs:size': len(data),
2609 'cbfs:image-pos': 0,
2610 'cbfs/u-boot:offset': 0x38,
2611 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2612 'cbfs/u-boot:image-pos': 0x38,
2613 'cbfs/u-boot-dtb:offset': 0xb8,
2614 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2615 'cbfs/u-boot-dtb:image-pos': 0xb8,
2616 }, props)
2617
Simon Glass8a1ad062019-07-08 14:25:42 -06002618 def testCbfsBadType(self):
2619 """Test an image header with a no specified location is detected"""
2620 with self.assertRaises(ValueError) as e:
2621 self._DoReadFile('126_cbfs_bad_type.dts')
2622 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2623
Simon Glass41b8ba02019-07-08 14:25:43 -06002624 def testList(self):
2625 """Test listing the files in an image"""
2626 self._CheckLz4()
2627 data = self._DoReadFile('127_list.dts')
2628 image = control.images['image']
2629 entries = image.BuildEntryList()
2630 self.assertEqual(7, len(entries))
2631
2632 ent = entries[0]
2633 self.assertEqual(0, ent.indent)
Simon Glass193d3db2023-02-07 14:34:18 -07002634 self.assertEqual('image', ent.name)
Simon Glass41b8ba02019-07-08 14:25:43 -06002635 self.assertEqual('section', ent.etype)
2636 self.assertEqual(len(data), ent.size)
2637 self.assertEqual(0, ent.image_pos)
2638 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002639 self.assertEqual(0, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002640
2641 ent = entries[1]
2642 self.assertEqual(1, ent.indent)
2643 self.assertEqual('u-boot', ent.name)
2644 self.assertEqual('u-boot', ent.etype)
2645 self.assertEqual(len(U_BOOT_DATA), ent.size)
2646 self.assertEqual(0, ent.image_pos)
2647 self.assertEqual(None, ent.uncomp_size)
2648 self.assertEqual(0, ent.offset)
2649
2650 ent = entries[2]
2651 self.assertEqual(1, ent.indent)
2652 self.assertEqual('section', ent.name)
2653 self.assertEqual('section', ent.etype)
2654 section_size = ent.size
2655 self.assertEqual(0x100, ent.image_pos)
2656 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002657 self.assertEqual(0x100, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002658
2659 ent = entries[3]
2660 self.assertEqual(2, ent.indent)
2661 self.assertEqual('cbfs', ent.name)
2662 self.assertEqual('cbfs', ent.etype)
2663 self.assertEqual(0x400, ent.size)
2664 self.assertEqual(0x100, ent.image_pos)
2665 self.assertEqual(None, ent.uncomp_size)
2666 self.assertEqual(0, ent.offset)
2667
2668 ent = entries[4]
2669 self.assertEqual(3, ent.indent)
2670 self.assertEqual('u-boot', ent.name)
2671 self.assertEqual('u-boot', ent.etype)
2672 self.assertEqual(len(U_BOOT_DATA), ent.size)
2673 self.assertEqual(0x138, ent.image_pos)
2674 self.assertEqual(None, ent.uncomp_size)
2675 self.assertEqual(0x38, ent.offset)
2676
2677 ent = entries[5]
2678 self.assertEqual(3, ent.indent)
2679 self.assertEqual('u-boot-dtb', ent.name)
2680 self.assertEqual('text', ent.etype)
2681 self.assertGreater(len(COMPRESS_DATA), ent.size)
2682 self.assertEqual(0x178, ent.image_pos)
2683 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2684 self.assertEqual(0x78, ent.offset)
2685
2686 ent = entries[6]
2687 self.assertEqual(2, ent.indent)
2688 self.assertEqual('u-boot-dtb', ent.name)
2689 self.assertEqual('u-boot-dtb', ent.etype)
2690 self.assertEqual(0x500, ent.image_pos)
2691 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2692 dtb_size = ent.size
2693 # Compressing this data expands it since headers are added
2694 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2695 self.assertEqual(0x400, ent.offset)
2696
2697 self.assertEqual(len(data), 0x100 + section_size)
2698 self.assertEqual(section_size, 0x400 + dtb_size)
2699
Simon Glasse1925fa2019-07-08 14:25:44 -06002700 def testFindFdtmap(self):
2701 """Test locating an FDT map in an image"""
2702 self._CheckLz4()
2703 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2704 image = control.images['image']
2705 entries = image.GetEntries()
2706 entry = entries['fdtmap']
2707 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2708
2709 def testFindFdtmapMissing(self):
2710 """Test failing to locate an FDP map"""
2711 data = self._DoReadFile('005_simple.dts')
2712 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2713
Simon Glass2d260032019-07-08 14:25:45 -06002714 def testFindImageHeader(self):
2715 """Test locating a image header"""
2716 self._CheckLz4()
Simon Glassffded752019-07-08 14:25:46 -06002717 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002718 image = control.images['image']
2719 entries = image.GetEntries()
2720 entry = entries['fdtmap']
2721 # The header should point to the FDT map
2722 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2723
2724 def testFindImageHeaderStart(self):
2725 """Test locating a image header located at the start of an image"""
Simon Glassffded752019-07-08 14:25:46 -06002726 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002727 image = control.images['image']
2728 entries = image.GetEntries()
2729 entry = entries['fdtmap']
2730 # The header should point to the FDT map
2731 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2732
2733 def testFindImageHeaderMissing(self):
2734 """Test failing to locate an image header"""
2735 data = self._DoReadFile('005_simple.dts')
2736 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2737
Simon Glassffded752019-07-08 14:25:46 -06002738 def testReadImage(self):
2739 """Test reading an image and accessing its FDT map"""
2740 self._CheckLz4()
2741 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002742 image_fname = tools.get_output_filename('image.bin')
Simon Glassffded752019-07-08 14:25:46 -06002743 orig_image = control.images['image']
2744 image = Image.FromFile(image_fname)
2745 self.assertEqual(orig_image.GetEntries().keys(),
2746 image.GetEntries().keys())
2747
2748 orig_entry = orig_image.GetEntries()['fdtmap']
2749 entry = image.GetEntries()['fdtmap']
2750 self.assertEquals(orig_entry.offset, entry.offset)
2751 self.assertEquals(orig_entry.size, entry.size)
2752 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2753
2754 def testReadImageNoHeader(self):
2755 """Test accessing an image's FDT map without an image header"""
2756 self._CheckLz4()
2757 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002758 image_fname = tools.get_output_filename('image.bin')
Simon Glassffded752019-07-08 14:25:46 -06002759 image = Image.FromFile(image_fname)
2760 self.assertTrue(isinstance(image, Image))
Simon Glass10f9d002019-07-20 12:23:50 -06002761 self.assertEqual('image', image.image_name[-5:])
Simon Glassffded752019-07-08 14:25:46 -06002762
2763 def testReadImageFail(self):
2764 """Test failing to read an image image's FDT map"""
2765 self._DoReadFile('005_simple.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002766 image_fname = tools.get_output_filename('image.bin')
Simon Glassffded752019-07-08 14:25:46 -06002767 with self.assertRaises(ValueError) as e:
2768 image = Image.FromFile(image_fname)
2769 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glasse073d4e2019-07-08 13:18:56 -06002770
Simon Glass61f564d2019-07-08 14:25:48 -06002771 def testListCmd(self):
2772 """Test listing the files in an image using an Fdtmap"""
2773 self._CheckLz4()
2774 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2775
2776 # lz4 compression size differs depending on the version
2777 image = control.images['image']
2778 entries = image.GetEntries()
2779 section_size = entries['section'].size
2780 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2781 fdtmap_offset = entries['fdtmap'].offset
2782
Simon Glassf86a7362019-07-20 12:24:10 -06002783 try:
2784 tmpdir, updated_fname = self._SetupImageInTmpdir()
2785 with test_util.capture_sys_output() as (stdout, stderr):
2786 self._DoBinman('ls', '-i', updated_fname)
2787 finally:
2788 shutil.rmtree(tmpdir)
Simon Glass61f564d2019-07-08 14:25:48 -06002789 lines = stdout.getvalue().splitlines()
2790 expected = [
2791'Name Image-pos Size Entry-type Offset Uncomp-size',
2792'----------------------------------------------------------------------',
Simon Glass193d3db2023-02-07 14:34:18 -07002793'image 0 c00 section 0',
Simon Glass61f564d2019-07-08 14:25:48 -06002794' u-boot 0 4 u-boot 0',
2795' section 100 %x section 100' % section_size,
2796' cbfs 100 400 cbfs 0',
2797' u-boot 138 4 u-boot 38',
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002798' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glass61f564d2019-07-08 14:25:48 -06002799' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002800' fdtmap %x 3bd fdtmap %x' %
Simon Glass61f564d2019-07-08 14:25:48 -06002801 (fdtmap_offset, fdtmap_offset),
2802' image-header bf8 8 image-header bf8',
2803 ]
2804 self.assertEqual(expected, lines)
2805
2806 def testListCmdFail(self):
2807 """Test failing to list an image"""
2808 self._DoReadFile('005_simple.dts')
Simon Glassf86a7362019-07-20 12:24:10 -06002809 try:
2810 tmpdir, updated_fname = self._SetupImageInTmpdir()
2811 with self.assertRaises(ValueError) as e:
2812 self._DoBinman('ls', '-i', updated_fname)
2813 finally:
2814 shutil.rmtree(tmpdir)
Simon Glass61f564d2019-07-08 14:25:48 -06002815 self.assertIn("Cannot find FDT map in image", str(e.exception))
2816
2817 def _RunListCmd(self, paths, expected):
2818 """List out entries and check the result
2819
2820 Args:
2821 paths: List of paths to pass to the list command
2822 expected: Expected list of filenames to be returned, in order
2823 """
2824 self._CheckLz4()
2825 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002826 image_fname = tools.get_output_filename('image.bin')
Simon Glass61f564d2019-07-08 14:25:48 -06002827 image = Image.FromFile(image_fname)
2828 lines = image.GetListEntries(paths)[1]
2829 files = [line[0].strip() for line in lines[1:]]
2830 self.assertEqual(expected, files)
2831
2832 def testListCmdSection(self):
2833 """Test listing the files in a section"""
2834 self._RunListCmd(['section'],
2835 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2836
2837 def testListCmdFile(self):
2838 """Test listing a particular file"""
2839 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2840
2841 def testListCmdWildcard(self):
2842 """Test listing a wildcarded file"""
2843 self._RunListCmd(['*boot*'],
2844 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2845
2846 def testListCmdWildcardMulti(self):
2847 """Test listing a wildcarded file"""
2848 self._RunListCmd(['*cb*', '*head*'],
2849 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2850
2851 def testListCmdEmpty(self):
2852 """Test listing a wildcarded file"""
2853 self._RunListCmd(['nothing'], [])
2854
2855 def testListCmdPath(self):
2856 """Test listing the files in a sub-entry of a section"""
2857 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2858
Simon Glassf667e452019-07-08 14:25:50 -06002859 def _RunExtractCmd(self, entry_name, decomp=True):
2860 """Extract an entry from an image
2861
2862 Args:
2863 entry_name: Entry name to extract
2864 decomp: True to decompress the data if compressed, False to leave
2865 it in its raw uncompressed format
2866
2867 Returns:
2868 data from entry
2869 """
2870 self._CheckLz4()
2871 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002872 image_fname = tools.get_output_filename('image.bin')
Simon Glassf667e452019-07-08 14:25:50 -06002873 return control.ReadEntry(image_fname, entry_name, decomp)
2874
2875 def testExtractSimple(self):
2876 """Test extracting a single file"""
2877 data = self._RunExtractCmd('u-boot')
2878 self.assertEqual(U_BOOT_DATA, data)
2879
Simon Glass71ce0ba2019-07-08 14:25:52 -06002880 def testExtractSection(self):
2881 """Test extracting the files in a section"""
2882 data = self._RunExtractCmd('section')
2883 cbfs_data = data[:0x400]
2884 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002885 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass71ce0ba2019-07-08 14:25:52 -06002886 dtb_data = data[0x400:]
2887 dtb = self._decompress(dtb_data)
2888 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2889
2890 def testExtractCompressed(self):
2891 """Test extracting compressed data"""
2892 data = self._RunExtractCmd('section/u-boot-dtb')
2893 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2894
2895 def testExtractRaw(self):
2896 """Test extracting compressed data without decompressing it"""
2897 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2898 dtb = self._decompress(data)
2899 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2900
2901 def testExtractCbfs(self):
2902 """Test extracting CBFS data"""
2903 data = self._RunExtractCmd('section/cbfs/u-boot')
2904 self.assertEqual(U_BOOT_DATA, data)
2905
2906 def testExtractCbfsCompressed(self):
2907 """Test extracting CBFS compressed data"""
2908 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2909 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2910
2911 def testExtractCbfsRaw(self):
2912 """Test extracting CBFS compressed data without decompressing it"""
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +02002913 bintool = self.comp_bintools['lzma_alone']
2914 self._CheckBintool(bintool)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002915 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +02002916 dtb = bintool.decompress(data)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002917 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2918
Simon Glassf667e452019-07-08 14:25:50 -06002919 def testExtractBadEntry(self):
2920 """Test extracting a bad section path"""
2921 with self.assertRaises(ValueError) as e:
2922 self._RunExtractCmd('section/does-not-exist')
2923 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2924 str(e.exception))
2925
2926 def testExtractMissingFile(self):
2927 """Test extracting file that does not exist"""
2928 with self.assertRaises(IOError) as e:
2929 control.ReadEntry('missing-file', 'name')
2930
2931 def testExtractBadFile(self):
2932 """Test extracting an invalid file"""
2933 fname = os.path.join(self._indir, 'badfile')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002934 tools.write_file(fname, b'')
Simon Glassf667e452019-07-08 14:25:50 -06002935 with self.assertRaises(ValueError) as e:
2936 control.ReadEntry(fname, 'name')
2937
Simon Glass71ce0ba2019-07-08 14:25:52 -06002938 def testExtractCmd(self):
2939 """Test extracting a file fron an image on the command line"""
2940 self._CheckLz4()
2941 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass71ce0ba2019-07-08 14:25:52 -06002942 fname = os.path.join(self._indir, 'output.extact')
Simon Glassf86a7362019-07-20 12:24:10 -06002943 try:
2944 tmpdir, updated_fname = self._SetupImageInTmpdir()
2945 with test_util.capture_sys_output() as (stdout, stderr):
2946 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2947 '-f', fname)
2948 finally:
2949 shutil.rmtree(tmpdir)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002950 data = tools.read_file(fname)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002951 self.assertEqual(U_BOOT_DATA, data)
2952
2953 def testExtractOneEntry(self):
2954 """Test extracting a single entry fron an image """
2955 self._CheckLz4()
2956 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002957 image_fname = tools.get_output_filename('image.bin')
Simon Glass71ce0ba2019-07-08 14:25:52 -06002958 fname = os.path.join(self._indir, 'output.extact')
2959 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
Simon Glassc1aa66e2022-01-29 14:14:04 -07002960 data = tools.read_file(fname)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002961 self.assertEqual(U_BOOT_DATA, data)
2962
2963 def _CheckExtractOutput(self, decomp):
2964 """Helper to test file output with and without decompression
2965
2966 Args:
2967 decomp: True to decompress entry data, False to output it raw
2968 """
2969 def _CheckPresent(entry_path, expect_data, expect_size=None):
2970 """Check and remove expected file
2971
2972 This checks the data/size of a file and removes the file both from
2973 the outfiles set and from the output directory. Once all files are
2974 processed, both the set and directory should be empty.
2975
2976 Args:
2977 entry_path: Entry path
2978 expect_data: Data to expect in file, or None to skip check
2979 expect_size: Size of data to expect in file, or None to skip
2980 """
2981 path = os.path.join(outdir, entry_path)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002982 data = tools.read_file(path)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002983 os.remove(path)
2984 if expect_data:
2985 self.assertEqual(expect_data, data)
2986 elif expect_size:
2987 self.assertEqual(expect_size, len(data))
2988 outfiles.remove(path)
2989
2990 def _CheckDirPresent(name):
2991 """Remove expected directory
2992
2993 This gives an error if the directory does not exist as expected
2994
2995 Args:
2996 name: Name of directory to remove
2997 """
2998 path = os.path.join(outdir, name)
2999 os.rmdir(path)
3000
3001 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003002 image_fname = tools.get_output_filename('image.bin')
Simon Glass71ce0ba2019-07-08 14:25:52 -06003003 outdir = os.path.join(self._indir, 'extract')
3004 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
3005
3006 # Create a set of all file that were output (should be 9)
3007 outfiles = set()
3008 for root, dirs, files in os.walk(outdir):
3009 outfiles |= set([os.path.join(root, fname) for fname in files])
3010 self.assertEqual(9, len(outfiles))
3011 self.assertEqual(9, len(einfos))
3012
3013 image = control.images['image']
3014 entries = image.GetEntries()
3015
3016 # Check the 9 files in various ways
3017 section = entries['section']
3018 section_entries = section.GetEntries()
3019 cbfs_entries = section_entries['cbfs'].GetEntries()
3020 _CheckPresent('u-boot', U_BOOT_DATA)
3021 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
3022 dtb_len = EXTRACT_DTB_SIZE
3023 if not decomp:
3024 dtb_len = cbfs_entries['u-boot-dtb'].size
3025 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
3026 if not decomp:
3027 dtb_len = section_entries['u-boot-dtb'].size
3028 _CheckPresent('section/u-boot-dtb', None, dtb_len)
3029
3030 fdtmap = entries['fdtmap']
3031 _CheckPresent('fdtmap', fdtmap.data)
3032 hdr = entries['image-header']
3033 _CheckPresent('image-header', hdr.data)
3034
3035 _CheckPresent('section/root', section.data)
3036 cbfs = section_entries['cbfs']
3037 _CheckPresent('section/cbfs/root', cbfs.data)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003038 data = tools.read_file(image_fname)
Simon Glass71ce0ba2019-07-08 14:25:52 -06003039 _CheckPresent('root', data)
3040
3041 # There should be no files left. Remove all the directories to check.
3042 # If there are any files/dirs remaining, one of these checks will fail.
3043 self.assertEqual(0, len(outfiles))
3044 _CheckDirPresent('section/cbfs')
3045 _CheckDirPresent('section')
3046 _CheckDirPresent('')
3047 self.assertFalse(os.path.exists(outdir))
3048
3049 def testExtractAllEntries(self):
3050 """Test extracting all entries"""
3051 self._CheckLz4()
3052 self._CheckExtractOutput(decomp=True)
3053
3054 def testExtractAllEntriesRaw(self):
3055 """Test extracting all entries without decompressing them"""
3056 self._CheckLz4()
3057 self._CheckExtractOutput(decomp=False)
3058
3059 def testExtractSelectedEntries(self):
3060 """Test extracting some entries"""
3061 self._CheckLz4()
3062 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003063 image_fname = tools.get_output_filename('image.bin')
Simon Glass71ce0ba2019-07-08 14:25:52 -06003064 outdir = os.path.join(self._indir, 'extract')
3065 einfos = control.ExtractEntries(image_fname, None, outdir,
3066 ['*cb*', '*head*'])
3067
3068 # File output is tested by testExtractAllEntries(), so just check that
3069 # the expected entries are selected
3070 names = [einfo.name for einfo in einfos]
3071 self.assertEqual(names,
3072 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
3073
3074 def testExtractNoEntryPaths(self):
3075 """Test extracting some entries"""
3076 self._CheckLz4()
3077 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003078 image_fname = tools.get_output_filename('image.bin')
Simon Glass71ce0ba2019-07-08 14:25:52 -06003079 with self.assertRaises(ValueError) as e:
3080 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassbb5edc12019-07-20 12:24:14 -06003081 self.assertIn('Must specify an entry path to write with -f',
Simon Glass71ce0ba2019-07-08 14:25:52 -06003082 str(e.exception))
3083
3084 def testExtractTooManyEntryPaths(self):
3085 """Test extracting some entries"""
3086 self._CheckLz4()
3087 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003088 image_fname = tools.get_output_filename('image.bin')
Simon Glass71ce0ba2019-07-08 14:25:52 -06003089 with self.assertRaises(ValueError) as e:
3090 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassbb5edc12019-07-20 12:24:14 -06003091 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass71ce0ba2019-07-08 14:25:52 -06003092 str(e.exception))
3093
Simon Glasse2705fa2019-07-08 14:25:53 -06003094 def testPackAlignSection(self):
3095 """Test that sections can have alignment"""
3096 self._DoReadFile('131_pack_align_section.dts')
3097
3098 self.assertIn('image', control.images)
3099 image = control.images['image']
3100 entries = image.GetEntries()
3101 self.assertEqual(3, len(entries))
3102
3103 # First u-boot
3104 self.assertIn('u-boot', entries)
3105 entry = entries['u-boot']
3106 self.assertEqual(0, entry.offset)
3107 self.assertEqual(0, entry.image_pos)
3108 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3109 self.assertEqual(len(U_BOOT_DATA), entry.size)
3110
3111 # Section0
3112 self.assertIn('section0', entries)
3113 section0 = entries['section0']
3114 self.assertEqual(0x10, section0.offset)
3115 self.assertEqual(0x10, section0.image_pos)
3116 self.assertEqual(len(U_BOOT_DATA), section0.size)
3117
3118 # Second u-boot
3119 section_entries = section0.GetEntries()
3120 self.assertIn('u-boot', section_entries)
3121 entry = section_entries['u-boot']
3122 self.assertEqual(0, entry.offset)
3123 self.assertEqual(0x10, entry.image_pos)
3124 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3125 self.assertEqual(len(U_BOOT_DATA), entry.size)
3126
3127 # Section1
3128 self.assertIn('section1', entries)
3129 section1 = entries['section1']
3130 self.assertEqual(0x14, section1.offset)
3131 self.assertEqual(0x14, section1.image_pos)
3132 self.assertEqual(0x20, section1.size)
3133
3134 # Second u-boot
3135 section_entries = section1.GetEntries()
3136 self.assertIn('u-boot', section_entries)
3137 entry = section_entries['u-boot']
3138 self.assertEqual(0, entry.offset)
3139 self.assertEqual(0x14, entry.image_pos)
3140 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3141 self.assertEqual(len(U_BOOT_DATA), entry.size)
3142
3143 # Section2
3144 self.assertIn('section2', section_entries)
3145 section2 = section_entries['section2']
3146 self.assertEqual(0x4, section2.offset)
3147 self.assertEqual(0x18, section2.image_pos)
3148 self.assertEqual(4, section2.size)
3149
3150 # Third u-boot
3151 section_entries = section2.GetEntries()
3152 self.assertIn('u-boot', section_entries)
3153 entry = section_entries['u-boot']
3154 self.assertEqual(0, entry.offset)
3155 self.assertEqual(0x18, entry.image_pos)
3156 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3157 self.assertEqual(len(U_BOOT_DATA), entry.size)
3158
Simon Glass51014aa2019-07-20 12:23:56 -06003159 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3160 dts='132_replace.dts'):
Simon Glass10f9d002019-07-20 12:23:50 -06003161 """Replace an entry in an image
3162
3163 This writes the entry data to update it, then opens the updated file and
3164 returns the value that it now finds there.
3165
3166 Args:
3167 entry_name: Entry name to replace
3168 data: Data to replace it with
3169 decomp: True to compress the data if needed, False if data is
3170 already compressed so should be used as is
Simon Glass51014aa2019-07-20 12:23:56 -06003171 allow_resize: True to allow entries to change size, False to raise
3172 an exception
Simon Glass10f9d002019-07-20 12:23:50 -06003173
3174 Returns:
3175 Tuple:
3176 data from entry
3177 data from fdtmap (excluding header)
Simon Glass51014aa2019-07-20 12:23:56 -06003178 Image object that was modified
Simon Glass10f9d002019-07-20 12:23:50 -06003179 """
Simon Glass51014aa2019-07-20 12:23:56 -06003180 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass10f9d002019-07-20 12:23:50 -06003181 update_dtb=True)[1]
3182
3183 self.assertIn('image', control.images)
3184 image = control.images['image']
3185 entries = image.GetEntries()
3186 orig_dtb_data = entries['u-boot-dtb'].data
3187 orig_fdtmap_data = entries['fdtmap'].data
3188
Simon Glassc1aa66e2022-01-29 14:14:04 -07003189 image_fname = tools.get_output_filename('image.bin')
3190 updated_fname = tools.get_output_filename('image-updated.bin')
3191 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glass51014aa2019-07-20 12:23:56 -06003192 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3193 allow_resize)
Simon Glass10f9d002019-07-20 12:23:50 -06003194 data = control.ReadEntry(updated_fname, entry_name, decomp)
3195
Simon Glass51014aa2019-07-20 12:23:56 -06003196 # The DT data should not change unless resized:
3197 if not allow_resize:
3198 new_dtb_data = entries['u-boot-dtb'].data
3199 self.assertEqual(new_dtb_data, orig_dtb_data)
3200 new_fdtmap_data = entries['fdtmap'].data
3201 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass10f9d002019-07-20 12:23:50 -06003202
Simon Glass51014aa2019-07-20 12:23:56 -06003203 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass10f9d002019-07-20 12:23:50 -06003204
3205 def testReplaceSimple(self):
3206 """Test replacing a single file"""
3207 expected = b'x' * len(U_BOOT_DATA)
Simon Glass51014aa2019-07-20 12:23:56 -06003208 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3209 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06003210 self.assertEqual(expected, data)
3211
3212 # Test that the state looks right. There should be an FDT for the fdtmap
3213 # that we jsut read back in, and it should match what we find in the
3214 # 'control' tables. Checking for an FDT that does not exist should
3215 # return None.
3216 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glass51014aa2019-07-20 12:23:56 -06003217 self.assertIsNotNone(path)
Simon Glass10f9d002019-07-20 12:23:50 -06003218 self.assertEqual(expected_fdtmap, fdtmap)
3219
3220 dtb = state.GetFdtForEtype('fdtmap')
3221 self.assertEqual(dtb.GetContents(), fdtmap)
3222
3223 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3224 self.assertIsNone(missing_path)
3225 self.assertIsNone(missing_fdtmap)
3226
3227 missing_dtb = state.GetFdtForEtype('missing')
3228 self.assertIsNone(missing_dtb)
3229
3230 self.assertEqual('/binman', state.fdt_path_prefix)
3231
3232 def testReplaceResizeFail(self):
3233 """Test replacing a file by something larger"""
3234 expected = U_BOOT_DATA + b'x'
3235 with self.assertRaises(ValueError) as e:
Simon Glass51014aa2019-07-20 12:23:56 -06003236 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3237 dts='139_replace_repack.dts')
Simon Glass10f9d002019-07-20 12:23:50 -06003238 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3239 str(e.exception))
3240
3241 def testReplaceMulti(self):
3242 """Test replacing entry data where multiple images are generated"""
3243 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3244 update_dtb=True)[0]
3245 expected = b'x' * len(U_BOOT_DATA)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003246 updated_fname = tools.get_output_filename('image-updated.bin')
3247 tools.write_file(updated_fname, data)
Simon Glass10f9d002019-07-20 12:23:50 -06003248 entry_name = 'u-boot'
Simon Glass51014aa2019-07-20 12:23:56 -06003249 control.WriteEntry(updated_fname, entry_name, expected,
3250 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06003251 data = control.ReadEntry(updated_fname, entry_name)
3252 self.assertEqual(expected, data)
3253
3254 # Check the state looks right.
3255 self.assertEqual('/binman/image', state.fdt_path_prefix)
3256
3257 # Now check we can write the first image
Simon Glassc1aa66e2022-01-29 14:14:04 -07003258 image_fname = tools.get_output_filename('first-image.bin')
3259 updated_fname = tools.get_output_filename('first-updated.bin')
3260 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glass10f9d002019-07-20 12:23:50 -06003261 entry_name = 'u-boot'
Simon Glass51014aa2019-07-20 12:23:56 -06003262 control.WriteEntry(updated_fname, entry_name, expected,
3263 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06003264 data = control.ReadEntry(updated_fname, entry_name)
3265 self.assertEqual(expected, data)
3266
3267 # Check the state looks right.
3268 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass8beb11e2019-07-08 14:25:47 -06003269
Simon Glass12bb1a92019-07-20 12:23:51 -06003270 def testUpdateFdtAllRepack(self):
3271 """Test that all device trees are updated with offset/size info"""
3272 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3273 SECTION_SIZE = 0x300
3274 DTB_SIZE = 602
3275 FDTMAP_SIZE = 608
3276 base_expected = {
3277 'offset': 0,
3278 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3279 'image-pos': 0,
3280 'section:offset': 0,
3281 'section:size': SECTION_SIZE,
3282 'section:image-pos': 0,
3283 'section/u-boot-dtb:offset': 4,
3284 'section/u-boot-dtb:size': 636,
3285 'section/u-boot-dtb:image-pos': 4,
3286 'u-boot-spl-dtb:offset': SECTION_SIZE,
3287 'u-boot-spl-dtb:size': DTB_SIZE,
3288 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3289 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3290 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3291 'u-boot-tpl-dtb:size': DTB_SIZE,
3292 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3293 'fdtmap:size': FDTMAP_SIZE,
3294 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3295 }
3296 main_expected = {
3297 'section:orig-size': SECTION_SIZE,
3298 'section/u-boot-dtb:orig-offset': 4,
3299 }
3300
3301 # We expect three device-tree files in the output, with the first one
3302 # within a fixed-size section.
3303 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3304 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3305 # main U-Boot tree. All three should have the same positions and offset
3306 # except that the main tree should include the main_expected properties
3307 start = 4
3308 for item in ['', 'spl', 'tpl', None]:
3309 if item is None:
3310 start += 16 # Move past fdtmap header
3311 dtb = fdt.Fdt.FromData(data[start:])
3312 dtb.Scan()
3313 props = self._GetPropTree(dtb,
3314 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3315 prefix='/' if item is None else '/binman/')
3316 expected = dict(base_expected)
3317 if item:
3318 expected[item] = 0
3319 else:
3320 # Main DTB and fdtdec should include the 'orig-' properties
3321 expected.update(main_expected)
3322 # Helpful for debugging:
3323 #for prop in sorted(props):
3324 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3325 self.assertEqual(expected, props)
3326 if item == '':
3327 start = SECTION_SIZE
3328 else:
3329 start += dtb._fdt_obj.totalsize()
3330
Simon Glasseba1f0c2019-07-20 12:23:55 -06003331 def testFdtmapHeaderMiddle(self):
3332 """Test an FDT map in the middle of an image when it should be at end"""
3333 with self.assertRaises(ValueError) as e:
3334 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3335 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3336 str(e.exception))
3337
3338 def testFdtmapHeaderStartBad(self):
3339 """Test an FDT map in middle of an image when it should be at start"""
3340 with self.assertRaises(ValueError) as e:
3341 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3342 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3343 str(e.exception))
3344
3345 def testFdtmapHeaderEndBad(self):
3346 """Test an FDT map at the start of an image when it should be at end"""
3347 with self.assertRaises(ValueError) as e:
3348 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3349 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3350 str(e.exception))
3351
3352 def testFdtmapHeaderNoSize(self):
3353 """Test an image header at the end of an image with undefined size"""
3354 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3355
Simon Glass51014aa2019-07-20 12:23:56 -06003356 def testReplaceResize(self):
3357 """Test replacing a single file in an entry with a larger file"""
3358 expected = U_BOOT_DATA + b'x'
3359 data, _, image = self._RunReplaceCmd('u-boot', expected,
3360 dts='139_replace_repack.dts')
3361 self.assertEqual(expected, data)
3362
3363 entries = image.GetEntries()
3364 dtb_data = entries['u-boot-dtb'].data
3365 dtb = fdt.Fdt.FromData(dtb_data)
3366 dtb.Scan()
3367
3368 # The u-boot section should now be larger in the dtb
3369 node = dtb.GetNode('/binman/u-boot')
3370 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3371
3372 # Same for the fdtmap
3373 fdata = entries['fdtmap'].data
3374 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3375 fdtb.Scan()
3376 fnode = fdtb.GetNode('/u-boot')
3377 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3378
3379 def testReplaceResizeNoRepack(self):
3380 """Test replacing an entry with a larger file when not allowed"""
3381 expected = U_BOOT_DATA + b'x'
3382 with self.assertRaises(ValueError) as e:
3383 self._RunReplaceCmd('u-boot', expected)
3384 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3385 str(e.exception))
3386
Simon Glass61ec04f2019-07-20 12:23:58 -06003387 def testEntryShrink(self):
3388 """Test contracting an entry after it is packed"""
3389 try:
3390 state.SetAllowEntryContraction(True)
3391 data = self._DoReadFileDtb('140_entry_shrink.dts',
3392 update_dtb=True)[0]
3393 finally:
3394 state.SetAllowEntryContraction(False)
3395 self.assertEqual(b'a', data[:1])
3396 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3397 self.assertEqual(b'a', data[-1:])
3398
3399 def testEntryShrinkFail(self):
3400 """Test not being allowed to contract an entry after it is packed"""
3401 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3402
3403 # In this case there is a spare byte at the end of the data. The size of
3404 # the contents is only 1 byte but we still have the size before it
3405 # shrunk.
3406 self.assertEqual(b'a\0', data[:2])
3407 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3408 self.assertEqual(b'a\0', data[-2:])
3409
Simon Glass27145fd2019-07-20 12:24:01 -06003410 def testDescriptorOffset(self):
3411 """Test that the Intel descriptor is always placed at at the start"""
3412 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3413 image = control.images['image']
3414 entries = image.GetEntries()
3415 desc = entries['intel-descriptor']
3416 self.assertEqual(0xff800000, desc.offset);
3417 self.assertEqual(0xff800000, desc.image_pos);
3418
Simon Glasseb0f4a42019-07-20 12:24:06 -06003419 def testReplaceCbfs(self):
3420 """Test replacing a single file in CBFS without changing the size"""
3421 self._CheckLz4()
3422 expected = b'x' * len(U_BOOT_DATA)
3423 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003424 updated_fname = tools.get_output_filename('image-updated.bin')
3425 tools.write_file(updated_fname, data)
Simon Glasseb0f4a42019-07-20 12:24:06 -06003426 entry_name = 'section/cbfs/u-boot'
3427 control.WriteEntry(updated_fname, entry_name, expected,
3428 allow_resize=True)
3429 data = control.ReadEntry(updated_fname, entry_name)
3430 self.assertEqual(expected, data)
3431
3432 def testReplaceResizeCbfs(self):
3433 """Test replacing a single file in CBFS with one of a different size"""
3434 self._CheckLz4()
3435 expected = U_BOOT_DATA + b'x'
3436 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003437 updated_fname = tools.get_output_filename('image-updated.bin')
3438 tools.write_file(updated_fname, data)
Simon Glasseb0f4a42019-07-20 12:24:06 -06003439 entry_name = 'section/cbfs/u-boot'
3440 control.WriteEntry(updated_fname, entry_name, expected,
3441 allow_resize=True)
3442 data = control.ReadEntry(updated_fname, entry_name)
3443 self.assertEqual(expected, data)
3444
Simon Glassa6cb9952019-07-20 12:24:15 -06003445 def _SetupForReplace(self):
3446 """Set up some files to use to replace entries
3447
3448 This generates an image, copies it to a new file, extracts all the files
3449 in it and updates some of them
3450
3451 Returns:
3452 List
3453 Image filename
3454 Output directory
3455 Expected values for updated entries, each a string
3456 """
3457 data = self._DoReadFileRealDtb('143_replace_all.dts')
3458
Simon Glassc1aa66e2022-01-29 14:14:04 -07003459 updated_fname = tools.get_output_filename('image-updated.bin')
3460 tools.write_file(updated_fname, data)
Simon Glassa6cb9952019-07-20 12:24:15 -06003461
3462 outdir = os.path.join(self._indir, 'extract')
3463 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3464
3465 expected1 = b'x' + U_BOOT_DATA + b'y'
3466 u_boot_fname1 = os.path.join(outdir, 'u-boot')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003467 tools.write_file(u_boot_fname1, expected1)
Simon Glassa6cb9952019-07-20 12:24:15 -06003468
3469 expected2 = b'a' + U_BOOT_DATA + b'b'
3470 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003471 tools.write_file(u_boot_fname2, expected2)
Simon Glassa6cb9952019-07-20 12:24:15 -06003472
3473 expected_text = b'not the same text'
3474 text_fname = os.path.join(outdir, 'text')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003475 tools.write_file(text_fname, expected_text)
Simon Glassa6cb9952019-07-20 12:24:15 -06003476
3477 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3478 dtb = fdt.FdtScan(dtb_fname)
3479 node = dtb.GetNode('/binman/text')
3480 node.AddString('my-property', 'the value')
3481 dtb.Sync(auto_resize=True)
3482 dtb.Flush()
3483
3484 return updated_fname, outdir, expected1, expected2, expected_text
3485
3486 def _CheckReplaceMultiple(self, entry_paths):
3487 """Handle replacing the contents of multiple entries
3488
3489 Args:
3490 entry_paths: List of entry paths to replace
3491
3492 Returns:
3493 List
3494 Dict of entries in the image:
3495 key: Entry name
3496 Value: Entry object
3497 Expected values for updated entries, each a string
3498 """
3499 updated_fname, outdir, expected1, expected2, expected_text = (
3500 self._SetupForReplace())
3501 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3502
3503 image = Image.FromFile(updated_fname)
3504 image.LoadData()
3505 return image.GetEntries(), expected1, expected2, expected_text
3506
3507 def testReplaceAll(self):
3508 """Test replacing the contents of all entries"""
3509 entries, expected1, expected2, expected_text = (
3510 self._CheckReplaceMultiple([]))
3511 data = entries['u-boot'].data
3512 self.assertEqual(expected1, data)
3513
3514 data = entries['u-boot2'].data
3515 self.assertEqual(expected2, data)
3516
3517 data = entries['text'].data
3518 self.assertEqual(expected_text, data)
3519
3520 # Check that the device tree is updated
3521 data = entries['u-boot-dtb'].data
3522 dtb = fdt.Fdt.FromData(data)
3523 dtb.Scan()
3524 node = dtb.GetNode('/binman/text')
3525 self.assertEqual('the value', node.props['my-property'].value)
3526
3527 def testReplaceSome(self):
3528 """Test replacing the contents of a few entries"""
3529 entries, expected1, expected2, expected_text = (
3530 self._CheckReplaceMultiple(['u-boot2', 'text']))
3531
3532 # This one should not change
3533 data = entries['u-boot'].data
3534 self.assertEqual(U_BOOT_DATA, data)
3535
3536 data = entries['u-boot2'].data
3537 self.assertEqual(expected2, data)
3538
3539 data = entries['text'].data
3540 self.assertEqual(expected_text, data)
3541
3542 def testReplaceCmd(self):
3543 """Test replacing a file fron an image on the command line"""
3544 self._DoReadFileRealDtb('143_replace_all.dts')
3545
3546 try:
3547 tmpdir, updated_fname = self._SetupImageInTmpdir()
3548
3549 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3550 expected = b'x' * len(U_BOOT_DATA)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003551 tools.write_file(fname, expected)
Simon Glassa6cb9952019-07-20 12:24:15 -06003552
3553 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003554 data = tools.read_file(updated_fname)
Simon Glassa6cb9952019-07-20 12:24:15 -06003555 self.assertEqual(expected, data[:len(expected)])
3556 map_fname = os.path.join(tmpdir, 'image-updated.map')
3557 self.assertFalse(os.path.exists(map_fname))
3558 finally:
3559 shutil.rmtree(tmpdir)
3560
3561 def testReplaceCmdSome(self):
3562 """Test replacing some files fron an image on the command line"""
3563 updated_fname, outdir, expected1, expected2, expected_text = (
3564 self._SetupForReplace())
3565
3566 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3567 'u-boot2', 'text')
3568
Simon Glassc1aa66e2022-01-29 14:14:04 -07003569 tools.prepare_output_dir(None)
Simon Glassa6cb9952019-07-20 12:24:15 -06003570 image = Image.FromFile(updated_fname)
3571 image.LoadData()
3572 entries = image.GetEntries()
3573
3574 # This one should not change
3575 data = entries['u-boot'].data
3576 self.assertEqual(U_BOOT_DATA, data)
3577
3578 data = entries['u-boot2'].data
3579 self.assertEqual(expected2, data)
3580
3581 data = entries['text'].data
3582 self.assertEqual(expected_text, data)
3583
3584 def testReplaceMissing(self):
3585 """Test replacing entries where the file is missing"""
3586 updated_fname, outdir, expected1, expected2, expected_text = (
3587 self._SetupForReplace())
3588
3589 # Remove one of the files, to generate a warning
3590 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3591 os.remove(u_boot_fname1)
3592
3593 with test_util.capture_sys_output() as (stdout, stderr):
3594 control.ReplaceEntries(updated_fname, None, outdir, [])
3595 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass38fdb4c2020-07-09 18:39:39 -06003596 stderr.getvalue())
Simon Glassa6cb9952019-07-20 12:24:15 -06003597
3598 def testReplaceCmdMap(self):
3599 """Test replacing a file fron an image on the command line"""
3600 self._DoReadFileRealDtb('143_replace_all.dts')
3601
3602 try:
3603 tmpdir, updated_fname = self._SetupImageInTmpdir()
3604
3605 fname = os.path.join(self._indir, 'update-u-boot.bin')
3606 expected = b'x' * len(U_BOOT_DATA)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003607 tools.write_file(fname, expected)
Simon Glassa6cb9952019-07-20 12:24:15 -06003608
3609 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3610 '-f', fname, '-m')
3611 map_fname = os.path.join(tmpdir, 'image-updated.map')
3612 self.assertTrue(os.path.exists(map_fname))
3613 finally:
3614 shutil.rmtree(tmpdir)
3615
3616 def testReplaceNoEntryPaths(self):
3617 """Test replacing an entry without an entry path"""
3618 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003619 image_fname = tools.get_output_filename('image.bin')
Simon Glassa6cb9952019-07-20 12:24:15 -06003620 with self.assertRaises(ValueError) as e:
3621 control.ReplaceEntries(image_fname, 'fname', None, [])
3622 self.assertIn('Must specify an entry path to read with -f',
3623 str(e.exception))
3624
3625 def testReplaceTooManyEntryPaths(self):
3626 """Test extracting some entries"""
3627 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003628 image_fname = tools.get_output_filename('image.bin')
Simon Glassa6cb9952019-07-20 12:24:15 -06003629 with self.assertRaises(ValueError) as e:
3630 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3631 self.assertIn('Must specify exactly one entry path to write with -f',
3632 str(e.exception))
3633
Simon Glass2250ee62019-08-24 07:22:48 -06003634 def testPackReset16(self):
3635 """Test that an image with an x86 reset16 region can be created"""
3636 data = self._DoReadFile('144_x86_reset16.dts')
3637 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3638
3639 def testPackReset16Spl(self):
3640 """Test that an image with an x86 reset16-spl region can be created"""
3641 data = self._DoReadFile('145_x86_reset16_spl.dts')
3642 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3643
3644 def testPackReset16Tpl(self):
3645 """Test that an image with an x86 reset16-tpl region can be created"""
3646 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3647 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3648
Simon Glass5af12072019-08-24 07:22:50 -06003649 def testPackIntelFit(self):
3650 """Test that an image with an Intel FIT and pointer can be created"""
3651 data = self._DoReadFile('147_intel_fit.dts')
3652 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3653 fit = data[16:32];
3654 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3655 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3656
3657 image = control.images['image']
3658 entries = image.GetEntries()
3659 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3660 self.assertEqual(expected_ptr, ptr)
3661
3662 def testPackIntelFitMissing(self):
3663 """Test detection of a FIT pointer with not FIT region"""
3664 with self.assertRaises(ValueError) as e:
3665 self._DoReadFile('148_intel_fit_missing.dts')
3666 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3667 str(e.exception))
3668
Simon Glass7c150132019-11-06 17:22:44 -07003669 def _CheckSymbolsTplSection(self, dts, expected_vals):
3670 data = self._DoReadFile(dts)
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003671 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE, *expected_vals)
Simon Glass2090f1e2019-08-24 07:23:00 -06003672 upto1 = 4 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003673 expected1 = tools.get_bytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass2090f1e2019-08-24 07:23:00 -06003674 self.assertEqual(expected1, data[:upto1])
3675
3676 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003677 expected2 = tools.get_bytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass2090f1e2019-08-24 07:23:00 -06003678 self.assertEqual(expected2, data[upto1:upto2])
3679
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003680 upto3 = 0x3c + len(U_BOOT_DATA)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003681 expected3 = tools.get_bytes(0xff, 1) + U_BOOT_DATA
Simon Glass2090f1e2019-08-24 07:23:00 -06003682 self.assertEqual(expected3, data[upto2:upto3])
3683
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003684 expected4 = sym_values + U_BOOT_TPL_DATA[24:]
Simon Glass7c150132019-11-06 17:22:44 -07003685 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3686
3687 def testSymbolsTplSection(self):
3688 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3689 self._SetupSplElf('u_boot_binman_syms')
3690 self._SetupTplElf('u_boot_binman_syms')
3691 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003692 [0x04, 0x20, 0x10 + 0x3c, 0x04])
Simon Glass7c150132019-11-06 17:22:44 -07003693
3694 def testSymbolsTplSectionX86(self):
3695 """Test binman can assign symbols in a section with end-at-4gb"""
3696 self._SetupSplElf('u_boot_binman_syms_x86')
3697 self._SetupTplElf('u_boot_binman_syms_x86')
3698 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003699 [0xffffff04, 0xffffff20, 0xffffff3c,
Simon Glass7c150132019-11-06 17:22:44 -07003700 0x04])
Simon Glass2090f1e2019-08-24 07:23:00 -06003701
Simon Glassbf4d0e22019-08-24 07:23:03 -06003702 def testPackX86RomIfwiSectiom(self):
3703 """Test that a section can be placed in an IFWI region"""
3704 self._SetupIfwi('fitimage.bin')
3705 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3706 self._CheckIfwi(data)
3707
Simon Glassea0fff92019-08-24 07:23:07 -06003708 def testPackFspM(self):
3709 """Test that an image with a FSP memory-init binary can be created"""
3710 data = self._DoReadFile('152_intel_fsp_m.dts')
3711 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3712
Simon Glassbc6a88f2019-10-20 21:31:35 -06003713 def testPackFspS(self):
3714 """Test that an image with a FSP silicon-init binary can be created"""
3715 data = self._DoReadFile('153_intel_fsp_s.dts')
3716 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassea0fff92019-08-24 07:23:07 -06003717
Simon Glass998d1482019-10-20 21:31:36 -06003718 def testPackFspT(self):
3719 """Test that an image with a FSP temp-ram-init binary can be created"""
3720 data = self._DoReadFile('154_intel_fsp_t.dts')
3721 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3722
Simon Glass0dc706f2020-07-09 18:39:31 -06003723 def testMkimage(self):
3724 """Test using mkimage to build an image"""
3725 data = self._DoReadFile('156_mkimage.dts')
3726
3727 # Just check that the data appears in the file somewhere
3728 self.assertIn(U_BOOT_SPL_DATA, data)
3729
Simon Glass4f9ee832022-01-09 20:14:09 -07003730 def testMkimageMissing(self):
3731 """Test that binman still produces an image if mkimage is missing"""
3732 with test_util.capture_sys_output() as (_, stderr):
3733 self._DoTestFile('156_mkimage.dts',
3734 force_missing_bintools='mkimage')
3735 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07003736 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass4f9ee832022-01-09 20:14:09 -07003737
Simon Glassce867ad2020-07-09 18:39:36 -06003738 def testExtblob(self):
3739 """Test an image with an external blob"""
3740 data = self._DoReadFile('157_blob_ext.dts')
3741 self.assertEqual(REFCODE_DATA, data)
3742
3743 def testExtblobMissing(self):
3744 """Test an image with a missing external blob"""
3745 with self.assertRaises(ValueError) as e:
3746 self._DoReadFile('158_blob_ext_missing.dts')
3747 self.assertIn("Filename 'missing-file' not found in input path",
3748 str(e.exception))
3749
Simon Glass4f9f1052020-07-09 18:39:38 -06003750 def testExtblobMissingOk(self):
3751 """Test an image with an missing external blob that is allowed"""
Simon Glassb1cca952020-07-09 18:39:40 -06003752 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glassb38da152022-11-09 19:14:42 -07003753 ret = self._DoTestFile('158_blob_ext_missing.dts',
3754 allow_missing=True)
3755 self.assertEqual(103, ret)
Simon Glassb1cca952020-07-09 18:39:40 -06003756 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07003757 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glassb38da152022-11-09 19:14:42 -07003758 self.assertIn('Some images are invalid', err)
3759
3760 def testExtblobMissingOkFlag(self):
3761 """Test an image with an missing external blob allowed with -W"""
3762 with test_util.capture_sys_output() as (stdout, stderr):
3763 ret = self._DoTestFile('158_blob_ext_missing.dts',
3764 allow_missing=True, ignore_missing=True)
3765 self.assertEqual(0, ret)
3766 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07003767 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glassb38da152022-11-09 19:14:42 -07003768 self.assertIn('Some images are invalid', err)
Simon Glassb1cca952020-07-09 18:39:40 -06003769
3770 def testExtblobMissingOkSect(self):
3771 """Test an image with an missing external blob that is allowed"""
3772 with test_util.capture_sys_output() as (stdout, stderr):
3773 self._DoTestFile('159_blob_ext_missing_sect.dts',
3774 allow_missing=True)
3775 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07003776 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext blob-ext2")
Simon Glass4f9f1052020-07-09 18:39:38 -06003777
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003778 def testPackX86RomMeMissingDesc(self):
3779 """Test that an missing Intel descriptor entry is allowed"""
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003780 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass52b10dd2020-07-25 15:11:19 -06003781 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003782 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07003783 self.assertRegex(err, "Image 'image'.*missing.*: intel-descriptor")
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003784
3785 def testPackX86RomMissingIfwi(self):
3786 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3787 self._SetupIfwi('fitimage.bin')
3788 pathname = os.path.join(self._indir, 'fitimage.bin')
3789 os.remove(pathname)
3790 with test_util.capture_sys_output() as (stdout, stderr):
3791 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3792 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07003793 self.assertRegex(err, "Image 'image'.*missing.*: intel-ifwi")
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003794
Simon Glass8d2ef3e2022-02-11 13:23:21 -07003795 def testPackOverlapZero(self):
Simon Glassb3295fd2020-07-09 18:39:42 -06003796 """Test that zero-size overlapping regions are ignored"""
3797 self._DoTestFile('160_pack_overlap_zero.dts')
3798
Alper Nebi Yasak21353312022-02-08 01:08:04 +03003799 def _CheckSimpleFitData(self, fit_data, kernel_data, fdt1_data):
Simon Glassfdc34362020-07-09 18:39:45 -06003800 # The data should be inside the FIT
3801 dtb = fdt.Fdt.FromData(fit_data)
3802 dtb.Scan()
3803 fnode = dtb.GetNode('/images/kernel')
3804 self.assertIn('data', fnode.props)
3805
3806 fname = os.path.join(self._indir, 'fit_data.fit')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003807 tools.write_file(fname, fit_data)
3808 out = tools.run('dumpimage', '-l', fname)
Simon Glassfdc34362020-07-09 18:39:45 -06003809
3810 # Check a few features to make sure the plumbing works. We don't need
3811 # to test the operation of mkimage or dumpimage here. First convert the
3812 # output into a dict where the keys are the fields printed by dumpimage
3813 # and the values are a list of values for each field
3814 lines = out.splitlines()
3815
3816 # Converts "Compression: gzip compressed" into two groups:
3817 # 'Compression' and 'gzip compressed'
3818 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3819 vals = collections.defaultdict(list)
3820 for line in lines:
3821 mat = re_line.match(line)
3822 vals[mat.group(1)].append(mat.group(2))
3823
3824 self.assertEquals('FIT description: test-desc', lines[0])
3825 self.assertIn('Created:', lines[1])
3826 self.assertIn('Image 0 (kernel)', vals)
3827 self.assertIn('Hash value', vals)
3828 data_sizes = vals.get('Data Size')
3829 self.assertIsNotNone(data_sizes)
3830 self.assertEqual(2, len(data_sizes))
3831 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
Alper Nebi Yasak21353312022-02-08 01:08:04 +03003832 self.assertEqual(len(kernel_data), int(data_sizes[0].split()[0]))
3833 self.assertEqual(len(fdt1_data), int(data_sizes[1].split()[0]))
3834
Alper Nebi Yasake7368782022-03-27 18:31:47 +03003835 # Check if entry listing correctly omits /images/
3836 image = control.images['image']
3837 fit_entry = image.GetEntries()['fit']
3838 subentries = list(fit_entry.GetEntries().keys())
3839 expected = ['kernel', 'fdt-1']
3840 self.assertEqual(expected, subentries)
3841
Alper Nebi Yasak21353312022-02-08 01:08:04 +03003842 def testSimpleFit(self):
3843 """Test an image with a FIT inside"""
3844 data = self._DoReadFile('161_fit.dts')
3845 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3846 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3847 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3848
3849 self._CheckSimpleFitData(fit_data, U_BOOT_DATA, U_BOOT_SPL_DTB_DATA)
3850
3851 def testSimpleFitExpandsSubentries(self):
3852 """Test that FIT images expand their subentries"""
3853 data = self._DoReadFileDtb('161_fit.dts', use_expanded=True)[0]
3854 self.assertEqual(U_BOOT_EXP_DATA, data[:len(U_BOOT_EXP_DATA)])
3855 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3856 fit_data = data[len(U_BOOT_EXP_DATA):-len(U_BOOT_NODTB_DATA)]
3857
3858 self._CheckSimpleFitData(fit_data, U_BOOT_EXP_DATA, U_BOOT_SPL_DTB_DATA)
Simon Glassfdc34362020-07-09 18:39:45 -06003859
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003860 def testSimpleFitImagePos(self):
3861 """Test that we have correct image-pos for FIT subentries"""
3862 data, _, _, out_dtb_fname = self._DoReadFileDtb('161_fit.dts',
3863 update_dtb=True)
3864 dtb = fdt.Fdt(out_dtb_fname)
3865 dtb.Scan()
3866 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3867
Simon Glass38397d02022-03-05 20:19:01 -07003868 self.maxDiff = None
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003869 self.assertEqual({
3870 'image-pos': 0,
3871 'offset': 0,
3872 'size': 1890,
3873
3874 'u-boot:image-pos': 0,
3875 'u-boot:offset': 0,
3876 'u-boot:size': 4,
3877
3878 'fit:image-pos': 4,
3879 'fit:offset': 4,
3880 'fit:size': 1840,
3881
Simon Glass38397d02022-03-05 20:19:01 -07003882 'fit/images/kernel:image-pos': 304,
3883 'fit/images/kernel:offset': 300,
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003884 'fit/images/kernel:size': 4,
3885
Simon Glass38397d02022-03-05 20:19:01 -07003886 'fit/images/kernel/u-boot:image-pos': 304,
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003887 'fit/images/kernel/u-boot:offset': 0,
3888 'fit/images/kernel/u-boot:size': 4,
3889
Simon Glass38397d02022-03-05 20:19:01 -07003890 'fit/images/fdt-1:image-pos': 552,
3891 'fit/images/fdt-1:offset': 548,
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003892 'fit/images/fdt-1:size': 6,
3893
Simon Glass38397d02022-03-05 20:19:01 -07003894 'fit/images/fdt-1/u-boot-spl-dtb:image-pos': 552,
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003895 'fit/images/fdt-1/u-boot-spl-dtb:offset': 0,
3896 'fit/images/fdt-1/u-boot-spl-dtb:size': 6,
3897
3898 'u-boot-nodtb:image-pos': 1844,
3899 'u-boot-nodtb:offset': 1844,
3900 'u-boot-nodtb:size': 46,
3901 }, props)
3902
3903 # Actually check the data is where we think it is
3904 for node, expected in [
3905 ("u-boot", U_BOOT_DATA),
3906 ("fit/images/kernel", U_BOOT_DATA),
3907 ("fit/images/kernel/u-boot", U_BOOT_DATA),
3908 ("fit/images/fdt-1", U_BOOT_SPL_DTB_DATA),
3909 ("fit/images/fdt-1/u-boot-spl-dtb", U_BOOT_SPL_DTB_DATA),
3910 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
3911 ]:
3912 image_pos = props[f"{node}:image-pos"]
3913 size = props[f"{node}:size"]
3914 self.assertEqual(len(expected), size)
3915 self.assertEqual(expected, data[image_pos:image_pos+size])
3916
Simon Glassfdc34362020-07-09 18:39:45 -06003917 def testFitExternal(self):
Simon Glasse9d336d2020-09-01 05:13:55 -06003918 """Test an image with an FIT with external images"""
Simon Glassfdc34362020-07-09 18:39:45 -06003919 data = self._DoReadFile('162_fit_external.dts')
3920 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3921
Simon Glass8bc78b72022-01-09 20:13:39 -07003922 # Size of the external-data region as set up by mkimage
3923 external_data_size = len(U_BOOT_DATA) + 2
3924 expected_size = (len(U_BOOT_DATA) + 0x400 +
Simon Glassc1aa66e2022-01-29 14:14:04 -07003925 tools.align(external_data_size, 4) +
Simon Glass8bc78b72022-01-09 20:13:39 -07003926 len(U_BOOT_NODTB_DATA))
3927
Simon Glassfdc34362020-07-09 18:39:45 -06003928 # The data should be outside the FIT
3929 dtb = fdt.Fdt.FromData(fit_data)
3930 dtb.Scan()
3931 fnode = dtb.GetNode('/images/kernel')
3932 self.assertNotIn('data', fnode.props)
Simon Glass8bc78b72022-01-09 20:13:39 -07003933 self.assertEqual(len(U_BOOT_DATA),
3934 fdt_util.fdt32_to_cpu(fnode.props['data-size'].value))
3935 fit_pos = 0x400;
3936 self.assertEqual(
3937 fit_pos,
3938 fdt_util.fdt32_to_cpu(fnode.props['data-position'].value))
3939
3940 self.assertEquals(expected_size, len(data))
3941 actual_pos = len(U_BOOT_DATA) + fit_pos
3942 self.assertEqual(U_BOOT_DATA + b'aa',
3943 data[actual_pos:actual_pos + external_data_size])
Simon Glass12bb1a92019-07-20 12:23:51 -06003944
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003945 def testFitExternalImagePos(self):
3946 """Test that we have correct image-pos for external FIT subentries"""
3947 data, _, _, out_dtb_fname = self._DoReadFileDtb('162_fit_external.dts',
3948 update_dtb=True)
3949 dtb = fdt.Fdt(out_dtb_fname)
3950 dtb.Scan()
3951 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3952
3953 self.assertEqual({
3954 'image-pos': 0,
3955 'offset': 0,
3956 'size': 1082,
3957
3958 'u-boot:image-pos': 0,
3959 'u-boot:offset': 0,
3960 'u-boot:size': 4,
3961
3962 'fit:size': 1032,
3963 'fit:offset': 4,
3964 'fit:image-pos': 4,
3965
3966 'fit/images/kernel:size': 4,
3967 'fit/images/kernel:offset': 1024,
3968 'fit/images/kernel:image-pos': 1028,
3969
3970 'fit/images/kernel/u-boot:size': 4,
3971 'fit/images/kernel/u-boot:offset': 0,
3972 'fit/images/kernel/u-boot:image-pos': 1028,
3973
3974 'fit/images/fdt-1:size': 2,
3975 'fit/images/fdt-1:offset': 1028,
3976 'fit/images/fdt-1:image-pos': 1032,
3977
3978 'fit/images/fdt-1/_testing:size': 2,
3979 'fit/images/fdt-1/_testing:offset': 0,
3980 'fit/images/fdt-1/_testing:image-pos': 1032,
3981
3982 'u-boot-nodtb:image-pos': 1036,
3983 'u-boot-nodtb:offset': 1036,
3984 'u-boot-nodtb:size': 46,
3985 }, props)
3986
3987 # Actually check the data is where we think it is
3988 for node, expected in [
3989 ("u-boot", U_BOOT_DATA),
3990 ("fit/images/kernel", U_BOOT_DATA),
3991 ("fit/images/kernel/u-boot", U_BOOT_DATA),
3992 ("fit/images/fdt-1", b'aa'),
3993 ("fit/images/fdt-1/_testing", b'aa'),
3994 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
3995 ]:
3996 image_pos = props[f"{node}:image-pos"]
3997 size = props[f"{node}:size"]
3998 self.assertEqual(len(expected), size)
3999 self.assertEqual(expected, data[image_pos:image_pos+size])
4000
Simon Glass4f9ee832022-01-09 20:14:09 -07004001 def testFitMissing(self):
Simon Glass033828c2023-03-02 17:02:43 -07004002 """Test that binman complains if mkimage is missing"""
4003 with self.assertRaises(ValueError) as e:
4004 self._DoTestFile('162_fit_external.dts',
4005 force_missing_bintools='mkimage')
4006 self.assertIn("Node '/binman/fit': Missing tool: 'mkimage'",
4007 str(e.exception))
4008
4009 def testFitMissingOK(self):
Simon Glass4f9ee832022-01-09 20:14:09 -07004010 """Test that binman still produces a FIT image if mkimage is missing"""
4011 with test_util.capture_sys_output() as (_, stderr):
Simon Glass033828c2023-03-02 17:02:43 -07004012 self._DoTestFile('162_fit_external.dts', allow_missing=True,
Simon Glass4f9ee832022-01-09 20:14:09 -07004013 force_missing_bintools='mkimage')
4014 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07004015 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass4f9ee832022-01-09 20:14:09 -07004016
Alper Nebi Yasak8001d0b2020-08-31 12:58:18 +03004017 def testSectionIgnoreHashSignature(self):
4018 """Test that sections ignore hash, signature nodes for its data"""
4019 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
4020 expected = (U_BOOT_DATA + U_BOOT_DATA)
4021 self.assertEqual(expected, data)
4022
Alper Nebi Yasak3fdeb142020-08-31 12:58:19 +03004023 def testPadInSections(self):
4024 """Test pad-before, pad-after for entries in sections"""
Simon Glassf90d9062020-10-26 17:40:09 -06004025 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4026 '166_pad_in_sections.dts', update_dtb=True)
Simon Glassc1aa66e2022-01-29 14:14:04 -07004027 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4028 U_BOOT_DATA + tools.get_bytes(ord('!'), 6) +
Alper Nebi Yasak3fdeb142020-08-31 12:58:19 +03004029 U_BOOT_DATA)
4030 self.assertEqual(expected, data)
4031
Simon Glassf90d9062020-10-26 17:40:09 -06004032 dtb = fdt.Fdt(out_dtb_fname)
4033 dtb.Scan()
4034 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
4035 expected = {
4036 'image-pos': 0,
4037 'offset': 0,
4038 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
4039
4040 'section:image-pos': 0,
4041 'section:offset': 0,
4042 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
4043
4044 'section/before:image-pos': 0,
4045 'section/before:offset': 0,
4046 'section/before:size': len(U_BOOT_DATA),
4047
4048 'section/u-boot:image-pos': 4,
4049 'section/u-boot:offset': 4,
4050 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
4051
4052 'section/after:image-pos': 26,
4053 'section/after:offset': 26,
4054 'section/after:size': len(U_BOOT_DATA),
4055 }
4056 self.assertEqual(expected, props)
4057
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03004058 def testFitImageSubentryAlignment(self):
4059 """Test relative alignability of FIT image subentries"""
Alper Nebi Yasakf3078d42022-02-08 01:08:07 +03004060 self._SetupSplElf()
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03004061 entry_args = {
4062 'test-id': TEXT_DATA,
4063 }
4064 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
4065 entry_args=entry_args)
4066 dtb = fdt.Fdt.FromData(data)
4067 dtb.Scan()
4068
4069 node = dtb.GetNode('/images/kernel')
4070 data = dtb.GetProps(node)["data"].bytes
4071 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
Simon Glassc1aa66e2022-01-29 14:14:04 -07004072 expected = (tools.get_bytes(0, 0x20) + U_BOOT_SPL_DATA +
4073 tools.get_bytes(0, align_pad) + U_BOOT_DATA)
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03004074 self.assertEqual(expected, data)
4075
4076 node = dtb.GetNode('/images/fdt-1')
4077 data = dtb.GetProps(node)["data"].bytes
Simon Glassc1aa66e2022-01-29 14:14:04 -07004078 expected = (U_BOOT_SPL_DTB_DATA + tools.get_bytes(0, 20) +
4079 tools.to_bytes(TEXT_DATA) + tools.get_bytes(0, 30) +
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03004080 U_BOOT_DTB_DATA)
4081 self.assertEqual(expected, data)
4082
4083 def testFitExtblobMissingOk(self):
4084 """Test a FIT with a missing external blob that is allowed"""
4085 with test_util.capture_sys_output() as (stdout, stderr):
4086 self._DoTestFile('168_fit_missing_blob.dts',
4087 allow_missing=True)
4088 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07004089 self.assertRegex(err, "Image 'image'.*missing.*: atf-bl31")
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03004090
Simon Glass3decfa32020-09-01 05:13:54 -06004091 def testBlobNamedByArgMissing(self):
4092 """Test handling of a missing entry arg"""
4093 with self.assertRaises(ValueError) as e:
4094 self._DoReadFile('068_blob_named_by_arg.dts')
4095 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
4096 str(e.exception))
4097
Simon Glassdc2f81a2020-09-01 05:13:58 -06004098 def testPackBl31(self):
4099 """Test that an image with an ATF BL31 binary can be created"""
4100 data = self._DoReadFile('169_atf_bl31.dts')
4101 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
4102
Samuel Holland18bd4552020-10-21 21:12:15 -05004103 def testPackScp(self):
4104 """Test that an image with an SCP binary can be created"""
4105 data = self._DoReadFile('172_scp.dts')
4106 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
4107
Simon Glass6cf99532020-09-01 05:13:59 -06004108 def testFitFdt(self):
4109 """Test an image with an FIT with multiple FDT images"""
4110 def _CheckFdt(seq, expected_data):
4111 """Check the FDT nodes
4112
4113 Args:
4114 seq: Sequence number to check (0 or 1)
4115 expected_data: Expected contents of 'data' property
4116 """
4117 name = 'fdt-%d' % seq
4118 fnode = dtb.GetNode('/images/%s' % name)
4119 self.assertIsNotNone(fnode)
4120 self.assertEqual({'description','type', 'compression', 'data'},
4121 set(fnode.props.keys()))
4122 self.assertEqual(expected_data, fnode.props['data'].bytes)
4123 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
4124 fnode.props['description'].value)
Jan Kiszkab2106612022-02-28 17:06:20 +01004125 self.assertEqual(fnode.subnodes[0].name, 'hash')
Simon Glass6cf99532020-09-01 05:13:59 -06004126
4127 def _CheckConfig(seq, expected_data):
4128 """Check the configuration nodes
4129
4130 Args:
4131 seq: Sequence number to check (0 or 1)
4132 expected_data: Expected contents of 'data' property
4133 """
4134 cnode = dtb.GetNode('/configurations')
4135 self.assertIn('default', cnode.props)
Simon Glassc0f1ebe2020-09-06 10:39:08 -06004136 self.assertEqual('config-2', cnode.props['default'].value)
Simon Glass6cf99532020-09-01 05:13:59 -06004137
4138 name = 'config-%d' % seq
4139 fnode = dtb.GetNode('/configurations/%s' % name)
4140 self.assertIsNotNone(fnode)
4141 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
4142 set(fnode.props.keys()))
4143 self.assertEqual('conf-test-fdt%d.dtb' % seq,
4144 fnode.props['description'].value)
4145 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
4146
4147 entry_args = {
4148 'of-list': 'test-fdt1 test-fdt2',
Simon Glassc0f1ebe2020-09-06 10:39:08 -06004149 'default-dt': 'test-fdt2',
Simon Glass6cf99532020-09-01 05:13:59 -06004150 }
4151 data = self._DoReadFileDtb(
Bin Mengaa75ce92021-05-10 20:23:32 +08004152 '170_fit_fdt.dts',
Simon Glass6cf99532020-09-01 05:13:59 -06004153 entry_args=entry_args,
4154 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4155 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4156 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4157
4158 dtb = fdt.Fdt.FromData(fit_data)
4159 dtb.Scan()
4160 fnode = dtb.GetNode('/images/kernel')
4161 self.assertIn('data', fnode.props)
4162
4163 # Check all the properties in fdt-1 and fdt-2
4164 _CheckFdt(1, TEST_FDT1_DATA)
4165 _CheckFdt(2, TEST_FDT2_DATA)
4166
4167 # Check configurations
4168 _CheckConfig(1, TEST_FDT1_DATA)
4169 _CheckConfig(2, TEST_FDT2_DATA)
4170
4171 def testFitFdtMissingList(self):
4172 """Test handling of a missing 'of-list' entry arg"""
4173 with self.assertRaises(ValueError) as e:
Bin Mengaa75ce92021-05-10 20:23:32 +08004174 self._DoReadFile('170_fit_fdt.dts')
Simon Glass6cf99532020-09-01 05:13:59 -06004175 self.assertIn("Generator node requires 'of-list' entry argument",
4176 str(e.exception))
4177
4178 def testFitFdtEmptyList(self):
4179 """Test handling of an empty 'of-list' entry arg"""
4180 entry_args = {
4181 'of-list': '',
4182 }
4183 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
4184
4185 def testFitFdtMissingProp(self):
4186 """Test handling of a missing 'fit,fdt-list' property"""
4187 with self.assertRaises(ValueError) as e:
4188 self._DoReadFile('171_fit_fdt_missing_prop.dts')
4189 self.assertIn("Generator node requires 'fit,fdt-list' property",
4190 str(e.exception))
Simon Glassdc2f81a2020-09-01 05:13:58 -06004191
Simon Glassc0f1ebe2020-09-06 10:39:08 -06004192 def testFitFdtMissing(self):
4193 """Test handling of a missing 'default-dt' entry arg"""
4194 entry_args = {
4195 'of-list': 'test-fdt1 test-fdt2',
4196 }
4197 with self.assertRaises(ValueError) as e:
4198 self._DoReadFileDtb(
Bin Mengaa75ce92021-05-10 20:23:32 +08004199 '170_fit_fdt.dts',
Simon Glassc0f1ebe2020-09-06 10:39:08 -06004200 entry_args=entry_args,
4201 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4202 self.assertIn("Generated 'default' node requires default-dt entry argument",
4203 str(e.exception))
4204
4205 def testFitFdtNotInList(self):
4206 """Test handling of a default-dt that is not in the of-list"""
4207 entry_args = {
4208 'of-list': 'test-fdt1 test-fdt2',
4209 'default-dt': 'test-fdt3',
4210 }
4211 with self.assertRaises(ValueError) as e:
4212 self._DoReadFileDtb(
Bin Mengaa75ce92021-05-10 20:23:32 +08004213 '170_fit_fdt.dts',
Simon Glassc0f1ebe2020-09-06 10:39:08 -06004214 entry_args=entry_args,
4215 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4216 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
4217 str(e.exception))
4218
Simon Glassb2381432020-09-06 10:39:09 -06004219 def testFitExtblobMissingHelp(self):
4220 """Test display of help messages when an external blob is missing"""
4221 control.missing_blob_help = control._ReadMissingBlobHelp()
4222 control.missing_blob_help['wibble'] = 'Wibble test'
4223 control.missing_blob_help['another'] = 'Another test'
4224 with test_util.capture_sys_output() as (stdout, stderr):
4225 self._DoTestFile('168_fit_missing_blob.dts',
4226 allow_missing=True)
4227 err = stderr.getvalue()
4228
4229 # We can get the tag from the name, the type or the missing-msg
4230 # property. Check all three.
4231 self.assertIn('You may need to build ARM Trusted', err)
4232 self.assertIn('Wibble test', err)
4233 self.assertIn('Another test', err)
4234
Simon Glass204aa782020-09-06 10:35:32 -06004235 def testMissingBlob(self):
4236 """Test handling of a blob containing a missing file"""
4237 with self.assertRaises(ValueError) as e:
4238 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
4239 self.assertIn("Filename 'missing' not found in input path",
4240 str(e.exception))
4241
Simon Glassfb91d562020-09-06 10:35:33 -06004242 def testEnvironment(self):
4243 """Test adding a U-Boot environment"""
4244 data = self._DoReadFile('174_env.dts')
4245 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
4246 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4247 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4248 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
4249 env)
4250
4251 def testEnvironmentNoSize(self):
4252 """Test that a missing 'size' property is detected"""
4253 with self.assertRaises(ValueError) as e:
Simon Glassa4dfe3e2020-10-26 17:40:00 -06004254 self._DoTestFile('175_env_no_size.dts')
Simon Glassfb91d562020-09-06 10:35:33 -06004255 self.assertIn("'u-boot-env' entry must have a size property",
4256 str(e.exception))
4257
4258 def testEnvironmentTooSmall(self):
4259 """Test handling of an environment that does not fit"""
4260 with self.assertRaises(ValueError) as e:
Simon Glassa4dfe3e2020-10-26 17:40:00 -06004261 self._DoTestFile('176_env_too_small.dts')
Simon Glassfb91d562020-09-06 10:35:33 -06004262
4263 # checksum, start byte, environment with \0 terminator, final \0
4264 need = 4 + 1 + len(ENV_DATA) + 1 + 1
4265 short = need - 0x8
4266 self.assertIn("too small to hold data (need %#x more bytes)" % short,
4267 str(e.exception))
4268
Simon Glassf2c0dd82020-10-26 17:40:01 -06004269 def testSkipAtStart(self):
4270 """Test handling of skip-at-start section"""
4271 data = self._DoReadFile('177_skip_at_start.dts')
4272 self.assertEqual(U_BOOT_DATA, data)
4273
4274 image = control.images['image']
4275 entries = image.GetEntries()
4276 section = entries['section']
4277 self.assertEqual(0, section.offset)
4278 self.assertEqual(len(U_BOOT_DATA), section.size)
4279 self.assertEqual(U_BOOT_DATA, section.GetData())
4280
4281 entry = section.GetEntries()['u-boot']
4282 self.assertEqual(16, entry.offset)
4283 self.assertEqual(len(U_BOOT_DATA), entry.size)
4284 self.assertEqual(U_BOOT_DATA, entry.data)
4285
4286 def testSkipAtStartPad(self):
4287 """Test handling of skip-at-start section with padded entry"""
4288 data = self._DoReadFile('178_skip_at_start_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004289 before = tools.get_bytes(0, 8)
4290 after = tools.get_bytes(0, 4)
Simon Glassf2c0dd82020-10-26 17:40:01 -06004291 all = before + U_BOOT_DATA + after
4292 self.assertEqual(all, data)
4293
4294 image = control.images['image']
4295 entries = image.GetEntries()
4296 section = entries['section']
4297 self.assertEqual(0, section.offset)
4298 self.assertEqual(len(all), section.size)
4299 self.assertEqual(all, section.GetData())
4300
4301 entry = section.GetEntries()['u-boot']
4302 self.assertEqual(16, entry.offset)
4303 self.assertEqual(len(all), entry.size)
4304 self.assertEqual(U_BOOT_DATA, entry.data)
4305
4306 def testSkipAtStartSectionPad(self):
4307 """Test handling of skip-at-start section with padding"""
4308 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004309 before = tools.get_bytes(0, 8)
4310 after = tools.get_bytes(0, 4)
Simon Glassf2c0dd82020-10-26 17:40:01 -06004311 all = before + U_BOOT_DATA + after
Simon Glassd1d3ad72020-10-26 17:40:13 -06004312 self.assertEqual(all, data)
Simon Glassf2c0dd82020-10-26 17:40:01 -06004313
4314 image = control.images['image']
4315 entries = image.GetEntries()
4316 section = entries['section']
4317 self.assertEqual(0, section.offset)
4318 self.assertEqual(len(all), section.size)
Simon Glass63e7ba62020-10-26 17:40:16 -06004319 self.assertEqual(U_BOOT_DATA, section.data)
Simon Glassd1d3ad72020-10-26 17:40:13 -06004320 self.assertEqual(all, section.GetPaddedData())
Simon Glassf2c0dd82020-10-26 17:40:01 -06004321
4322 entry = section.GetEntries()['u-boot']
4323 self.assertEqual(16, entry.offset)
4324 self.assertEqual(len(U_BOOT_DATA), entry.size)
4325 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassfb91d562020-09-06 10:35:33 -06004326
Simon Glass7d398bb2020-10-26 17:40:14 -06004327 def testSectionPad(self):
4328 """Testing padding with sections"""
4329 data = self._DoReadFile('180_section_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004330 expected = (tools.get_bytes(ord('&'), 3) +
4331 tools.get_bytes(ord('!'), 5) +
Simon Glass7d398bb2020-10-26 17:40:14 -06004332 U_BOOT_DATA +
Simon Glassc1aa66e2022-01-29 14:14:04 -07004333 tools.get_bytes(ord('!'), 1) +
4334 tools.get_bytes(ord('&'), 2))
Simon Glass7d398bb2020-10-26 17:40:14 -06004335 self.assertEqual(expected, data)
4336
4337 def testSectionAlign(self):
4338 """Testing alignment with sections"""
4339 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4340 expected = (b'\0' + # fill section
Simon Glassc1aa66e2022-01-29 14:14:04 -07004341 tools.get_bytes(ord('&'), 1) + # padding to section align
Simon Glass7d398bb2020-10-26 17:40:14 -06004342 b'\0' + # fill section
Simon Glassc1aa66e2022-01-29 14:14:04 -07004343 tools.get_bytes(ord('!'), 3) + # padding to u-boot align
Simon Glass7d398bb2020-10-26 17:40:14 -06004344 U_BOOT_DATA +
Simon Glassc1aa66e2022-01-29 14:14:04 -07004345 tools.get_bytes(ord('!'), 4) + # padding to u-boot size
4346 tools.get_bytes(ord('!'), 4)) # padding to section size
Simon Glass7d398bb2020-10-26 17:40:14 -06004347 self.assertEqual(expected, data)
4348
Simon Glass8f5ef892020-10-26 17:40:25 -06004349 def testCompressImage(self):
4350 """Test compression of the entire image"""
4351 self._CheckLz4()
4352 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4353 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4354 dtb = fdt.Fdt(out_dtb_fname)
4355 dtb.Scan()
4356 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4357 'uncomp-size'])
4358 orig = self._decompress(data)
4359 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4360
4361 # Do a sanity check on various fields
4362 image = control.images['image']
4363 entries = image.GetEntries()
4364 self.assertEqual(2, len(entries))
4365
4366 entry = entries['blob']
4367 self.assertEqual(COMPRESS_DATA, entry.data)
4368 self.assertEqual(len(COMPRESS_DATA), entry.size)
4369
4370 entry = entries['u-boot']
4371 self.assertEqual(U_BOOT_DATA, entry.data)
4372 self.assertEqual(len(U_BOOT_DATA), entry.size)
4373
4374 self.assertEqual(len(data), image.size)
4375 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4376 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4377 orig = self._decompress(image.data)
4378 self.assertEqual(orig, image.uncomp_data)
4379
4380 expected = {
4381 'blob:offset': 0,
4382 'blob:size': len(COMPRESS_DATA),
4383 'u-boot:offset': len(COMPRESS_DATA),
4384 'u-boot:size': len(U_BOOT_DATA),
4385 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4386 'offset': 0,
4387 'image-pos': 0,
4388 'size': len(data),
4389 }
4390 self.assertEqual(expected, props)
4391
4392 def testCompressImageLess(self):
4393 """Test compression where compression reduces the image size"""
4394 self._CheckLz4()
4395 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4396 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4397 dtb = fdt.Fdt(out_dtb_fname)
4398 dtb.Scan()
4399 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4400 'uncomp-size'])
4401 orig = self._decompress(data)
4402
4403 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
4404
4405 # Do a sanity check on various fields
4406 image = control.images['image']
4407 entries = image.GetEntries()
4408 self.assertEqual(2, len(entries))
4409
4410 entry = entries['blob']
4411 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4412 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4413
4414 entry = entries['u-boot']
4415 self.assertEqual(U_BOOT_DATA, entry.data)
4416 self.assertEqual(len(U_BOOT_DATA), entry.size)
4417
4418 self.assertEqual(len(data), image.size)
4419 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4420 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4421 image.uncomp_size)
4422 orig = self._decompress(image.data)
4423 self.assertEqual(orig, image.uncomp_data)
4424
4425 expected = {
4426 'blob:offset': 0,
4427 'blob:size': len(COMPRESS_DATA_BIG),
4428 'u-boot:offset': len(COMPRESS_DATA_BIG),
4429 'u-boot:size': len(U_BOOT_DATA),
4430 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4431 'offset': 0,
4432 'image-pos': 0,
4433 'size': len(data),
4434 }
4435 self.assertEqual(expected, props)
4436
4437 def testCompressSectionSize(self):
4438 """Test compression of a section with a fixed size"""
4439 self._CheckLz4()
4440 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4441 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4442 dtb = fdt.Fdt(out_dtb_fname)
4443 dtb.Scan()
4444 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4445 'uncomp-size'])
4446 orig = self._decompress(data)
4447 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4448 expected = {
4449 'section/blob:offset': 0,
4450 'section/blob:size': len(COMPRESS_DATA),
4451 'section/u-boot:offset': len(COMPRESS_DATA),
4452 'section/u-boot:size': len(U_BOOT_DATA),
4453 'section:offset': 0,
4454 'section:image-pos': 0,
4455 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4456 'section:size': 0x30,
4457 'offset': 0,
4458 'image-pos': 0,
4459 'size': 0x30,
4460 }
4461 self.assertEqual(expected, props)
4462
4463 def testCompressSection(self):
4464 """Test compression of a section with no fixed size"""
4465 self._CheckLz4()
4466 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4467 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4468 dtb = fdt.Fdt(out_dtb_fname)
4469 dtb.Scan()
4470 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4471 'uncomp-size'])
4472 orig = self._decompress(data)
4473 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4474 expected = {
4475 'section/blob:offset': 0,
4476 'section/blob:size': len(COMPRESS_DATA),
4477 'section/u-boot:offset': len(COMPRESS_DATA),
4478 'section/u-boot:size': len(U_BOOT_DATA),
4479 'section:offset': 0,
4480 'section:image-pos': 0,
4481 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4482 'section:size': len(data),
4483 'offset': 0,
4484 'image-pos': 0,
4485 'size': len(data),
4486 }
4487 self.assertEqual(expected, props)
4488
Stefan Herbrechtsmeierc3665a82022-08-19 16:25:31 +02004489 def testLz4Missing(self):
4490 """Test that binman still produces an image if lz4 is missing"""
4491 with test_util.capture_sys_output() as (_, stderr):
4492 self._DoTestFile('185_compress_section.dts',
4493 force_missing_bintools='lz4')
4494 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07004495 self.assertRegex(err, "Image 'image'.*missing bintools.*: lz4")
Stefan Herbrechtsmeierc3665a82022-08-19 16:25:31 +02004496
Simon Glass8f5ef892020-10-26 17:40:25 -06004497 def testCompressExtra(self):
4498 """Test compression of a section with no fixed size"""
4499 self._CheckLz4()
4500 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4501 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4502 dtb = fdt.Fdt(out_dtb_fname)
4503 dtb.Scan()
4504 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4505 'uncomp-size'])
4506
4507 base = data[len(U_BOOT_DATA):]
4508 self.assertEquals(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
4509 rest = base[len(U_BOOT_DATA):]
4510
4511 # Check compressed data
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +02004512 bintool = self.comp_bintools['lz4']
4513 expect1 = bintool.compress(COMPRESS_DATA + U_BOOT_DATA)
Stefan Herbrechtsmeierfa24f552022-08-19 16:25:23 +02004514 data1 = rest[:len(expect1)]
4515 section1 = self._decompress(data1)
4516 self.assertEquals(expect1, data1)
Simon Glass8f5ef892020-10-26 17:40:25 -06004517 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, section1)
4518 rest1 = rest[len(expect1):]
4519
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +02004520 expect2 = bintool.compress(COMPRESS_DATA + COMPRESS_DATA)
Stefan Herbrechtsmeierfa24f552022-08-19 16:25:23 +02004521 data2 = rest1[:len(expect2)]
4522 section2 = self._decompress(data2)
4523 self.assertEquals(expect2, data2)
Simon Glass8f5ef892020-10-26 17:40:25 -06004524 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA, section2)
4525 rest2 = rest1[len(expect2):]
4526
4527 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4528 len(expect2) + len(U_BOOT_DATA))
4529 #self.assertEquals(expect_size, len(data))
4530
4531 #self.assertEquals(U_BOOT_DATA, rest2)
4532
4533 self.maxDiff = None
4534 expected = {
4535 'u-boot:offset': 0,
4536 'u-boot:image-pos': 0,
4537 'u-boot:size': len(U_BOOT_DATA),
4538
4539 'base:offset': len(U_BOOT_DATA),
4540 'base:image-pos': len(U_BOOT_DATA),
4541 'base:size': len(data) - len(U_BOOT_DATA),
4542 'base/u-boot:offset': 0,
4543 'base/u-boot:image-pos': len(U_BOOT_DATA),
4544 'base/u-boot:size': len(U_BOOT_DATA),
4545 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4546 len(expect2),
4547 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4548 len(expect2),
4549 'base/u-boot2:size': len(U_BOOT_DATA),
4550
4551 'base/section:offset': len(U_BOOT_DATA),
4552 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4553 'base/section:size': len(expect1),
4554 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4555 'base/section/blob:offset': 0,
4556 'base/section/blob:size': len(COMPRESS_DATA),
4557 'base/section/u-boot:offset': len(COMPRESS_DATA),
4558 'base/section/u-boot:size': len(U_BOOT_DATA),
4559
4560 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4561 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4562 'base/section2:size': len(expect2),
4563 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4564 'base/section2/blob:offset': 0,
4565 'base/section2/blob:size': len(COMPRESS_DATA),
4566 'base/section2/blob2:offset': len(COMPRESS_DATA),
4567 'base/section2/blob2:size': len(COMPRESS_DATA),
4568
4569 'offset': 0,
4570 'image-pos': 0,
4571 'size': len(data),
4572 }
4573 self.assertEqual(expected, props)
4574
Simon Glass870a9ea2021-01-06 21:35:15 -07004575 def testSymbolsSubsection(self):
4576 """Test binman can assign symbols from a subsection"""
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03004577 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glass870a9ea2021-01-06 21:35:15 -07004578
Simon Glass939d1062021-01-06 21:35:16 -07004579 def testReadImageEntryArg(self):
4580 """Test reading an image that would need an entry arg to generate"""
4581 entry_args = {
4582 'cros-ec-rw-path': 'ecrw.bin',
4583 }
4584 data = self.data = self._DoReadFileDtb(
4585 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4586 entry_args=entry_args)
4587
Simon Glassc1aa66e2022-01-29 14:14:04 -07004588 image_fname = tools.get_output_filename('image.bin')
Simon Glass939d1062021-01-06 21:35:16 -07004589 orig_image = control.images['image']
4590
4591 # This should not generate an error about the missing 'cros-ec-rw-path'
4592 # since we are reading the image from a file. Compare with
4593 # testEntryArgsRequired()
4594 image = Image.FromFile(image_fname)
4595 self.assertEqual(orig_image.GetEntries().keys(),
4596 image.GetEntries().keys())
4597
Simon Glass6eb99322021-01-06 21:35:18 -07004598 def testFilesAlign(self):
4599 """Test alignment with files"""
4600 data = self._DoReadFile('190_files_align.dts')
4601
4602 # The first string is 15 bytes so will align to 16
4603 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4604 self.assertEqual(expect, data)
4605
Simon Glass5c6ba712021-01-06 21:35:19 -07004606 def testReadImageSkip(self):
4607 """Test reading an image and accessing its FDT map"""
4608 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004609 image_fname = tools.get_output_filename('image.bin')
Simon Glass5c6ba712021-01-06 21:35:19 -07004610 orig_image = control.images['image']
4611 image = Image.FromFile(image_fname)
4612 self.assertEqual(orig_image.GetEntries().keys(),
4613 image.GetEntries().keys())
4614
4615 orig_entry = orig_image.GetEntries()['fdtmap']
4616 entry = image.GetEntries()['fdtmap']
4617 self.assertEqual(orig_entry.offset, entry.offset)
4618 self.assertEqual(orig_entry.size, entry.size)
4619 self.assertEqual(16, entry.image_pos)
4620
4621 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4622
4623 self.assertEquals(U_BOOT_DATA, u_boot.ReadData())
4624
Simon Glass77a64e02021-03-18 20:24:57 +13004625 def testTplNoDtb(self):
4626 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
Simon Glass0fe44dc2021-04-25 08:39:32 +12004627 self._SetupTplElf()
Simon Glass77a64e02021-03-18 20:24:57 +13004628 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4629 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4630 data[:len(U_BOOT_TPL_NODTB_DATA)])
4631
Simon Glassd26efc82021-03-18 20:24:58 +13004632 def testTplBssPad(self):
4633 """Test that we can pad TPL's BSS with zeros"""
4634 # ELF file with a '__bss_size' symbol
4635 self._SetupTplElf()
4636 data = self._DoReadFile('193_tpl_bss_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004637 self.assertEqual(U_BOOT_TPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glassd26efc82021-03-18 20:24:58 +13004638 data)
4639
4640 def testTplBssPadMissing(self):
4641 """Test that a missing symbol is detected"""
4642 self._SetupTplElf('u_boot_ucode_ptr')
4643 with self.assertRaises(ValueError) as e:
4644 self._DoReadFile('193_tpl_bss_pad.dts')
4645 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4646 str(e.exception))
4647
Simon Glass06684922021-03-18 20:25:07 +13004648 def checkDtbSizes(self, data, pad_len, start):
4649 """Check the size arguments in a dtb embedded in an image
4650
4651 Args:
4652 data: The image data
4653 pad_len: Length of the pad section in the image, in bytes
4654 start: Start offset of the devicetree to examine, within the image
4655
4656 Returns:
4657 Size of the devicetree in bytes
4658 """
4659 dtb_data = data[start:]
4660 dtb = fdt.Fdt.FromData(dtb_data)
4661 fdt_size = dtb.GetFdtObj().totalsize()
4662 dtb.Scan()
4663 props = self._GetPropTree(dtb, 'size')
4664 self.assertEqual({
4665 'size': len(data),
4666 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4667 'u-boot-spl/u-boot-spl-dtb:size': 801,
4668 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4669 'u-boot-spl:size': 860,
4670 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4671 'u-boot/u-boot-dtb:size': 781,
4672 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4673 'u-boot:size': 827,
4674 }, props)
4675 return fdt_size
4676
4677 def testExpanded(self):
4678 """Test that an expanded entry type is selected when needed"""
4679 self._SetupSplElf()
4680 self._SetupTplElf()
4681
4682 # SPL has a devicetree, TPL does not
4683 entry_args = {
4684 'spl-dtb': '1',
4685 'spl-bss-pad': 'y',
4686 'tpl-dtb': '',
4687 }
4688 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4689 entry_args=entry_args)
4690 image = control.images['image']
4691 entries = image.GetEntries()
4692 self.assertEqual(3, len(entries))
4693
4694 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4695 self.assertIn('u-boot', entries)
4696 entry = entries['u-boot']
4697 self.assertEqual('u-boot-expanded', entry.etype)
4698 subent = entry.GetEntries()
4699 self.assertEqual(2, len(subent))
4700 self.assertIn('u-boot-nodtb', subent)
4701 self.assertIn('u-boot-dtb', subent)
4702
4703 # Second, u-boot-spl, which should be expanded into three parts
4704 self.assertIn('u-boot-spl', entries)
4705 entry = entries['u-boot-spl']
4706 self.assertEqual('u-boot-spl-expanded', entry.etype)
4707 subent = entry.GetEntries()
4708 self.assertEqual(3, len(subent))
4709 self.assertIn('u-boot-spl-nodtb', subent)
4710 self.assertIn('u-boot-spl-bss-pad', subent)
4711 self.assertIn('u-boot-spl-dtb', subent)
4712
4713 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4714 # devicetree
4715 self.assertIn('u-boot-tpl', entries)
4716 entry = entries['u-boot-tpl']
4717 self.assertEqual('u-boot-tpl', entry.etype)
4718 self.assertEqual(None, entry.GetEntries())
4719
4720 def testExpandedTpl(self):
4721 """Test that an expanded entry type is selected for TPL when needed"""
4722 self._SetupTplElf()
4723
4724 entry_args = {
4725 'tpl-bss-pad': 'y',
4726 'tpl-dtb': 'y',
4727 }
4728 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4729 entry_args=entry_args)
4730 image = control.images['image']
4731 entries = image.GetEntries()
4732 self.assertEqual(1, len(entries))
4733
4734 # We only have u-boot-tpl, which be expanded
4735 self.assertIn('u-boot-tpl', entries)
4736 entry = entries['u-boot-tpl']
4737 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4738 subent = entry.GetEntries()
4739 self.assertEqual(3, len(subent))
4740 self.assertIn('u-boot-tpl-nodtb', subent)
4741 self.assertIn('u-boot-tpl-bss-pad', subent)
4742 self.assertIn('u-boot-tpl-dtb', subent)
4743
4744 def testExpandedNoPad(self):
4745 """Test an expanded entry without BSS pad enabled"""
4746 self._SetupSplElf()
4747 self._SetupTplElf()
4748
4749 # SPL has a devicetree, TPL does not
4750 entry_args = {
4751 'spl-dtb': 'something',
4752 'spl-bss-pad': 'n',
4753 'tpl-dtb': '',
4754 }
4755 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4756 entry_args=entry_args)
4757 image = control.images['image']
4758 entries = image.GetEntries()
4759
4760 # Just check u-boot-spl, which should be expanded into two parts
4761 self.assertIn('u-boot-spl', entries)
4762 entry = entries['u-boot-spl']
4763 self.assertEqual('u-boot-spl-expanded', entry.etype)
4764 subent = entry.GetEntries()
4765 self.assertEqual(2, len(subent))
4766 self.assertIn('u-boot-spl-nodtb', subent)
4767 self.assertIn('u-boot-spl-dtb', subent)
4768
4769 def testExpandedTplNoPad(self):
4770 """Test that an expanded entry type with padding disabled in TPL"""
4771 self._SetupTplElf()
4772
4773 entry_args = {
4774 'tpl-bss-pad': '',
4775 'tpl-dtb': 'y',
4776 }
4777 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4778 entry_args=entry_args)
4779 image = control.images['image']
4780 entries = image.GetEntries()
4781 self.assertEqual(1, len(entries))
4782
4783 # We only have u-boot-tpl, which be expanded
4784 self.assertIn('u-boot-tpl', entries)
4785 entry = entries['u-boot-tpl']
4786 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4787 subent = entry.GetEntries()
4788 self.assertEqual(2, len(subent))
4789 self.assertIn('u-boot-tpl-nodtb', subent)
4790 self.assertIn('u-boot-tpl-dtb', subent)
4791
4792 def testFdtInclude(self):
4793 """Test that an Fdt is update within all binaries"""
4794 self._SetupSplElf()
4795 self._SetupTplElf()
4796
4797 # SPL has a devicetree, TPL does not
4798 self.maxDiff = None
4799 entry_args = {
4800 'spl-dtb': '1',
4801 'spl-bss-pad': 'y',
4802 'tpl-dtb': '',
4803 }
4804 # Build the image. It includes two separate devicetree binaries, each
4805 # with their own contents, but all contain the binman definition.
4806 data = self._DoReadFileDtb(
4807 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4808 update_dtb=True, entry_args=entry_args)[0]
4809 pad_len = 10
4810
4811 # Check the U-Boot dtb
4812 start = len(U_BOOT_NODTB_DATA)
4813 fdt_size = self.checkDtbSizes(data, pad_len, start)
4814
4815 # Now check SPL
4816 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4817 fdt_size = self.checkDtbSizes(data, pad_len, start)
4818
4819 # TPL has no devicetree
4820 start += fdt_size + len(U_BOOT_TPL_DATA)
4821 self.assertEqual(len(data), start)
Simon Glass7d398bb2020-10-26 17:40:14 -06004822
Simon Glass3d433382021-03-21 18:24:30 +13004823 def testSymbolsExpanded(self):
4824 """Test binman can assign symbols in expanded entries"""
4825 entry_args = {
4826 'spl-dtb': '1',
4827 }
4828 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4829 U_BOOT_SPL_DTB_DATA, 0x38,
4830 entry_args=entry_args, use_expanded=True)
4831
Simon Glass189f2912021-03-21 18:24:31 +13004832 def testCollection(self):
4833 """Test a collection"""
4834 data = self._DoReadFile('198_collection.dts')
4835 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
Simon Glassc1aa66e2022-01-29 14:14:04 -07004836 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
4837 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
Simon Glass189f2912021-03-21 18:24:31 +13004838 data)
4839
Simon Glass631f7522021-03-21 18:24:32 +13004840 def testCollectionSection(self):
4841 """Test a collection where a section must be built first"""
4842 # Sections never have their contents when GetData() is called, but when
Simon Glassd34bcdd2021-11-23 11:03:47 -07004843 # BuildSectionData() is called with required=True, a section will force
Simon Glass631f7522021-03-21 18:24:32 +13004844 # building the contents, producing an error is anything is still
4845 # missing.
4846 data = self._DoReadFile('199_collection_section.dts')
4847 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
Simon Glassc1aa66e2022-01-29 14:14:04 -07004848 self.assertEqual(section + U_BOOT_DATA + tools.get_bytes(0xff, 2) +
4849 section + tools.get_bytes(0xfe, 3) + U_BOOT_DATA,
Simon Glass631f7522021-03-21 18:24:32 +13004850 data)
4851
Simon Glass5ff9fed2021-03-21 18:24:33 +13004852 def testAlignDefault(self):
4853 """Test that default alignment works on sections"""
4854 data = self._DoReadFile('200_align_default.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004855 expected = (U_BOOT_DATA + tools.get_bytes(0, 8 - len(U_BOOT_DATA)) +
Simon Glass5ff9fed2021-03-21 18:24:33 +13004856 U_BOOT_DATA)
4857 # Special alignment for section
Simon Glassc1aa66e2022-01-29 14:14:04 -07004858 expected += tools.get_bytes(0, 32 - len(expected))
Simon Glass5ff9fed2021-03-21 18:24:33 +13004859 # No alignment within the nested section
4860 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
4861 # Now the final piece, which should be default-aligned
Simon Glassc1aa66e2022-01-29 14:14:04 -07004862 expected += tools.get_bytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
Simon Glass5ff9fed2021-03-21 18:24:33 +13004863 self.assertEqual(expected, data)
Simon Glass631f7522021-03-21 18:24:32 +13004864
Bin Meng4c4d6072021-05-10 20:23:33 +08004865 def testPackOpenSBI(self):
4866 """Test that an image with an OpenSBI binary can be created"""
4867 data = self._DoReadFile('201_opensbi.dts')
4868 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
4869
Simon Glassc69d19c2021-07-06 10:36:37 -06004870 def testSectionsSingleThread(self):
4871 """Test sections without multithreading"""
4872 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
Simon Glassc1aa66e2022-01-29 14:14:04 -07004873 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4874 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
4875 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glassc69d19c2021-07-06 10:36:37 -06004876 self.assertEqual(expected, data)
4877
4878 def testThreadTimeout(self):
4879 """Test handling a thread that takes too long"""
4880 with self.assertRaises(ValueError) as e:
4881 self._DoTestFile('202_section_timeout.dts',
4882 test_section_timeout=True)
Simon Glassb2dfe832021-10-18 12:13:15 -06004883 self.assertIn("Timed out obtaining contents", str(e.exception))
Simon Glassc69d19c2021-07-06 10:36:37 -06004884
Simon Glass03ebc202021-07-06 10:36:41 -06004885 def testTiming(self):
4886 """Test output of timing information"""
4887 data = self._DoReadFile('055_sections.dts')
4888 with test_util.capture_sys_output() as (stdout, stderr):
4889 state.TimingShow()
4890 self.assertIn('read:', stdout.getvalue())
4891 self.assertIn('compress:', stdout.getvalue())
4892
Simon Glass0427bed2021-11-03 21:09:18 -06004893 def testUpdateFdtInElf(self):
4894 """Test that we can update the devicetree in an ELF file"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02004895 if not elf.ELF_TOOLS:
4896 self.skipTest('Python elftools not available')
Simon Glass0427bed2021-11-03 21:09:18 -06004897 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4898 outfile = os.path.join(self._indir, 'u-boot.out')
4899 begin_sym = 'dtb_embed_begin'
4900 end_sym = 'dtb_embed_end'
4901 retcode = self._DoTestFile(
4902 '060_fdt_update.dts', update_dtb=True,
4903 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4904 self.assertEqual(0, retcode)
4905
4906 # Check that the output file does in fact contact a dtb with the binman
4907 # definition in the correct place
4908 syms = elf.GetSymbolFileOffset(infile,
4909 ['dtb_embed_begin', 'dtb_embed_end'])
Simon Glassc1aa66e2022-01-29 14:14:04 -07004910 data = tools.read_file(outfile)
Simon Glass0427bed2021-11-03 21:09:18 -06004911 dtb_data = data[syms['dtb_embed_begin'].offset:
4912 syms['dtb_embed_end'].offset]
4913
4914 dtb = fdt.Fdt.FromData(dtb_data)
4915 dtb.Scan()
4916 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4917 self.assertEqual({
4918 'image-pos': 0,
4919 'offset': 0,
4920 '_testing:offset': 32,
4921 '_testing:size': 2,
4922 '_testing:image-pos': 32,
4923 'section@0/u-boot:offset': 0,
4924 'section@0/u-boot:size': len(U_BOOT_DATA),
4925 'section@0/u-boot:image-pos': 0,
4926 'section@0:offset': 0,
4927 'section@0:size': 16,
4928 'section@0:image-pos': 0,
4929
4930 'section@1/u-boot:offset': 0,
4931 'section@1/u-boot:size': len(U_BOOT_DATA),
4932 'section@1/u-boot:image-pos': 16,
4933 'section@1:offset': 16,
4934 'section@1:size': 16,
4935 'section@1:image-pos': 16,
4936 'size': 40
4937 }, props)
4938
4939 def testUpdateFdtInElfInvalid(self):
4940 """Test that invalid args are detected with --update-fdt-in-elf"""
4941 with self.assertRaises(ValueError) as e:
4942 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
4943 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
4944 str(e.exception))
4945
4946 def testUpdateFdtInElfNoSyms(self):
4947 """Test that missing symbols are detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02004948 if not elf.ELF_TOOLS:
4949 self.skipTest('Python elftools not available')
Simon Glass0427bed2021-11-03 21:09:18 -06004950 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4951 outfile = ''
4952 begin_sym = 'wrong_begin'
4953 end_sym = 'wrong_end'
4954 with self.assertRaises(ValueError) as e:
4955 self._DoTestFile(
4956 '060_fdt_update.dts',
4957 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4958 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
4959 str(e.exception))
4960
4961 def testUpdateFdtInElfTooSmall(self):
4962 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02004963 if not elf.ELF_TOOLS:
4964 self.skipTest('Python elftools not available')
Simon Glass0427bed2021-11-03 21:09:18 -06004965 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
4966 outfile = os.path.join(self._indir, 'u-boot.out')
4967 begin_sym = 'dtb_embed_begin'
4968 end_sym = 'dtb_embed_end'
4969 with self.assertRaises(ValueError) as e:
4970 self._DoTestFile(
4971 '060_fdt_update.dts', update_dtb=True,
4972 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4973 self.assertRegex(
4974 str(e.exception),
4975 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
4976
Simon Glassc475dec2021-11-23 11:03:42 -07004977 def testVersion(self):
4978 """Test we can get the binman version"""
4979 version = '(unreleased)'
4980 self.assertEqual(version, state.GetVersion(self._indir))
4981
4982 with self.assertRaises(SystemExit):
4983 with test_util.capture_sys_output() as (_, stderr):
4984 self._DoBinman('-V')
4985 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
4986
4987 # Try running the tool too, just to be safe
4988 result = self._RunBinman('-V')
4989 self.assertEqual('Binman %s\n' % version, result.stderr)
4990
4991 # Set up a version file to make sure that works
4992 version = 'v2025.01-rc2'
Simon Glassc1aa66e2022-01-29 14:14:04 -07004993 tools.write_file(os.path.join(self._indir, 'version'), version,
Simon Glassc475dec2021-11-23 11:03:42 -07004994 binary=False)
4995 self.assertEqual(version, state.GetVersion(self._indir))
4996
Simon Glass943bf782021-11-23 21:09:50 -07004997 def testAltFormat(self):
4998 """Test that alternative formats can be used to extract"""
4999 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
5000
5001 try:
5002 tmpdir, updated_fname = self._SetupImageInTmpdir()
5003 with test_util.capture_sys_output() as (stdout, _):
5004 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
5005 self.assertEqual(
5006 '''Flag (-F) Entry type Description
5007fdt fdtmap Extract the devicetree blob from the fdtmap
5008''',
5009 stdout.getvalue())
5010
5011 dtb = os.path.join(tmpdir, 'fdt.dtb')
5012 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
5013 dtb, 'fdtmap')
5014
5015 # Check that we can read it and it can be scanning, meaning it does
5016 # not have a 16-byte fdtmap header
Simon Glassc1aa66e2022-01-29 14:14:04 -07005017 data = tools.read_file(dtb)
Simon Glass943bf782021-11-23 21:09:50 -07005018 dtb = fdt.Fdt.FromData(data)
5019 dtb.Scan()
5020
5021 # Now check u-boot which has no alt_format
5022 fname = os.path.join(tmpdir, 'fdt.dtb')
5023 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
5024 '-f', fname, 'u-boot')
Simon Glassc1aa66e2022-01-29 14:14:04 -07005025 data = tools.read_file(fname)
Simon Glass943bf782021-11-23 21:09:50 -07005026 self.assertEqual(U_BOOT_DATA, data)
5027
5028 finally:
5029 shutil.rmtree(tmpdir)
5030
Simon Glasscc2c5002021-11-23 21:09:52 -07005031 def testExtblobList(self):
5032 """Test an image with an external blob list"""
5033 data = self._DoReadFile('215_blob_ext_list.dts')
5034 self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
5035
5036 def testExtblobListMissing(self):
5037 """Test an image with a missing external blob"""
5038 with self.assertRaises(ValueError) as e:
5039 self._DoReadFile('216_blob_ext_list_missing.dts')
5040 self.assertIn("Filename 'missing-file' not found in input path",
5041 str(e.exception))
5042
5043 def testExtblobListMissingOk(self):
5044 """Test an image with an missing external blob that is allowed"""
5045 with test_util.capture_sys_output() as (stdout, stderr):
5046 self._DoTestFile('216_blob_ext_list_missing.dts',
5047 allow_missing=True)
5048 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07005049 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glasscc2c5002021-11-23 21:09:52 -07005050
Simon Glass75989722021-11-23 21:08:59 -07005051 def testFip(self):
5052 """Basic test of generation of an ARM Firmware Image Package (FIP)"""
5053 data = self._DoReadFile('203_fip.dts')
5054 hdr, fents = fip_util.decode_fip(data)
5055 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5056 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5057 self.assertEqual(0x123, hdr.flags)
5058
5059 self.assertEqual(2, len(fents))
5060
5061 fent = fents[0]
5062 self.assertEqual(
5063 bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
5064 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
5065 self.assertEqual('soc-fw', fent.fip_type)
5066 self.assertEqual(0x88, fent.offset)
5067 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5068 self.assertEqual(0x123456789abcdef, fent.flags)
5069 self.assertEqual(ATF_BL31_DATA, fent.data)
5070 self.assertEqual(True, fent.valid)
5071
5072 fent = fents[1]
5073 self.assertEqual(
5074 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
5075 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
5076 self.assertEqual('scp-fwu-cfg', fent.fip_type)
5077 self.assertEqual(0x8c, fent.offset)
5078 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5079 self.assertEqual(0, fent.flags)
5080 self.assertEqual(ATF_BL2U_DATA, fent.data)
5081 self.assertEqual(True, fent.valid)
5082
5083 def testFipOther(self):
5084 """Basic FIP with something that isn't a external blob"""
5085 data = self._DoReadFile('204_fip_other.dts')
5086 hdr, fents = fip_util.decode_fip(data)
5087
5088 self.assertEqual(2, len(fents))
5089 fent = fents[1]
5090 self.assertEqual('rot-cert', fent.fip_type)
5091 self.assertEqual(b'aa', fent.data)
5092
Simon Glass75989722021-11-23 21:08:59 -07005093 def testFipNoType(self):
5094 """FIP with an entry of an unknown type"""
5095 with self.assertRaises(ValueError) as e:
5096 self._DoReadFile('205_fip_no_type.dts')
5097 self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
5098 str(e.exception))
5099
5100 def testFipUuid(self):
5101 """Basic FIP with a manual uuid"""
5102 data = self._DoReadFile('206_fip_uuid.dts')
5103 hdr, fents = fip_util.decode_fip(data)
5104
5105 self.assertEqual(2, len(fents))
5106 fent = fents[1]
5107 self.assertEqual(None, fent.fip_type)
5108 self.assertEqual(
5109 bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
5110 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
5111 fent.uuid)
5112 self.assertEqual(U_BOOT_DATA, fent.data)
5113
5114 def testFipLs(self):
5115 """Test listing a FIP"""
5116 data = self._DoReadFileRealDtb('207_fip_ls.dts')
5117 hdr, fents = fip_util.decode_fip(data)
5118
5119 try:
5120 tmpdir, updated_fname = self._SetupImageInTmpdir()
5121 with test_util.capture_sys_output() as (stdout, stderr):
5122 self._DoBinman('ls', '-i', updated_fname)
5123 finally:
5124 shutil.rmtree(tmpdir)
5125 lines = stdout.getvalue().splitlines()
5126 expected = [
Simon Glass193d3db2023-02-07 14:34:18 -07005127'Name Image-pos Size Entry-type Offset Uncomp-size',
5128'--------------------------------------------------------------',
5129'image 0 2d3 section 0',
5130' atf-fip 0 90 atf-fip 0',
5131' soc-fw 88 4 blob-ext 88',
5132' u-boot 8c 4 u-boot 8c',
5133' fdtmap 90 243 fdtmap 90',
Simon Glass75989722021-11-23 21:08:59 -07005134]
5135 self.assertEqual(expected, lines)
5136
5137 image = control.images['image']
5138 entries = image.GetEntries()
5139 fdtmap = entries['fdtmap']
5140
5141 fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
5142 magic = fdtmap_data[:8]
5143 self.assertEqual(b'_FDTMAP_', magic)
Simon Glassc1aa66e2022-01-29 14:14:04 -07005144 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass75989722021-11-23 21:08:59 -07005145
5146 fdt_data = fdtmap_data[16:]
5147 dtb = fdt.Fdt.FromData(fdt_data)
5148 dtb.Scan()
5149 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
5150 self.assertEqual({
5151 'atf-fip/soc-fw:image-pos': 136,
5152 'atf-fip/soc-fw:offset': 136,
5153 'atf-fip/soc-fw:size': 4,
5154 'atf-fip/u-boot:image-pos': 140,
5155 'atf-fip/u-boot:offset': 140,
5156 'atf-fip/u-boot:size': 4,
5157 'atf-fip:image-pos': 0,
5158 'atf-fip:offset': 0,
5159 'atf-fip:size': 144,
5160 'image-pos': 0,
5161 'offset': 0,
5162 'fdtmap:image-pos': fdtmap.image_pos,
5163 'fdtmap:offset': fdtmap.offset,
5164 'fdtmap:size': len(fdtmap_data),
5165 'size': len(data),
5166 }, props)
5167
5168 def testFipExtractOneEntry(self):
5169 """Test extracting a single entry fron an FIP"""
5170 self._DoReadFileRealDtb('207_fip_ls.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07005171 image_fname = tools.get_output_filename('image.bin')
Simon Glass75989722021-11-23 21:08:59 -07005172 fname = os.path.join(self._indir, 'output.extact')
5173 control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
Simon Glassc1aa66e2022-01-29 14:14:04 -07005174 data = tools.read_file(fname)
Simon Glass75989722021-11-23 21:08:59 -07005175 self.assertEqual(U_BOOT_DATA, data)
5176
5177 def testFipReplace(self):
5178 """Test replacing a single file in a FIP"""
Simon Glassc1aa66e2022-01-29 14:14:04 -07005179 expected = U_BOOT_DATA + tools.get_bytes(0x78, 50)
Simon Glass75989722021-11-23 21:08:59 -07005180 data = self._DoReadFileRealDtb('208_fip_replace.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07005181 updated_fname = tools.get_output_filename('image-updated.bin')
5182 tools.write_file(updated_fname, data)
Simon Glass75989722021-11-23 21:08:59 -07005183 entry_name = 'atf-fip/u-boot'
5184 control.WriteEntry(updated_fname, entry_name, expected,
5185 allow_resize=True)
5186 actual = control.ReadEntry(updated_fname, entry_name)
5187 self.assertEqual(expected, actual)
5188
Simon Glassc1aa66e2022-01-29 14:14:04 -07005189 new_data = tools.read_file(updated_fname)
Simon Glass75989722021-11-23 21:08:59 -07005190 hdr, fents = fip_util.decode_fip(new_data)
5191
5192 self.assertEqual(2, len(fents))
5193
5194 # Check that the FIP entry is updated
5195 fent = fents[1]
5196 self.assertEqual(0x8c, fent.offset)
5197 self.assertEqual(len(expected), fent.size)
5198 self.assertEqual(0, fent.flags)
5199 self.assertEqual(expected, fent.data)
5200 self.assertEqual(True, fent.valid)
5201
5202 def testFipMissing(self):
5203 with test_util.capture_sys_output() as (stdout, stderr):
5204 self._DoTestFile('209_fip_missing.dts', allow_missing=True)
5205 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07005206 self.assertRegex(err, "Image 'image'.*missing.*: rmm-fw")
Simon Glass75989722021-11-23 21:08:59 -07005207
5208 def testFipSize(self):
5209 """Test a FIP with a size property"""
5210 data = self._DoReadFile('210_fip_size.dts')
5211 self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
5212 hdr, fents = fip_util.decode_fip(data)
5213 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5214 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5215
5216 self.assertEqual(1, len(fents))
5217
5218 fent = fents[0]
5219 self.assertEqual('soc-fw', fent.fip_type)
5220 self.assertEqual(0x60, fent.offset)
5221 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5222 self.assertEqual(ATF_BL31_DATA, fent.data)
5223 self.assertEqual(True, fent.valid)
5224
5225 rest = data[0x60 + len(ATF_BL31_DATA):0x100]
Simon Glassc1aa66e2022-01-29 14:14:04 -07005226 self.assertEqual(tools.get_bytes(0xff, len(rest)), rest)
Simon Glass75989722021-11-23 21:08:59 -07005227
5228 def testFipBadAlign(self):
5229 """Test that an invalid alignment value in a FIP is detected"""
5230 with self.assertRaises(ValueError) as e:
5231 self._DoTestFile('211_fip_bad_align.dts')
5232 self.assertIn(
5233 "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
5234 str(e.exception))
5235
5236 def testFipCollection(self):
5237 """Test using a FIP in a collection"""
5238 data = self._DoReadFile('212_fip_collection.dts')
5239 entry1 = control.images['image'].GetEntries()['collection']
5240 data1 = data[:entry1.size]
5241 hdr1, fents2 = fip_util.decode_fip(data1)
5242
5243 entry2 = control.images['image'].GetEntries()['atf-fip']
5244 data2 = data[entry2.offset:entry2.offset + entry2.size]
5245 hdr1, fents2 = fip_util.decode_fip(data2)
5246
5247 # The 'collection' entry should have U-Boot included at the end
5248 self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
5249 self.assertEqual(data1, data2 + U_BOOT_DATA)
5250 self.assertEqual(U_BOOT_DATA, data1[-4:])
5251
5252 # There should be a U-Boot after the final FIP
5253 self.assertEqual(U_BOOT_DATA, data[-4:])
Simon Glassc69d19c2021-07-06 10:36:37 -06005254
Simon Glass32d4f102022-01-12 13:10:35 -07005255 def testFakeBlob(self):
5256 """Test handling of faking an external blob"""
5257 with test_util.capture_sys_output() as (stdout, stderr):
5258 self._DoTestFile('217_fake_blob.dts', allow_missing=True,
5259 allow_fake_blobs=True)
5260 err = stderr.getvalue()
5261 self.assertRegex(
5262 err,
5263 "Image '.*' has faked external blobs and is non-functional: .*")
Simon Glass32d4f102022-01-12 13:10:35 -07005264
Simon Glassf4590e02022-01-09 20:13:46 -07005265 def testExtblobListFaked(self):
5266 """Test an extblob with missing external blob that are faked"""
5267 with test_util.capture_sys_output() as (stdout, stderr):
5268 self._DoTestFile('216_blob_ext_list_missing.dts',
5269 allow_fake_blobs=True)
5270 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07005271 self.assertRegex(err, "Image 'image'.*faked.*: blob-ext-list")
Simon Glassf4590e02022-01-09 20:13:46 -07005272
Simon Glass56ee85e2022-01-09 20:13:57 -07005273 def testListBintools(self):
5274 args = ['tool', '--list']
5275 with test_util.capture_sys_output() as (stdout, _):
5276 self._DoBinman(*args)
5277 out = stdout.getvalue().splitlines()
5278 self.assertTrue(len(out) >= 2)
5279
5280 def testFetchBintools(self):
5281 def fail_download(url):
Simon Glassc1aa66e2022-01-29 14:14:04 -07005282 """Take the tools.download() function by raising an exception"""
Simon Glass56ee85e2022-01-09 20:13:57 -07005283 raise urllib.error.URLError('my error')
5284
5285 args = ['tool']
5286 with self.assertRaises(ValueError) as e:
5287 self._DoBinman(*args)
5288 self.assertIn("Invalid arguments to 'tool' subcommand",
5289 str(e.exception))
5290
5291 args = ['tool', '--fetch']
5292 with self.assertRaises(ValueError) as e:
5293 self._DoBinman(*args)
5294 self.assertIn('Please specify bintools to fetch', str(e.exception))
5295
5296 args = ['tool', '--fetch', '_testing']
Simon Glassc1aa66e2022-01-29 14:14:04 -07005297 with unittest.mock.patch.object(tools, 'download',
Simon Glass56ee85e2022-01-09 20:13:57 -07005298 side_effect=fail_download):
5299 with test_util.capture_sys_output() as (stdout, _):
5300 self._DoBinman(*args)
5301 self.assertIn('failed to fetch with all methods', stdout.getvalue())
5302
Simon Glassbc570642022-01-09 20:14:11 -07005303 def testBintoolDocs(self):
5304 """Test for creation of bintool documentation"""
5305 with test_util.capture_sys_output() as (stdout, stderr):
5306 control.write_bintool_docs(control.bintool.Bintool.get_tool_list())
5307 self.assertTrue(len(stdout.getvalue()) > 0)
5308
5309 def testBintoolDocsMissing(self):
5310 """Test handling of missing bintool documentation"""
5311 with self.assertRaises(ValueError) as e:
5312 with test_util.capture_sys_output() as (stdout, stderr):
5313 control.write_bintool_docs(
5314 control.bintool.Bintool.get_tool_list(), 'mkimage')
5315 self.assertIn('Documentation is missing for modules: mkimage',
5316 str(e.exception))
5317
Jan Kiszkafcc87ef2022-01-28 20:37:53 +01005318 def testListWithGenNode(self):
5319 """Check handling of an FDT map when the section cannot be found"""
5320 entry_args = {
5321 'of-list': 'test-fdt1 test-fdt2',
5322 }
5323 data = self._DoReadFileDtb(
5324 '219_fit_gennode.dts',
5325 entry_args=entry_args,
5326 use_real_dtb=True,
5327 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])
5328
5329 try:
5330 tmpdir, updated_fname = self._SetupImageInTmpdir()
5331 with test_util.capture_sys_output() as (stdout, stderr):
5332 self._RunBinman('ls', '-i', updated_fname)
5333 finally:
5334 shutil.rmtree(tmpdir)
5335
Alper Nebi Yasaked293c32022-02-08 01:08:05 +03005336 def testFitSubentryUsesBintool(self):
5337 """Test that binman FIT subentries can use bintools"""
5338 command.test_result = self._HandleGbbCommand
5339 entry_args = {
5340 'keydir': 'devkeys',
5341 'bmpblk': 'bmpblk.bin',
5342 }
5343 data, _, _, _ = self._DoReadFileDtb('220_fit_subentry_bintool.dts',
5344 entry_args=entry_args)
5345
Alper Nebi Yasakf3078d42022-02-08 01:08:07 +03005346 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
5347 tools.get_bytes(0, 0x2180 - 16))
Alper Nebi Yasaked293c32022-02-08 01:08:05 +03005348 self.assertIn(expected, data)
5349
5350 def testFitSubentryMissingBintool(self):
5351 """Test that binman reports missing bintools for FIT subentries"""
5352 entry_args = {
5353 'keydir': 'devkeys',
5354 }
5355 with test_util.capture_sys_output() as (_, stderr):
5356 self._DoTestFile('220_fit_subentry_bintool.dts',
5357 force_missing_bintools='futility', entry_args=entry_args)
5358 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07005359 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass32d4f102022-01-12 13:10:35 -07005360
Alper Nebi Yasakee813c82022-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 Quadros47f420a2022-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 Glass6a0b5f82022-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 Glassce4e4022022-03-05 20:19:09 -07005405 self.assertIn("Node '/binman/fit': subnode 'images/@fdt-SEQ': Unknown operation 'unknown'",
Simon Glass6a0b5f82022-02-08 11:50:03 -07005406 str(exc.exception))
5407
Simon Glass80a66ae2022-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 Glass40c8bdd2022-03-05 20:19:12 -07005416 def testFitSplitElf(self):
5417 """Test an image with an FIT with an split-elf operation"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02005418 if not elf.ELF_TOOLS:
5419 self.skipTest('Python elftools not available')
Simon Glass40c8bdd2022-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 Karlman00b3d532023-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 Glass40c8bdd2022-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 Karlman00b3d532023-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 Glass40c8bdd2022-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 Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02005509 if not elf.ELF_TOOLS:
5510 self.skipTest('Python elftools not available')
Simon Glass40c8bdd2022-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 Glass40c8bdd2022-03-05 20:19:12 -07005528 def checkFitSplitElf(self, **kwargs):
Simon Glass7960a0a2022-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 Glass40c8bdd2022-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 Glass7960a0a2022-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 Glass40c8bdd2022-03-05 20:19:12 -07005553
Stefan Herbrechtsmeier5cb0b252022-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 Glass40c8bdd2022-03-05 20:19:12 -07005573 def testFitSplitElfMissing(self):
5574 """Test an split-elf FIT with a missing ELF file"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02005575 if not elf.ELF_TOOLS:
5576 self.skipTest('Python elftools not available')
Simon Glass7960a0a2022-08-07 09:46:46 -06005577 out, err = self.checkFitSplitElf(allow_missing=True)
Simon Glass40c8bdd2022-03-05 20:19:12 -07005578 self.assertRegex(
5579 err,
5580 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7960a0a2022-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 Glass40c8bdd2022-03-05 20:19:12 -07005584
5585 def testFitSplitElfFaked(self):
5586 """Test an split-elf FIT with faked ELF file"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02005587 if not elf.ELF_TOOLS:
5588 self.skipTest('Python elftools not available')
Simon Glass7960a0a2022-08-07 09:46:46 -06005589 out, err = self.checkFitSplitElf(allow_missing=True, allow_fake_blobs=True)
Simon Glass40c8bdd2022-03-05 20:19:12 -07005590 self.assertRegex(
5591 err,
5592 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7960a0a2022-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 Glass40c8bdd2022-03-05 20:19:12 -07005598
Stefan Herbrechtsmeier5cb0b252022-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 Reynesb1c50932022-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 Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005614 data, _, _, _ = self._DoReadFileDtb('230_pre_load.dts',
Philippe Reynesb1c50932022-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 Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005619 data = self._DoReadFile('230_pre_load.dts')
Philippe Reynesb1c50932022-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 Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005626 data = self._DoReadFile('231_pre_load_pkcs.dts')
Philippe Reynesb1c50932022-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 Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005633 data = self._DoReadFile('232_pre_load_pss.dts')
Philippe Reynesb1c50932022-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 Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005641 data = self._DoReadFile('233_pre_load_invalid_padding.dts')
Philippe Reynesb1c50932022-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 Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005646 data = self._DoReadFile('234_pre_load_invalid_sha.dts')
Philippe Reynesb1c50932022-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 Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005651 data = self._DoReadFile('235_pre_load_invalid_algo.dts')
Philippe Reynesb1c50932022-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 Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005656 data = self._DoReadFile('236_pre_load_invalid_key.dts')
Roger Quadros47f420a2022-02-19 20:50:04 +02005657
Alper Nebi Yasak67bf2c82022-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 Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005671 data = self._DoReadFileRealDtb('237_unique_names.dts')
Alper Nebi Yasak67bf2c82022-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 Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005681 data = self._DoReadFileRealDtb('238_unique_names_multi.dts')
Alper Nebi Yasak67bf2c82022-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 Yasak8ee4ec92022-03-27 18:31:45 +03005689 def testReplaceCmdWithBintool(self):
5690 """Test replacing an entry that needs a bintool to pack"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005691 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasak8ee4ec92022-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 Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005710 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasak8ee4ec92022-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 Yasake2ce4fb2022-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 Yasak74d3b232022-03-27 18:31:48 +03005748 def testExtractFit(self):
5749 """Test extracting a FIT section"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005750 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak74d3b232022-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 Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005769 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak74d3b232022-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 Yasak99283e52022-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 Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005788 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak99283e52022-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 Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005800 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak99283e52022-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 Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005814 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak99283e52022-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 Yasak82337bb2022-03-27 18:31:50 +03005821 def testReplaceSectionSimple(self):
Simon Glass7caa3722023-03-02 17:02:44 -07005822 """Test replacing a simple section with same-sized data"""
Alper Nebi Yasak82337bb2022-03-27 18:31:50 +03005823 new_data = b'w' * len(COMPRESS_DATA + U_BOOT_DATA)
Simon Glass7caa3722023-03-02 17:02:44 -07005824 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5825 new_data, dts='241_replace_section_simple.dts')
5826 self.assertEqual(new_data, data)
5827
5828 entries = image.GetEntries()
5829 self.assertIn('section', entries)
5830 entry = entries['section']
5831 self.assertEqual(len(new_data), entry.size)
5832
5833 def testReplaceSectionLarger(self):
5834 """Test replacing a simple section with larger data"""
5835 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
5836 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5837 new_data, dts='241_replace_section_simple.dts')
5838 self.assertEqual(new_data, data)
5839
5840 entries = image.GetEntries()
5841 self.assertIn('section', entries)
5842 entry = entries['section']
5843 self.assertEqual(len(new_data), entry.size)
5844 fentry = entries['fdtmap']
5845 self.assertEqual(entry.offset + entry.size, fentry.offset)
5846
5847 def testReplaceSectionSmaller(self):
5848 """Test replacing a simple section with smaller data"""
5849 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1) + b'\0'
5850 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5851 new_data, dts='241_replace_section_simple.dts')
5852 self.assertEqual(new_data, data)
5853
5854 # The new size is the same as the old, just with a pad byte at the end
5855 entries = image.GetEntries()
5856 self.assertIn('section', entries)
5857 entry = entries['section']
5858 self.assertEqual(len(new_data), entry.size)
5859
5860 def testReplaceSectionSmallerAllow(self):
5861 """Test failing to replace a simple section with smaller data"""
5862 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1)
5863 try:
5864 state.SetAllowEntryContraction(True)
5865 with self.assertRaises(ValueError) as exc:
5866 self._RunReplaceCmd('section', new_data,
5867 dts='241_replace_section_simple.dts')
5868 finally:
5869 state.SetAllowEntryContraction(False)
5870
5871 # Since we have no information about the position of things within the
5872 # section, we cannot adjust the position of /section-u-boot so it ends
5873 # up outside the section
Simon Glass73593e42022-08-13 11:40:46 -06005874 self.assertIn(
Simon Glass7caa3722023-03-02 17:02:44 -07005875 "Node '/section/u-boot': Offset 0x24 (36) size 0x4 (4) is outside "
5876 "the section '/section' starting at 0x0 (0) of size 0x27 (39)",
Simon Glass73593e42022-08-13 11:40:46 -06005877 str(exc.exception))
Alper Nebi Yasak82337bb2022-03-27 18:31:50 +03005878
Simon Glassdfe1db42022-08-13 11:40:48 -06005879 def testMkimageImagename(self):
5880 """Test using mkimage with -n holding the data too"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005881 data = self._DoReadFile('242_mkimage_name.dts')
Simon Glassdfe1db42022-08-13 11:40:48 -06005882
5883 # Check that the data appears in the file somewhere
5884 self.assertIn(U_BOOT_SPL_DATA, data)
5885
Simon Glassf3543e62022-09-06 20:26:52 -06005886 # Get struct legacy_img_hdr -> ih_name
Simon Glassdfe1db42022-08-13 11:40:48 -06005887 name = data[0x20:0x40]
5888
5889 # Build the filename that we expect to be placed in there, by virtue of
5890 # the -n paraameter
5891 expect = os.path.join(tools.get_output_dir(), 'mkimage.mkimage')
5892
5893 # Check that the image name is set to the temporary filename used
5894 self.assertEqual(expect.encode('utf-8')[:0x20], name)
5895
Simon Glass9db9e932022-08-13 11:40:49 -06005896 def testMkimageImage(self):
5897 """Test using mkimage with -n holding the data too"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005898 data = self._DoReadFile('243_mkimage_image.dts')
Simon Glass9db9e932022-08-13 11:40:49 -06005899
5900 # Check that the data appears in the file somewhere
5901 self.assertIn(U_BOOT_SPL_DATA, data)
5902
Simon Glassf3543e62022-09-06 20:26:52 -06005903 # Get struct legacy_img_hdr -> ih_name
Simon Glass9db9e932022-08-13 11:40:49 -06005904 name = data[0x20:0x40]
5905
5906 # Build the filename that we expect to be placed in there, by virtue of
5907 # the -n paraameter
5908 expect = os.path.join(tools.get_output_dir(), 'mkimage-n.mkimage')
5909
5910 # Check that the image name is set to the temporary filename used
5911 self.assertEqual(expect.encode('utf-8')[:0x20], name)
5912
5913 # Check the corect data is in the imagename file
5914 self.assertEqual(U_BOOT_DATA, tools.read_file(expect))
5915
5916 def testMkimageImageNoContent(self):
5917 """Test using mkimage with -n and no data"""
5918 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005919 self._DoReadFile('244_mkimage_image_no_content.dts')
Simon Glass9db9e932022-08-13 11:40:49 -06005920 self.assertIn('Could not complete processing of contents',
5921 str(exc.exception))
5922
5923 def testMkimageImageBad(self):
5924 """Test using mkimage with imagename node and data-to-imagename"""
5925 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005926 self._DoReadFile('245_mkimage_image_bad.dts')
Simon Glass9db9e932022-08-13 11:40:49 -06005927 self.assertIn('Cannot use both imagename node and data-to-imagename',
5928 str(exc.exception))
5929
Simon Glassd626e822022-08-13 11:40:50 -06005930 def testCollectionOther(self):
5931 """Test a collection where the data comes from another section"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005932 data = self._DoReadFile('246_collection_other.dts')
Simon Glassd626e822022-08-13 11:40:50 -06005933 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
5934 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
5935 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
5936 data)
5937
5938 def testMkimageCollection(self):
5939 """Test using a collection referring to an entry in a mkimage entry"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005940 data = self._DoReadFile('247_mkimage_coll.dts')
Simon Glassd626e822022-08-13 11:40:50 -06005941 expect = U_BOOT_SPL_DATA + U_BOOT_DATA
5942 self.assertEqual(expect, data[:len(expect)])
5943
Stefan Herbrechtsmeier6aa80002022-08-19 16:25:25 +02005944 def testCompressDtbPrependInvalid(self):
5945 """Test that invalid header is detected"""
5946 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005947 self._DoReadFileDtb('248_compress_dtb_prepend_invalid.dts')
Stefan Herbrechtsmeier6aa80002022-08-19 16:25:25 +02005948 self.assertIn("Node '/binman/u-boot-dtb': Invalid prepend in "
5949 "'u-boot-dtb': 'invalid'", str(e.exception))
5950
5951 def testCompressDtbPrependLength(self):
5952 """Test that compress with length header works as expected"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005953 data = self._DoReadFileRealDtb('249_compress_dtb_prepend_length.dts')
Stefan Herbrechtsmeier6aa80002022-08-19 16:25:25 +02005954 image = control.images['image']
5955 entries = image.GetEntries()
5956 self.assertIn('u-boot-dtb', entries)
5957 u_boot_dtb = entries['u-boot-dtb']
5958 self.assertIn('fdtmap', entries)
5959 fdtmap = entries['fdtmap']
5960
5961 image_fname = tools.get_output_filename('image.bin')
5962 orig = control.ReadEntry(image_fname, 'u-boot-dtb')
5963 dtb = fdt.Fdt.FromData(orig)
5964 dtb.Scan()
5965 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
5966 expected = {
5967 'u-boot:size': len(U_BOOT_DATA),
5968 'u-boot-dtb:uncomp-size': len(orig),
5969 'u-boot-dtb:size': u_boot_dtb.size,
5970 'fdtmap:size': fdtmap.size,
5971 'size': len(data),
5972 }
5973 self.assertEqual(expected, props)
5974
5975 # Check implementation
5976 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
5977 rest = data[len(U_BOOT_DATA):]
5978 comp_data_len = struct.unpack('<I', rest[:4])[0]
5979 comp_data = rest[4:4 + comp_data_len]
5980 orig2 = self._decompress(comp_data)
5981 self.assertEqual(orig, orig2)
5982
Stefan Herbrechtsmeierec7d27d2022-08-19 16:25:30 +02005983 def testInvalidCompress(self):
5984 """Test that invalid compress algorithm is detected"""
5985 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005986 self._DoTestFile('250_compress_dtb_invalid.dts')
Stefan Herbrechtsmeierec7d27d2022-08-19 16:25:30 +02005987 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
5988
Stefan Herbrechtsmeierda1af352022-08-19 16:25:32 +02005989 def testCompUtilCompressions(self):
5990 """Test compression algorithms"""
5991 for bintool in self.comp_bintools.values():
5992 self._CheckBintool(bintool)
5993 data = bintool.compress(COMPRESS_DATA)
5994 self.assertNotEqual(COMPRESS_DATA, data)
5995 orig = bintool.decompress(data)
5996 self.assertEquals(COMPRESS_DATA, orig)
5997
5998 def testCompUtilVersions(self):
5999 """Test tool version of compression algorithms"""
6000 for bintool in self.comp_bintools.values():
6001 self._CheckBintool(bintool)
6002 version = bintool.version()
6003 self.assertRegex(version, '^v?[0-9]+[0-9.]*')
6004
6005 def testCompUtilPadding(self):
6006 """Test padding of compression algorithms"""
Stefan Herbrechtsmeiercd15b642022-08-19 16:25:38 +02006007 # Skip zstd because it doesn't support padding
6008 for bintool in [v for k,v in self.comp_bintools.items() if k != 'zstd']:
Stefan Herbrechtsmeierda1af352022-08-19 16:25:32 +02006009 self._CheckBintool(bintool)
6010 data = bintool.compress(COMPRESS_DATA)
6011 self.assertNotEqual(COMPRESS_DATA, data)
6012 data += tools.get_bytes(0, 64)
6013 orig = bintool.decompress(data)
6014 self.assertEquals(COMPRESS_DATA, orig)
6015
Stefan Herbrechtsmeiercd15b642022-08-19 16:25:38 +02006016 def testCompressDtbZstd(self):
6017 """Test that zstd compress of device-tree files failed"""
6018 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02006019 self._DoTestFile('251_compress_dtb_zstd.dts')
Stefan Herbrechtsmeiercd15b642022-08-19 16:25:38 +02006020 self.assertIn("Node '/binman/u-boot-dtb': The zstd compression "
6021 "requires a length header", str(e.exception))
6022
Quentin Schulz4d91df02022-09-02 15:10:48 +02006023 def testMkimageMultipleDataFiles(self):
6024 """Test passing multiple files to mkimage in a mkimage entry"""
6025 data = self._DoReadFile('252_mkimage_mult_data.dts')
6026 # Size of files are packed in their 4B big-endian format
6027 expect = struct.pack('>I', len(U_BOOT_TPL_DATA))
6028 expect += struct.pack('>I', len(U_BOOT_SPL_DATA))
6029 # Size info is always followed by a 4B zero value.
6030 expect += tools.get_bytes(0, 4)
6031 expect += U_BOOT_TPL_DATA
6032 # All but last files are 4B-aligned
6033 align_pad = len(U_BOOT_TPL_DATA) % 4
6034 if align_pad:
6035 expect += tools.get_bytes(0, align_pad)
6036 expect += U_BOOT_SPL_DATA
6037 self.assertEqual(expect, data[-len(expect):])
6038
6039 def testMkimageMultipleNoContent(self):
6040 """Test passing multiple data files to mkimage with one data file having no content"""
6041 with self.assertRaises(ValueError) as exc:
6042 self._DoReadFile('253_mkimage_mult_no_content.dts')
6043 self.assertIn('Could not complete processing of contents',
6044 str(exc.exception))
6045
Quentin Schulz6cc29dc2022-09-02 15:10:49 +02006046 def testMkimageFilename(self):
6047 """Test using mkimage to build a binary with a filename"""
6048 retcode = self._DoTestFile('254_mkimage_filename.dts')
6049 self.assertEqual(0, retcode)
6050 fname = tools.get_output_filename('mkimage-test.bin')
6051 self.assertTrue(os.path.exists(fname))
6052
Simon Glass6ad24522022-02-28 07:16:54 -07006053 def testVpl(self):
6054 """Test that an image with VPL and its device tree can be created"""
6055 # ELF file with a '__bss_size' symbol
6056 self._SetupVplElf()
6057 data = self._DoReadFile('255_u_boot_vpl.dts')
6058 self.assertEqual(U_BOOT_VPL_DATA + U_BOOT_VPL_DTB_DATA, data)
6059
6060 def testVplNoDtb(self):
6061 """Test that an image with vpl/u-boot-vpl-nodtb.bin can be created"""
6062 self._SetupVplElf()
6063 data = self._DoReadFile('256_u_boot_vpl_nodtb.dts')
6064 self.assertEqual(U_BOOT_VPL_NODTB_DATA,
6065 data[:len(U_BOOT_VPL_NODTB_DATA)])
6066
6067 def testExpandedVpl(self):
6068 """Test that an expanded entry type is selected for TPL when needed"""
6069 self._SetupVplElf()
6070
6071 entry_args = {
6072 'vpl-bss-pad': 'y',
6073 'vpl-dtb': 'y',
6074 }
6075 self._DoReadFileDtb('257_fdt_incl_vpl.dts', use_expanded=True,
6076 entry_args=entry_args)
6077 image = control.images['image']
6078 entries = image.GetEntries()
6079 self.assertEqual(1, len(entries))
6080
6081 # We only have u-boot-vpl, which be expanded
6082 self.assertIn('u-boot-vpl', entries)
6083 entry = entries['u-boot-vpl']
6084 self.assertEqual('u-boot-vpl-expanded', entry.etype)
6085 subent = entry.GetEntries()
6086 self.assertEqual(3, len(subent))
6087 self.assertIn('u-boot-vpl-nodtb', subent)
6088 self.assertIn('u-boot-vpl-bss-pad', subent)
6089 self.assertIn('u-boot-vpl-dtb', subent)
6090
6091 def testVplBssPadMissing(self):
6092 """Test that a missing symbol is detected"""
6093 self._SetupVplElf('u_boot_ucode_ptr')
6094 with self.assertRaises(ValueError) as e:
6095 self._DoReadFile('258_vpl_bss_pad.dts')
6096 self.assertIn('Expected __bss_size symbol in vpl/u-boot-vpl',
6097 str(e.exception))
6098
Neha Malcom Francis3545e852022-10-17 16:36:25 +05306099 def testSymlink(self):
6100 """Test that image files can be named"""
6101 retcode = self._DoTestFile('259_symlink.dts', debug=True, map=True)
6102 self.assertEqual(0, retcode)
6103 image = control.images['test_image']
6104 fname = tools.get_output_filename('test_image.bin')
6105 sname = tools.get_output_filename('symlink_to_test.bin')
6106 self.assertTrue(os.path.islink(sname))
6107 self.assertEqual(os.readlink(sname), fname)
Alper Nebi Yasak8ee4ec92022-03-27 18:31:45 +03006108
Simon Glassd2afb9e2022-10-20 18:22:47 -06006109 def testSymbolsElf(self):
6110 """Test binman can assign symbols embedded in an ELF file"""
6111 if not elf.ELF_TOOLS:
6112 self.skipTest('Python elftools not available')
6113 self._SetupTplElf('u_boot_binman_syms')
6114 self._SetupVplElf('u_boot_binman_syms')
6115 self._SetupSplElf('u_boot_binman_syms')
6116 data = self._DoReadFileDtb('260_symbols_elf.dts')[0]
6117 image_fname = tools.get_output_filename('image.bin')
6118
6119 image = control.images['image']
6120 entries = image.GetEntries()
6121
6122 for entry in entries.values():
6123 # No symbols in u-boot and it has faked contents anyway
6124 if entry.name == 'u-boot':
6125 continue
6126 edata = data[entry.image_pos:entry.image_pos + entry.size]
6127 efname = tools.get_output_filename(f'edata-{entry.name}')
6128 tools.write_file(efname, edata)
6129
6130 syms = elf.GetSymbolFileOffset(efname, ['_binman_u_boot'])
6131 re_name = re.compile('_binman_(u_boot_(.*))_prop_(.*)')
6132 for name, sym in syms.items():
6133 msg = 'test'
6134 val = elf.GetSymbolValue(sym, edata, msg)
6135 entry_m = re_name.match(name)
6136 if entry_m:
6137 ename, prop = entry_m.group(1), entry_m.group(3)
6138 entry, entry_name, prop_name = image.LookupEntry(entries,
6139 name, msg)
6140 if prop_name == 'offset':
6141 expect_val = entry.offset
6142 elif prop_name == 'image_pos':
6143 expect_val = entry.image_pos
6144 elif prop_name == 'size':
6145 expect_val = entry.size
6146 self.assertEqual(expect_val, val)
6147
6148 def testSymbolsElfBad(self):
6149 """Check error when trying to write symbols without the elftools lib"""
6150 if not elf.ELF_TOOLS:
6151 self.skipTest('Python elftools not available')
6152 self._SetupTplElf('u_boot_binman_syms')
6153 self._SetupVplElf('u_boot_binman_syms')
6154 self._SetupSplElf('u_boot_binman_syms')
6155 try:
6156 elf.ELF_TOOLS = False
6157 with self.assertRaises(ValueError) as exc:
6158 self._DoReadFileDtb('260_symbols_elf.dts')
6159 finally:
6160 elf.ELF_TOOLS = True
6161 self.assertIn(
6162 "Section '/binman': entry '/binman/u-boot-spl-elf': "
6163 'Cannot write symbols to an ELF file without Python elftools',
6164 str(exc.exception))
6165
Simon Glassefddab62023-01-07 14:07:08 -07006166 def testSectionFilename(self):
6167 """Check writing of section contents to a file"""
6168 data = self._DoReadFile('261_section_fname.dts')
6169 expected = (b'&&' + U_BOOT_DATA + b'&&&' +
6170 tools.get_bytes(ord('!'), 7) +
6171 U_BOOT_DATA + tools.get_bytes(ord('&'), 12))
6172 self.assertEqual(expected, data)
6173
6174 sect_fname = tools.get_output_filename('outfile.bin')
6175 self.assertTrue(os.path.exists(sect_fname))
6176 sect_data = tools.read_file(sect_fname)
6177 self.assertEqual(U_BOOT_DATA, sect_data)
6178
Simon Glassc8c9f312023-01-07 14:07:12 -07006179 def testAbsent(self):
6180 """Check handling of absent entries"""
6181 data = self._DoReadFile('262_absent.dts')
6182 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6183
Simon Glass2f80c5e2023-01-07 14:07:14 -07006184 def testPackTeeOsOptional(self):
6185 """Test that an image with an optional TEE binary can be created"""
6186 entry_args = {
6187 'tee-os-path': 'tee.elf',
6188 }
6189 data = self._DoReadFileDtb('263_tee_os_opt.dts',
6190 entry_args=entry_args)[0]
6191 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6192
6193 def checkFitTee(self, dts, tee_fname):
6194 """Check that a tee-os entry works and returns data
6195
6196 Args:
6197 dts (str): Device tree filename to use
6198 tee_fname (str): filename containing tee-os
6199
6200 Returns:
6201 bytes: Image contents
6202 """
6203 if not elf.ELF_TOOLS:
6204 self.skipTest('Python elftools not available')
6205 entry_args = {
6206 'of-list': 'test-fdt1 test-fdt2',
6207 'default-dt': 'test-fdt2',
6208 'tee-os-path': tee_fname,
6209 }
6210 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
6211 data = self._DoReadFileDtb(dts, entry_args=entry_args,
6212 extra_indirs=[test_subdir])[0]
6213 return data
6214
6215 def testFitTeeOsOptionalFit(self):
6216 """Test an image with a FIT with an optional OP-TEE binary"""
6217 data = self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bin')
6218
6219 # There should be only one node, holding the data set up in SetUpClass()
6220 # for tee.bin
6221 dtb = fdt.Fdt.FromData(data)
6222 dtb.Scan()
6223 node = dtb.GetNode('/images/tee-1')
6224 self.assertEqual(TEE_ADDR,
6225 fdt_util.fdt32_to_cpu(node.props['load'].value))
6226 self.assertEqual(TEE_ADDR,
6227 fdt_util.fdt32_to_cpu(node.props['entry'].value))
6228 self.assertEqual(U_BOOT_DATA, node.props['data'].bytes)
6229
6230 def testFitTeeOsOptionalFitBad(self):
6231 """Test an image with a FIT with an optional OP-TEE binary"""
6232 with self.assertRaises(ValueError) as exc:
6233 self.checkFitTee('265_tee_os_opt_fit_bad.dts', 'tee.bin')
6234 self.assertIn(
6235 "Node '/binman/fit': subnode 'images/@tee-SEQ': Failed to read ELF file: Magic number does not match",
6236 str(exc.exception))
6237
6238 def testFitTeeOsBad(self):
6239 """Test an OP-TEE binary with wrong formats"""
6240 self.make_tee_bin('tee.bad1', 123)
6241 with self.assertRaises(ValueError) as exc:
6242 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad1')
6243 self.assertIn(
6244 "Node '/binman/fit/images/@tee-SEQ/tee-os': OP-TEE paged mode not supported",
6245 str(exc.exception))
6246
6247 self.make_tee_bin('tee.bad2', 0, b'extra data')
6248 with self.assertRaises(ValueError) as exc:
6249 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad2')
6250 self.assertIn(
6251 "Node '/binman/fit/images/@tee-SEQ/tee-os': Invalid OP-TEE file: size mismatch (expected 0x4, have 0xe)",
6252 str(exc.exception))
6253
Simon Glass67a05012023-01-07 14:07:15 -07006254 def testExtblobOptional(self):
6255 """Test an image with an external blob that is optional"""
6256 with test_util.capture_sys_output() as (stdout, stderr):
6257 data = self._DoReadFile('266_blob_ext_opt.dts')
6258 self.assertEqual(REFCODE_DATA, data)
6259 err = stderr.getvalue()
6260 self.assertRegex(
6261 err,
6262 "Image '.*' is missing external blobs but is still functional: missing")
6263
Simon Glass0b079fc2023-01-11 16:10:12 -07006264 def testSectionInner(self):
6265 """Test an inner section with a size"""
6266 data = self._DoReadFile('267_section_inner.dts')
6267 expected = U_BOOT_DATA + tools.get_bytes(0, 12)
6268 self.assertEqual(expected, data)
6269
Simon Glass62ef2f72023-01-11 16:10:14 -07006270 def testNull(self):
6271 """Test an image with a null entry"""
6272 data = self._DoReadFile('268_null.dts')
6273 self.assertEqual(U_BOOT_DATA + b'\xff\xff\xff\xff' + U_BOOT_IMG_DATA, data)
6274
Simon Glass9766f692023-01-11 16:10:16 -07006275 def testOverlap(self):
6276 """Test an image with a overlapping entry"""
6277 data = self._DoReadFile('269_overlap.dts')
6278 self.assertEqual(U_BOOT_DATA[:1] + b'aa' + U_BOOT_DATA[3:], data)
6279
6280 image = control.images['image']
6281 entries = image.GetEntries()
6282
6283 self.assertIn('inset', entries)
6284 inset = entries['inset']
6285 self.assertEqual(1, inset.offset);
6286 self.assertEqual(1, inset.image_pos);
6287 self.assertEqual(2, inset.size);
6288
6289 def testOverlapNull(self):
6290 """Test an image with a null overlap"""
6291 data = self._DoReadFile('270_overlap_null.dts')
6292 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6293
6294 # Check the FMAP
6295 fhdr, fentries = fmap_util.DecodeFmap(data[len(U_BOOT_DATA):])
6296 self.assertEqual(4, fhdr.nareas)
6297 fiter = iter(fentries)
6298
6299 fentry = next(fiter)
6300 self.assertEqual(b'SECTION', fentry.name)
6301 self.assertEqual(0, fentry.offset)
6302 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6303 self.assertEqual(0, fentry.flags)
6304
6305 fentry = next(fiter)
6306 self.assertEqual(b'U_BOOT', fentry.name)
6307 self.assertEqual(0, fentry.offset)
6308 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6309 self.assertEqual(0, fentry.flags)
6310
6311 # Make sure that the NULL entry appears in the FMAP
6312 fentry = next(fiter)
6313 self.assertEqual(b'NULL', fentry.name)
6314 self.assertEqual(1, fentry.offset)
6315 self.assertEqual(2, fentry.size)
6316 self.assertEqual(0, fentry.flags)
6317
6318 fentry = next(fiter)
6319 self.assertEqual(b'FMAP', fentry.name)
6320 self.assertEqual(len(U_BOOT_DATA), fentry.offset)
6321
6322 def testOverlapBad(self):
6323 """Test an image with a bad overlapping entry"""
6324 with self.assertRaises(ValueError) as exc:
6325 self._DoReadFile('271_overlap_bad.dts')
6326 self.assertIn(
6327 "Node '/binman/inset': Offset 0x10 (16) ending at 0x12 (18) must overlap with existing entries",
6328 str(exc.exception))
6329
6330 def testOverlapNoOffset(self):
6331 """Test an image with a bad overlapping entry"""
6332 with self.assertRaises(ValueError) as exc:
6333 self._DoReadFile('272_overlap_no_size.dts')
6334 self.assertIn(
6335 "Node '/binman/inset': 'fill' entry is missing properties: size",
6336 str(exc.exception))
6337
Simon Glassc1157862023-01-11 16:10:17 -07006338 def testBlobSymbol(self):
6339 """Test a blob with symbols read from an ELF file"""
6340 elf_fname = self.ElfTestFile('blob_syms')
6341 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6342 TestFunctional._MakeInputFile('blob_syms.bin',
6343 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6344
6345 data = self._DoReadFile('273_blob_symbol.dts')
6346
6347 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6348 addr = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6349 self.assertEqual(syms['_binman_sym_magic'].address, addr)
6350 self.assertEqual(syms['_binman_inset_prop_offset'].address, addr + 4)
6351 self.assertEqual(syms['_binman_inset_prop_size'].address, addr + 8)
6352
6353 sym_values = struct.pack('<LLL', elf.BINMAN_SYM_MAGIC_VALUE, 4, 8)
6354 expected = sym_values
6355 self.assertEqual(expected, data[:len(expected)])
6356
Simon Glass571bc4e2023-01-11 16:10:19 -07006357 def testOffsetFromElf(self):
6358 """Test a blob with symbols read from an ELF file"""
6359 elf_fname = self.ElfTestFile('blob_syms')
6360 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6361 TestFunctional._MakeInputFile('blob_syms.bin',
6362 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6363
6364 data = self._DoReadFile('274_offset_from_elf.dts')
6365
6366 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6367 base = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6368
6369 image = control.images['image']
6370 entries = image.GetEntries()
6371
6372 self.assertIn('inset', entries)
6373 inset = entries['inset']
6374
6375 self.assertEqual(base + 4, inset.offset);
6376 self.assertEqual(base + 4, inset.image_pos);
6377 self.assertEqual(4, inset.size);
6378
6379 self.assertIn('inset2', entries)
6380 inset = entries['inset2']
6381 self.assertEqual(base + 8, inset.offset);
6382 self.assertEqual(base + 8, inset.image_pos);
6383 self.assertEqual(4, inset.size);
6384
Jonas Karlman9b2fd2d2023-01-21 19:01:39 +00006385 def testFitAlign(self):
6386 """Test an image with an FIT with aligned external data"""
6387 data = self._DoReadFile('275_fit_align.dts')
6388 self.assertEqual(4096, len(data))
6389
6390 dtb = fdt.Fdt.FromData(data)
6391 dtb.Scan()
6392
6393 props = self._GetPropTree(dtb, ['data-position'])
6394 expected = {
6395 'u-boot:data-position': 1024,
6396 'fdt-1:data-position': 2048,
6397 'fdt-2:data-position': 3072,
6398 }
6399 self.assertEqual(expected, props)
6400
Jonas Karlmanf584d442023-01-21 19:02:12 +00006401 def testFitFirmwareLoadables(self):
6402 """Test an image with an FIT that use fit,firmware"""
6403 if not elf.ELF_TOOLS:
6404 self.skipTest('Python elftools not available')
6405 entry_args = {
6406 'of-list': 'test-fdt1',
6407 'default-dt': 'test-fdt1',
6408 'atf-bl31-path': 'bl31.elf',
6409 'tee-os-path': 'missing.bin',
6410 }
6411 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
Simon Glass7c4027a2023-02-23 18:18:01 -07006412 with test_util.capture_sys_output() as (stdout, stderr):
6413 data = self._DoReadFileDtb(
6414 '276_fit_firmware_loadables.dts',
6415 entry_args=entry_args,
6416 extra_indirs=[test_subdir])[0]
Jonas Karlmanf584d442023-01-21 19:02:12 +00006417
6418 dtb = fdt.Fdt.FromData(data)
6419 dtb.Scan()
6420
6421 node = dtb.GetNode('/configurations/conf-uboot-1')
6422 self.assertEqual('u-boot', node.props['firmware'].value)
6423 self.assertEqual(['atf-1', 'atf-2'],
6424 fdt_util.GetStringList(node, 'loadables'))
6425
6426 node = dtb.GetNode('/configurations/conf-atf-1')
6427 self.assertEqual('atf-1', node.props['firmware'].value)
6428 self.assertEqual(['u-boot', 'atf-2'],
6429 fdt_util.GetStringList(node, 'loadables'))
6430
6431 node = dtb.GetNode('/configurations/conf-missing-uboot-1')
6432 self.assertEqual('u-boot', node.props['firmware'].value)
6433 self.assertEqual(['atf-1', 'atf-2'],
6434 fdt_util.GetStringList(node, 'loadables'))
6435
6436 node = dtb.GetNode('/configurations/conf-missing-atf-1')
6437 self.assertEqual('atf-1', node.props['firmware'].value)
6438 self.assertEqual(['u-boot', 'atf-2'],
6439 fdt_util.GetStringList(node, 'loadables'))
6440
6441 node = dtb.GetNode('/configurations/conf-missing-tee-1')
6442 self.assertEqual('atf-1', node.props['firmware'].value)
6443 self.assertEqual(['u-boot', 'atf-2'],
6444 fdt_util.GetStringList(node, 'loadables'))
6445
Simon Glassfe7e9242023-02-22 12:14:49 -07006446 def testTooldir(self):
6447 """Test that we can specify the tooldir"""
6448 with test_util.capture_sys_output() as (stdout, stderr):
6449 self.assertEqual(0, self._DoBinman('--tooldir', 'fred',
6450 'tool', '-l'))
6451 self.assertEqual('fred', bintool.Bintool.tooldir)
6452
6453 # Check that the toolpath is updated correctly
6454 self.assertEqual(['fred'], tools.tool_search_paths)
6455
6456 # Try with a few toolpaths; the tooldir should be at the end
6457 with test_util.capture_sys_output() as (stdout, stderr):
6458 self.assertEqual(0, self._DoBinman(
6459 '--toolpath', 'mary', '--toolpath', 'anna', '--tooldir', 'fred',
6460 'tool', '-l'))
6461 self.assertEqual(['mary', 'anna', 'fred'], tools.tool_search_paths)
6462
Simon Glass7caa3722023-03-02 17:02:44 -07006463 def testReplaceSectionEntry(self):
6464 """Test replacing an entry in a section"""
6465 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6466 entry_data, expected_fdtmap, image = self._RunReplaceCmd('section/blob',
6467 expect_data, dts='241_replace_section_simple.dts')
6468 self.assertEqual(expect_data, entry_data)
6469
6470 entries = image.GetEntries()
6471 self.assertIn('section', entries)
6472 section = entries['section']
6473
6474 sect_entries = section.GetEntries()
6475 self.assertIn('blob', sect_entries)
6476 entry = sect_entries['blob']
6477 self.assertEqual(len(expect_data), entry.size)
6478
6479 fname = tools.get_output_filename('image-updated.bin')
6480 data = tools.read_file(fname)
6481
6482 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6483 self.assertEqual(expect_data, new_blob_data)
6484
6485 self.assertEqual(U_BOOT_DATA,
6486 data[entry.image_pos + len(expect_data):]
6487 [:len(U_BOOT_DATA)])
6488
6489 def testReplaceSectionDeep(self):
6490 """Test replacing an entry in two levels of sections"""
6491 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6492 entry_data, expected_fdtmap, image = self._RunReplaceCmd(
6493 'section/section/blob', expect_data,
6494 dts='278_replace_section_deep.dts')
6495 self.assertEqual(expect_data, entry_data)
6496
6497 entries = image.GetEntries()
6498 self.assertIn('section', entries)
6499 section = entries['section']
6500
6501 subentries = section.GetEntries()
6502 self.assertIn('section', subentries)
6503 section = subentries['section']
6504
6505 sect_entries = section.GetEntries()
6506 self.assertIn('blob', sect_entries)
6507 entry = sect_entries['blob']
6508 self.assertEqual(len(expect_data), entry.size)
6509
6510 fname = tools.get_output_filename('image-updated.bin')
6511 data = tools.read_file(fname)
6512
6513 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6514 self.assertEqual(expect_data, new_blob_data)
6515
6516 self.assertEqual(U_BOOT_DATA,
6517 data[entry.image_pos + len(expect_data):]
6518 [:len(U_BOOT_DATA)])
6519
6520 def testReplaceFitSibling(self):
6521 """Test an image with a FIT inside where we replace its sibling"""
6522 fname = TestFunctional._MakeInputFile('once', b'available once')
6523 self._DoReadFileRealDtb('277_replace_fit_sibling.dts')
6524 os.remove(fname)
6525
6526 try:
6527 tmpdir, updated_fname = self._SetupImageInTmpdir()
6528
6529 fname = os.path.join(tmpdir, 'update-blob')
6530 expected = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
6531 tools.write_file(fname, expected)
6532
6533 self._DoBinman('replace', '-i', updated_fname, 'blob', '-f', fname)
6534 data = tools.read_file(updated_fname)
6535 start = len(U_BOOT_DTB_DATA)
6536 self.assertEqual(expected, data[start:start + len(expected)])
6537 map_fname = os.path.join(tmpdir, 'image-updated.map')
6538 self.assertFalse(os.path.exists(map_fname))
6539 finally:
6540 shutil.rmtree(tmpdir)
6541
Simon Glassefddab62023-01-07 14:07:08 -07006542
Simon Glass9fc60b42017-11-12 21:52:22 -07006543if __name__ == "__main__":
6544 unittest.main()