blob: 6b203dfb644f906064f19c7b06999114ad63bd3c [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 Glassbf776672020-04-17 18:09:04 -060037from patman import command
38from patman import test_util
39from patman import tools
40from patman 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 Glass3b0c3822018-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 Glass3b0c3822018-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 Glass3b0c3822018-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 Glass3b0c3822018-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 Glass3b0c3822018-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 Glass3b0c3822018-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 Glass3b0c3822018-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
150600000000 00000000 00000028 main-section
150700000000 00000000 00000010 section@0
150800000000 00000000 00000004 u-boot
150900000010 00000010 00000010 section@1
151000000010 00000000 00000004 u-boot
151100000020 00000020 00000004 section@2
151200000020 00000000 00000004 u-boot
Simon Glass3b0c3822018-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
151900000000 00000000 00000028 main-section
152000000000 00000000 00000010 section@0
152100000000 00000000 00000004 ro-u-boot
152200000010 00000010 00000010 section@1
152300000010 00000000 00000004 rw-u-boot
Simon 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)
1705 self.assertEqual(0, fentry.flags)
1706
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"""
1753 if pipe_list[0][0] == 'futility':
1754 fname = pipe_list[0][-1]
1755 # Append our GBB data to the file, which will happen every time the
1756 # futility command is called.
Simon 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()
1798 self.assertRegex(err,
1799 "Image 'main-section'.*missing bintools.*: futility")
1800
Simon Glass24d0d3c2018-07-17 13:25:47 -06001801 def _HandleVblockCommand(self, pipe_list):
Simon Glass5af9ebc2021-01-06 21:35:17 -07001802 """Fake calls to the futility utility
1803
1804 The expected pipe is:
1805
1806 [('futility', 'vbutil_firmware', '--vblock',
1807 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1808 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1809 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1810 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1811
1812 This writes to the output file (here, 'vblock.vblock'). If
1813 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1814 of the input data (here, 'input.vblock').
1815 """
Simon Glass24d0d3c2018-07-17 13:25:47 -06001816 if pipe_list[0][0] == 'futility':
1817 fname = pipe_list[0][3]
Simon Glassa326b492018-09-14 04:57:11 -06001818 with open(fname, 'wb') as fd:
Simon Glass5af9ebc2021-01-06 21:35:17 -07001819 if self._hash_data:
1820 infile = pipe_list[0][11]
1821 m = hashlib.sha256()
Simon Glassc1aa66e2022-01-29 14:14:04 -07001822 data = tools.read_file(infile)
Simon Glass5af9ebc2021-01-06 21:35:17 -07001823 m.update(data)
1824 fd.write(m.digest())
1825 else:
1826 fd.write(VBLOCK_DATA)
1827
Simon Glass24d0d3c2018-07-17 13:25:47 -06001828 return command.CommandResult()
1829
1830 def testVblock(self):
1831 """Test for the Chromium OS Verified Boot Block"""
Simon Glass5af9ebc2021-01-06 21:35:17 -07001832 self._hash_data = False
Simon Glass24d0d3c2018-07-17 13:25:47 -06001833 command.test_result = self._HandleVblockCommand
1834 entry_args = {
1835 'keydir': 'devkeys',
1836 }
Simon Glass741f2d62018-10-01 12:22:30 -06001837 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass24d0d3c2018-07-17 13:25:47 -06001838 entry_args=entry_args)
1839 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1840 self.assertEqual(expected, data)
1841
1842 def testVblockNoContent(self):
1843 """Test we detect a vblock which has no content to sign"""
1844 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001845 self._DoReadFile('075_vblock_no_content.dts')
Simon Glass189f2912021-03-21 18:24:31 +13001846 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
Simon Glass24d0d3c2018-07-17 13:25:47 -06001847 'property', str(e.exception))
1848
1849 def testVblockBadPhandle(self):
1850 """Test that we detect a vblock with an invalid phandle in contents"""
1851 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001852 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001853 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1854 '1000', str(e.exception))
1855
1856 def testVblockBadEntry(self):
1857 """Test that we detect an entry that points to a non-entry"""
1858 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001859 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001860 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1861 "'other'", str(e.exception))
1862
Simon Glass5af9ebc2021-01-06 21:35:17 -07001863 def testVblockContent(self):
1864 """Test that the vblock signs the right data"""
1865 self._hash_data = True
1866 command.test_result = self._HandleVblockCommand
1867 entry_args = {
1868 'keydir': 'devkeys',
1869 }
1870 data = self._DoReadFileDtb(
1871 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1872 entry_args=entry_args)[0]
1873 hashlen = 32 # SHA256 hash is 32 bytes
1874 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1875 hashval = data[-hashlen:]
1876 dtb = data[len(U_BOOT_DATA):-hashlen]
1877
1878 expected_data = U_BOOT_DATA + dtb
1879
1880 # The hashval should be a hash of the dtb
1881 m = hashlib.sha256()
1882 m.update(expected_data)
1883 expected_hashval = m.digest()
1884 self.assertEqual(expected_hashval, hashval)
1885
Simon Glass4f9ee832022-01-09 20:14:09 -07001886 def testVblockMissing(self):
1887 """Test that binman still produces an image if futility is missing"""
1888 entry_args = {
1889 'keydir': 'devkeys',
1890 }
1891 with test_util.capture_sys_output() as (_, stderr):
1892 self._DoTestFile('074_vblock.dts',
1893 force_missing_bintools='futility',
1894 entry_args=entry_args)
1895 err = stderr.getvalue()
1896 self.assertRegex(err,
1897 "Image 'main-section'.*missing bintools.*: futility")
1898
Simon Glassb8ef5b62018-07-17 13:25:48 -06001899 def testTpl(self):
Simon Glass2090f1e2019-08-24 07:23:00 -06001900 """Test that an image with TPL and its device tree can be created"""
Simon Glassb8ef5b62018-07-17 13:25:48 -06001901 # ELF file with a '__bss_size' symbol
Simon Glass2090f1e2019-08-24 07:23:00 -06001902 self._SetupTplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001903 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glassb8ef5b62018-07-17 13:25:48 -06001904 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1905
Simon Glass15a587c2018-07-17 13:25:51 -06001906 def testUsesPos(self):
1907 """Test that the 'pos' property cannot be used anymore"""
1908 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001909 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass15a587c2018-07-17 13:25:51 -06001910 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1911 "'pos'", str(e.exception))
1912
Simon Glassd178eab2018-09-14 04:57:08 -06001913 def testFillZero(self):
1914 """Test for an fill entry type with a size of 0"""
Simon Glass741f2d62018-10-01 12:22:30 -06001915 data = self._DoReadFile('080_fill_empty.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001916 self.assertEqual(tools.get_bytes(0, 16), data)
Simon Glassd178eab2018-09-14 04:57:08 -06001917
Simon Glass0b489362018-09-14 04:57:09 -06001918 def testTextMissing(self):
1919 """Test for a text entry type where there is no text"""
1920 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001921 self._DoReadFileDtb('066_text.dts',)
Simon Glass0b489362018-09-14 04:57:09 -06001922 self.assertIn("Node '/binman/text': No value provided for text label "
1923 "'test-id'", str(e.exception))
1924
Simon Glass35b384c2018-09-14 04:57:10 -06001925 def testPackStart16Tpl(self):
1926 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001927 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glass35b384c2018-09-14 04:57:10 -06001928 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1929
Simon Glass0bfa7b02018-09-14 04:57:12 -06001930 def testSelectImage(self):
1931 """Test that we can select which images to build"""
Simon Glasseb833d82019-04-25 21:58:34 -06001932 expected = 'Skipping images: image1'
Simon Glass0bfa7b02018-09-14 04:57:12 -06001933
Simon Glasseb833d82019-04-25 21:58:34 -06001934 # We should only get the expected message in verbose mode
Simon Glassee0c9a72019-07-08 13:18:48 -06001935 for verbosity in (0, 2):
Simon Glasseb833d82019-04-25 21:58:34 -06001936 with test_util.capture_sys_output() as (stdout, stderr):
1937 retcode = self._DoTestFile('006_dual_image.dts',
1938 verbosity=verbosity,
1939 images=['image2'])
1940 self.assertEqual(0, retcode)
1941 if verbosity:
1942 self.assertIn(expected, stdout.getvalue())
1943 else:
1944 self.assertNotIn(expected, stdout.getvalue())
1945
Simon Glassc1aa66e2022-01-29 14:14:04 -07001946 self.assertFalse(os.path.exists(tools.get_output_filename('image1.bin')))
1947 self.assertTrue(os.path.exists(tools.get_output_filename('image2.bin')))
Simon Glassf86a7362019-07-20 12:24:10 -06001948 self._CleanupOutputDir()
Simon Glass0bfa7b02018-09-14 04:57:12 -06001949
Simon Glass6ed45ba2018-09-14 04:57:24 -06001950 def testUpdateFdtAll(self):
1951 """Test that all device trees are updated with offset/size info"""
Simon Glass3c081312019-07-08 14:25:26 -06001952 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glass6ed45ba2018-09-14 04:57:24 -06001953
1954 base_expected = {
Simon Glass6ed45ba2018-09-14 04:57:24 -06001955 'offset': 0,
Simon Glass6ad24522022-02-28 07:16:54 -07001956 'image-pos': 0,
1957 'size': 2320,
Simon Glass6ed45ba2018-09-14 04:57:24 -06001958 'section:offset': 0,
Simon Glass6ad24522022-02-28 07:16:54 -07001959 'section:image-pos': 0,
1960 'section:size': 565,
1961 'section/u-boot-dtb:offset': 0,
1962 'section/u-boot-dtb:image-pos': 0,
1963 'section/u-boot-dtb:size': 565,
1964 'u-boot-spl-dtb:offset': 565,
1965 'u-boot-spl-dtb:image-pos': 565,
1966 'u-boot-spl-dtb:size': 585,
1967 'u-boot-tpl-dtb:offset': 1150,
1968 'u-boot-tpl-dtb:image-pos': 1150,
1969 'u-boot-tpl-dtb:size': 585,
1970 'u-boot-vpl-dtb:image-pos': 1735,
1971 'u-boot-vpl-dtb:offset': 1735,
1972 'u-boot-vpl-dtb:size': 585,
Simon Glass6ed45ba2018-09-14 04:57:24 -06001973 }
1974
1975 # We expect three device-tree files in the output, one after the other.
1976 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1977 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1978 # main U-Boot tree. All three should have the same postions and offset.
1979 start = 0
Simon Glass6ad24522022-02-28 07:16:54 -07001980 self.maxDiff = None
1981 for item in ['', 'spl', 'tpl', 'vpl']:
Simon Glass6ed45ba2018-09-14 04:57:24 -06001982 dtb = fdt.Fdt.FromData(data[start:])
1983 dtb.Scan()
Simon Glass12bb1a92019-07-20 12:23:51 -06001984 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
Simon Glass6ad24522022-02-28 07:16:54 -07001985 ['spl', 'tpl', 'vpl'])
Simon Glass6ed45ba2018-09-14 04:57:24 -06001986 expected = dict(base_expected)
1987 if item:
1988 expected[item] = 0
1989 self.assertEqual(expected, props)
1990 start += dtb._fdt_obj.totalsize()
1991
1992 def testUpdateFdtOutput(self):
1993 """Test that output DTB files are updated"""
1994 try:
Simon Glass741f2d62018-10-01 12:22:30 -06001995 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glass6ed45ba2018-09-14 04:57:24 -06001996 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1997
1998 # Unfortunately, compiling a source file always results in a file
1999 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass741f2d62018-10-01 12:22:30 -06002000 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glass6ed45ba2018-09-14 04:57:24 -06002001 # binman as a file called u-boot.dtb. To fix this, copy the file
2002 # over to the expected place.
Simon Glass6ed45ba2018-09-14 04:57:24 -06002003 start = 0
2004 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
Simon Glass6ad24522022-02-28 07:16:54 -07002005 'tpl/u-boot-tpl.dtb.out', 'vpl/u-boot-vpl.dtb.out']:
Simon Glass6ed45ba2018-09-14 04:57:24 -06002006 dtb = fdt.Fdt.FromData(data[start:])
2007 size = dtb._fdt_obj.totalsize()
Simon Glassc1aa66e2022-01-29 14:14:04 -07002008 pathname = tools.get_output_filename(os.path.split(fname)[1])
2009 outdata = tools.read_file(pathname)
Simon Glass6ed45ba2018-09-14 04:57:24 -06002010 name = os.path.split(fname)[0]
2011
2012 if name:
Simon Glass6ad24522022-02-28 07:16:54 -07002013 orig_indata = self._GetDtbContentsForSpls(dtb_data, name)
Simon Glass6ed45ba2018-09-14 04:57:24 -06002014 else:
2015 orig_indata = dtb_data
2016 self.assertNotEqual(outdata, orig_indata,
2017 "Expected output file '%s' be updated" % pathname)
2018 self.assertEqual(outdata, data[start:start + size],
2019 "Expected output file '%s' to match output image" %
2020 pathname)
2021 start += size
2022 finally:
2023 self._ResetDtbs()
2024
Simon Glass83d73c22018-09-14 04:57:26 -06002025 def _decompress(self, data):
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +02002026 bintool = self.comp_bintools['lz4']
2027 return bintool.decompress(data)
Simon Glass83d73c22018-09-14 04:57:26 -06002028
2029 def testCompress(self):
2030 """Test compression of blobs"""
Simon Glassac62fba2019-07-08 13:18:53 -06002031 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06002032 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass83d73c22018-09-14 04:57:26 -06002033 use_real_dtb=True, update_dtb=True)
2034 dtb = fdt.Fdt(out_dtb_fname)
2035 dtb.Scan()
2036 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2037 orig = self._decompress(data)
2038 self.assertEquals(COMPRESS_DATA, orig)
Simon Glass97c3e9a2020-10-26 17:40:15 -06002039
2040 # Do a sanity check on various fields
2041 image = control.images['image']
2042 entries = image.GetEntries()
2043 self.assertEqual(1, len(entries))
2044
2045 entry = entries['blob']
2046 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
2047 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
2048 orig = self._decompress(entry.data)
2049 self.assertEqual(orig, entry.uncomp_data)
2050
Simon Glass63e7ba62020-10-26 17:40:16 -06002051 self.assertEqual(image.data, entry.data)
2052
Simon Glass83d73c22018-09-14 04:57:26 -06002053 expected = {
2054 'blob:uncomp-size': len(COMPRESS_DATA),
2055 'blob:size': len(data),
2056 'size': len(data),
2057 }
2058 self.assertEqual(expected, props)
2059
Simon Glass0a98b282018-09-14 04:57:28 -06002060 def testFiles(self):
2061 """Test bringing in multiple files"""
Simon Glass741f2d62018-10-01 12:22:30 -06002062 data = self._DoReadFile('084_files.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06002063 self.assertEqual(FILES_DATA, data)
2064
2065 def testFilesCompress(self):
2066 """Test bringing in multiple files and compressing them"""
Simon Glassac62fba2019-07-08 13:18:53 -06002067 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06002068 data = self._DoReadFile('085_files_compress.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06002069
2070 image = control.images['image']
2071 entries = image.GetEntries()
2072 files = entries['files']
Simon Glass8beb11e2019-07-08 14:25:47 -06002073 entries = files._entries
Simon Glass0a98b282018-09-14 04:57:28 -06002074
Simon Glassc6c10e72019-05-17 22:00:46 -06002075 orig = b''
Simon Glass0a98b282018-09-14 04:57:28 -06002076 for i in range(1, 3):
2077 key = '%d.dat' % i
2078 start = entries[key].image_pos
2079 len = entries[key].size
2080 chunk = data[start:start + len]
2081 orig += self._decompress(chunk)
2082
2083 self.assertEqual(FILES_DATA, orig)
2084
2085 def testFilesMissing(self):
2086 """Test missing files"""
2087 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002088 data = self._DoReadFile('086_files_none.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06002089 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
2090 'no files', str(e.exception))
2091
2092 def testFilesNoPattern(self):
2093 """Test missing files"""
2094 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002095 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06002096 self.assertIn("Node '/binman/files': Missing 'pattern' property",
2097 str(e.exception))
2098
Simon Glass80a66ae2022-03-05 20:18:59 -07002099 def testExtendSize(self):
2100 """Test an extending entry"""
2101 data, _, map_data, _ = self._DoReadFileDtb('088_extend_size.dts',
Simon Glassba64a0b2018-09-14 04:57:29 -06002102 map=True)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002103 expect = (tools.get_bytes(ord('a'), 8) + U_BOOT_DATA +
2104 MRC_DATA + tools.get_bytes(ord('b'), 1) + U_BOOT_DATA +
2105 tools.get_bytes(ord('c'), 8) + U_BOOT_DATA +
2106 tools.get_bytes(ord('d'), 8))
Simon Glassba64a0b2018-09-14 04:57:29 -06002107 self.assertEqual(expect, data)
2108 self.assertEqual('''ImagePos Offset Size Name
210900000000 00000000 00000028 main-section
211000000000 00000000 00000008 fill
211100000008 00000008 00000004 u-boot
21120000000c 0000000c 00000004 section
21130000000c 00000000 00000003 intel-mrc
211400000010 00000010 00000004 u-boot2
211500000014 00000014 0000000c section2
211600000014 00000000 00000008 fill
21170000001c 00000008 00000004 u-boot
211800000020 00000020 00000008 fill2
2119''', map_data)
2120
Simon Glass80a66ae2022-03-05 20:18:59 -07002121 def testExtendSizeBad(self):
2122 """Test an extending entry which fails to provide contents"""
Simon Glass163ed6c2018-09-14 04:57:36 -06002123 with test_util.capture_sys_output() as (stdout, stderr):
2124 with self.assertRaises(ValueError) as e:
Simon Glass80a66ae2022-03-05 20:18:59 -07002125 self._DoReadFileDtb('089_extend_size_bad.dts', map=True)
Simon Glassba64a0b2018-09-14 04:57:29 -06002126 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
2127 'expanding entry', str(e.exception))
2128
Simon Glasse0e5df92018-09-14 04:57:31 -06002129 def testHash(self):
2130 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06002131 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06002132 use_real_dtb=True, update_dtb=True)
2133 dtb = fdt.Fdt(out_dtb_fname)
2134 dtb.Scan()
2135 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
2136 m = hashlib.sha256()
2137 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06002138 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06002139
2140 def testHashNoAlgo(self):
2141 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002142 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06002143 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2144 'hash node', str(e.exception))
2145
2146 def testHashBadAlgo(self):
2147 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002148 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glass8db1f992022-02-08 10:59:44 -07002149 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm 'invalid'",
Simon Glasse0e5df92018-09-14 04:57:31 -06002150 str(e.exception))
2151
2152 def testHashSection(self):
2153 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06002154 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06002155 use_real_dtb=True, update_dtb=True)
2156 dtb = fdt.Fdt(out_dtb_fname)
2157 dtb.Scan()
2158 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2159 m = hashlib.sha256()
2160 m.update(U_BOOT_DATA)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002161 m.update(tools.get_bytes(ord('a'), 16))
Simon Glassc6c10e72019-05-17 22:00:46 -06002162 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06002163
Simon Glassf0253632018-09-14 04:57:32 -06002164 def testPackUBootTplMicrocode(self):
2165 """Test that x86 microcode can be handled correctly in TPL
2166
2167 We expect to see the following in the image, in order:
2168 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2169 place
2170 u-boot-tpl.dtb with the microcode removed
2171 the microcode
2172 """
Simon Glass2090f1e2019-08-24 07:23:00 -06002173 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass741f2d62018-10-01 12:22:30 -06002174 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glassf0253632018-09-14 04:57:32 -06002175 U_BOOT_TPL_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06002176 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2177 b'ter somewhere in here', first)
Simon Glassf0253632018-09-14 04:57:32 -06002178
Simon Glassf8f8df62018-09-14 04:57:34 -06002179 def testFmapX86(self):
2180 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06002181 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassf8f8df62018-09-14 04:57:34 -06002182 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc1aa66e2022-01-29 14:14:04 -07002183 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('a'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06002184 self.assertEqual(expected, data[:32])
2185 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2186
2187 self.assertEqual(0x100, fhdr.image_size)
2188
2189 self.assertEqual(0, fentries[0].offset)
2190 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06002191 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06002192
2193 self.assertEqual(4, fentries[1].offset)
2194 self.assertEqual(3, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06002195 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06002196
2197 self.assertEqual(32, fentries[2].offset)
2198 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2199 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06002200 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06002201
2202 def testFmapX86Section(self):
2203 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06002204 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002205 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('b'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06002206 self.assertEqual(expected, data[:32])
2207 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2208
Simon Glass17365752021-04-03 11:05:10 +13002209 self.assertEqual(0x180, fhdr.image_size)
2210 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
Simon Glassc7722e82021-04-03 11:05:09 +13002211 fiter = iter(fentries)
Simon Glassf8f8df62018-09-14 04:57:34 -06002212
Simon Glassc7722e82021-04-03 11:05:09 +13002213 fentry = next(fiter)
2214 self.assertEqual(b'U_BOOT', fentry.name)
2215 self.assertEqual(0, fentry.offset)
2216 self.assertEqual(4, fentry.size)
Simon Glassf8f8df62018-09-14 04:57:34 -06002217
Simon Glassc7722e82021-04-03 11:05:09 +13002218 fentry = next(fiter)
Simon Glass17365752021-04-03 11:05:10 +13002219 self.assertEqual(b'SECTION', fentry.name)
2220 self.assertEqual(4, fentry.offset)
2221 self.assertEqual(0x20 + expect_size, fentry.size)
2222
2223 fentry = next(fiter)
Simon Glassc7722e82021-04-03 11:05:09 +13002224 self.assertEqual(b'INTEL_MRC', fentry.name)
2225 self.assertEqual(4, fentry.offset)
2226 self.assertEqual(3, fentry.size)
Simon Glassf8f8df62018-09-14 04:57:34 -06002227
Simon Glassc7722e82021-04-03 11:05:09 +13002228 fentry = next(fiter)
2229 self.assertEqual(b'FMAP', fentry.name)
2230 self.assertEqual(36, fentry.offset)
2231 self.assertEqual(expect_size, fentry.size)
Simon Glassf8f8df62018-09-14 04:57:34 -06002232
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002233 def testElf(self):
2234 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06002235 self._SetupSplElf()
Simon Glass2090f1e2019-08-24 07:23:00 -06002236 self._SetupTplElf()
Simon Glass53e22bf2019-08-24 07:22:53 -06002237 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002238 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06002239 data = self._DoReadFile('096_elf.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002240
Simon Glass093d1682019-07-08 13:18:25 -06002241 def testElfStrip(self):
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002242 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06002243 self._SetupSplElf()
Simon Glass53e22bf2019-08-24 07:22:53 -06002244 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002245 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06002246 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002247
Simon Glass163ed6c2018-09-14 04:57:36 -06002248 def testPackOverlapMap(self):
2249 """Test that overlapping regions are detected"""
2250 with test_util.capture_sys_output() as (stdout, stderr):
2251 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002252 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002253 map_fname = tools.get_output_filename('image.map')
Simon Glass163ed6c2018-09-14 04:57:36 -06002254 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2255 stdout.getvalue())
2256
2257 # We should not get an inmage, but there should be a map file
Simon Glassc1aa66e2022-01-29 14:14:04 -07002258 self.assertFalse(os.path.exists(tools.get_output_filename('image.bin')))
Simon Glass163ed6c2018-09-14 04:57:36 -06002259 self.assertTrue(os.path.exists(map_fname))
Simon Glassc1aa66e2022-01-29 14:14:04 -07002260 map_data = tools.read_file(map_fname, binary=False)
Simon Glass163ed6c2018-09-14 04:57:36 -06002261 self.assertEqual('''ImagePos Offset Size Name
Simon Glass0ff83da2020-10-26 17:40:24 -06002262<none> 00000000 00000008 main-section
Simon Glass163ed6c2018-09-14 04:57:36 -06002263<none> 00000000 00000004 u-boot
2264<none> 00000003 00000004 u-boot-align
2265''', map_data)
2266
Simon Glass093d1682019-07-08 13:18:25 -06002267 def testPackRefCode(self):
Simon Glass3ae192c2018-10-01 12:22:31 -06002268 """Test that an image with an Intel Reference code binary works"""
2269 data = self._DoReadFile('100_intel_refcode.dts')
2270 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2271
Simon Glass9481c802019-04-25 21:58:39 -06002272 def testSectionOffset(self):
2273 """Tests use of a section with an offset"""
2274 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2275 map=True)
2276 self.assertEqual('''ImagePos Offset Size Name
227700000000 00000000 00000038 main-section
227800000004 00000004 00000010 section@0
227900000004 00000000 00000004 u-boot
228000000018 00000018 00000010 section@1
228100000018 00000000 00000004 u-boot
22820000002c 0000002c 00000004 section@2
22830000002c 00000000 00000004 u-boot
2284''', map_data)
2285 self.assertEqual(data,
Simon Glassc1aa66e2022-01-29 14:14:04 -07002286 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2287 tools.get_bytes(0x21, 12) +
2288 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2289 tools.get_bytes(0x61, 12) +
2290 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2291 tools.get_bytes(0x26, 8))
Simon Glass9481c802019-04-25 21:58:39 -06002292
Simon Glassac62fba2019-07-08 13:18:53 -06002293 def testCbfsRaw(self):
2294 """Test base handling of a Coreboot Filesystem (CBFS)
2295
2296 The exact contents of the CBFS is verified by similar tests in
2297 cbfs_util_test.py. The tests here merely check that the files added to
2298 the CBFS can be found in the final image.
2299 """
2300 data = self._DoReadFile('102_cbfs_raw.dts')
2301 size = 0xb0
2302
2303 cbfs = cbfs_util.CbfsReader(data)
2304 self.assertEqual(size, cbfs.rom_size)
2305
2306 self.assertIn('u-boot-dtb', cbfs.files)
2307 cfile = cbfs.files['u-boot-dtb']
2308 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2309
2310 def testCbfsArch(self):
2311 """Test on non-x86 architecture"""
2312 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2313 size = 0x100
2314
2315 cbfs = cbfs_util.CbfsReader(data)
2316 self.assertEqual(size, cbfs.rom_size)
2317
2318 self.assertIn('u-boot-dtb', cbfs.files)
2319 cfile = cbfs.files['u-boot-dtb']
2320 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2321
2322 def testCbfsStage(self):
2323 """Tests handling of a Coreboot Filesystem (CBFS)"""
2324 if not elf.ELF_TOOLS:
2325 self.skipTest('Python elftools not available')
2326 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2327 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2328 size = 0xb0
2329
2330 data = self._DoReadFile('104_cbfs_stage.dts')
2331 cbfs = cbfs_util.CbfsReader(data)
2332 self.assertEqual(size, cbfs.rom_size)
2333
2334 self.assertIn('u-boot', cbfs.files)
2335 cfile = cbfs.files['u-boot']
2336 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2337
2338 def testCbfsRawCompress(self):
2339 """Test handling of compressing raw files"""
2340 self._CheckLz4()
2341 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2342 size = 0x140
2343
2344 cbfs = cbfs_util.CbfsReader(data)
2345 self.assertIn('u-boot', cbfs.files)
2346 cfile = cbfs.files['u-boot']
2347 self.assertEqual(COMPRESS_DATA, cfile.data)
2348
2349 def testCbfsBadArch(self):
2350 """Test handling of a bad architecture"""
2351 with self.assertRaises(ValueError) as e:
2352 self._DoReadFile('106_cbfs_bad_arch.dts')
2353 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2354
2355 def testCbfsNoSize(self):
2356 """Test handling of a missing size property"""
2357 with self.assertRaises(ValueError) as e:
2358 self._DoReadFile('107_cbfs_no_size.dts')
2359 self.assertIn('entry must have a size property', str(e.exception))
2360
Simon Glasse2f04742021-11-23 11:03:54 -07002361 def testCbfsNoContents(self):
Simon Glassac62fba2019-07-08 13:18:53 -06002362 """Test handling of a CBFS entry which does not provide contentsy"""
2363 with self.assertRaises(ValueError) as e:
2364 self._DoReadFile('108_cbfs_no_contents.dts')
2365 self.assertIn('Could not complete processing of contents',
2366 str(e.exception))
2367
2368 def testCbfsBadCompress(self):
2369 """Test handling of a bad architecture"""
2370 with self.assertRaises(ValueError) as e:
2371 self._DoReadFile('109_cbfs_bad_compress.dts')
2372 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2373 str(e.exception))
2374
2375 def testCbfsNamedEntries(self):
2376 """Test handling of named entries"""
2377 data = self._DoReadFile('110_cbfs_name.dts')
2378
2379 cbfs = cbfs_util.CbfsReader(data)
2380 self.assertIn('FRED', cbfs.files)
2381 cfile1 = cbfs.files['FRED']
2382 self.assertEqual(U_BOOT_DATA, cfile1.data)
2383
2384 self.assertIn('hello', cbfs.files)
2385 cfile2 = cbfs.files['hello']
2386 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2387
Simon Glassc5ac1382019-07-08 13:18:54 -06002388 def _SetupIfwi(self, fname):
2389 """Set up to run an IFWI test
2390
2391 Args:
2392 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2393 """
2394 self._SetupSplElf()
Simon Glass2090f1e2019-08-24 07:23:00 -06002395 self._SetupTplElf()
Simon Glassc5ac1382019-07-08 13:18:54 -06002396
2397 # Intel Integrated Firmware Image (IFWI) file
2398 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2399 data = fd.read()
2400 TestFunctional._MakeInputFile(fname,data)
2401
2402 def _CheckIfwi(self, data):
2403 """Check that an image with an IFWI contains the correct output
2404
2405 Args:
2406 data: Conents of output file
2407 """
Simon Glassc1aa66e2022-01-29 14:14:04 -07002408 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glassc5ac1382019-07-08 13:18:54 -06002409 if data[:0x1000] != expected_desc:
2410 self.fail('Expected descriptor binary at start of image')
2411
2412 # We expect to find the TPL wil in subpart IBBP entry IBBL
Simon Glassc1aa66e2022-01-29 14:14:04 -07002413 image_fname = tools.get_output_filename('image.bin')
2414 tpl_fname = tools.get_output_filename('tpl.out')
Simon Glass532ae702022-01-09 20:14:01 -07002415 ifwitool = bintool.Bintool.create('ifwitool')
2416 ifwitool.extract(image_fname, 'IBBP', 'IBBL', tpl_fname)
Simon Glassc5ac1382019-07-08 13:18:54 -06002417
Simon Glassc1aa66e2022-01-29 14:14:04 -07002418 tpl_data = tools.read_file(tpl_fname)
Simon Glasse95be632019-08-24 07:22:51 -06002419 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glassc5ac1382019-07-08 13:18:54 -06002420
2421 def testPackX86RomIfwi(self):
2422 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2423 self._SetupIfwi('fitimage.bin')
Simon Glass9255f3c2019-08-24 07:23:01 -06002424 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002425 self._CheckIfwi(data)
2426
2427 def testPackX86RomIfwiNoDesc(self):
2428 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2429 self._SetupIfwi('ifwi.bin')
Simon Glass9255f3c2019-08-24 07:23:01 -06002430 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002431 self._CheckIfwi(data)
2432
2433 def testPackX86RomIfwiNoData(self):
2434 """Test that an x86 ROM with IFWI handles missing data"""
2435 self._SetupIfwi('ifwi.bin')
2436 with self.assertRaises(ValueError) as e:
Simon Glass9255f3c2019-08-24 07:23:01 -06002437 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002438 self.assertIn('Could not complete processing of contents',
2439 str(e.exception))
Simon Glass53af22a2018-07-17 13:25:32 -06002440
Simon Glass4f9ee832022-01-09 20:14:09 -07002441 def testIfwiMissing(self):
2442 """Test that binman still produces an image if ifwitool is missing"""
2443 self._SetupIfwi('fitimage.bin')
2444 with test_util.capture_sys_output() as (_, stderr):
2445 self._DoTestFile('111_x86_rom_ifwi.dts',
2446 force_missing_bintools='ifwitool')
2447 err = stderr.getvalue()
2448 self.assertRegex(err,
2449 "Image 'main-section'.*missing bintools.*: ifwitool")
2450
Simon Glasse073d4e2019-07-08 13:18:56 -06002451 def testCbfsOffset(self):
2452 """Test a CBFS with files at particular offsets
2453
2454 Like all CFBS tests, this is just checking the logic that calls
2455 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2456 """
2457 data = self._DoReadFile('114_cbfs_offset.dts')
2458 size = 0x200
2459
2460 cbfs = cbfs_util.CbfsReader(data)
2461 self.assertEqual(size, cbfs.rom_size)
2462
2463 self.assertIn('u-boot', cbfs.files)
2464 cfile = cbfs.files['u-boot']
2465 self.assertEqual(U_BOOT_DATA, cfile.data)
2466 self.assertEqual(0x40, cfile.cbfs_offset)
2467
2468 self.assertIn('u-boot-dtb', cbfs.files)
2469 cfile2 = cbfs.files['u-boot-dtb']
2470 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2471 self.assertEqual(0x140, cfile2.cbfs_offset)
2472
Simon Glass086cec92019-07-08 14:25:27 -06002473 def testFdtmap(self):
2474 """Test an FDT map can be inserted in the image"""
2475 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2476 fdtmap_data = data[len(U_BOOT_DATA):]
2477 magic = fdtmap_data[:8]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002478 self.assertEqual(b'_FDTMAP_', magic)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002479 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass086cec92019-07-08 14:25:27 -06002480
2481 fdt_data = fdtmap_data[16:]
2482 dtb = fdt.Fdt.FromData(fdt_data)
2483 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002484 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass086cec92019-07-08 14:25:27 -06002485 self.assertEqual({
2486 'image-pos': 0,
2487 'offset': 0,
2488 'u-boot:offset': 0,
2489 'u-boot:size': len(U_BOOT_DATA),
2490 'u-boot:image-pos': 0,
2491 'fdtmap:image-pos': 4,
2492 'fdtmap:offset': 4,
2493 'fdtmap:size': len(fdtmap_data),
2494 'size': len(data),
2495 }, props)
2496
2497 def testFdtmapNoMatch(self):
2498 """Check handling of an FDT map when the section cannot be found"""
2499 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2500
2501 # Mangle the section name, which should cause a mismatch between the
2502 # correct FDT path and the one expected by the section
2503 image = control.images['image']
Simon Glasscf228942019-07-08 14:25:28 -06002504 image._node.path += '-suffix'
Simon Glass086cec92019-07-08 14:25:27 -06002505 entries = image.GetEntries()
2506 fdtmap = entries['fdtmap']
2507 with self.assertRaises(ValueError) as e:
2508 fdtmap._GetFdtmap()
2509 self.assertIn("Cannot locate node for path '/binman-suffix'",
2510 str(e.exception))
2511
Simon Glasscf228942019-07-08 14:25:28 -06002512 def testFdtmapHeader(self):
2513 """Test an FDT map and image header can be inserted in the image"""
2514 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2515 fdtmap_pos = len(U_BOOT_DATA)
2516 fdtmap_data = data[fdtmap_pos:]
2517 fdt_data = fdtmap_data[16:]
2518 dtb = fdt.Fdt.FromData(fdt_data)
2519 fdt_size = dtb.GetFdtObj().totalsize()
2520 hdr_data = data[-8:]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002521 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002522 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2523 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2524
2525 def testFdtmapHeaderStart(self):
2526 """Test an image header can be inserted at the image start"""
2527 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2528 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2529 hdr_data = data[:8]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002530 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002531 offset = struct.unpack('<I', hdr_data[4:])[0]
2532 self.assertEqual(fdtmap_pos, offset)
2533
2534 def testFdtmapHeaderPos(self):
2535 """Test an image header can be inserted at a chosen position"""
2536 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2537 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2538 hdr_data = data[0x80:0x88]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002539 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002540 offset = struct.unpack('<I', hdr_data[4:])[0]
2541 self.assertEqual(fdtmap_pos, offset)
2542
2543 def testHeaderMissingFdtmap(self):
2544 """Test an image header requires an fdtmap"""
2545 with self.assertRaises(ValueError) as e:
2546 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2547 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2548 str(e.exception))
2549
2550 def testHeaderNoLocation(self):
2551 """Test an image header with a no specified location is detected"""
2552 with self.assertRaises(ValueError) as e:
2553 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2554 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2555 str(e.exception))
2556
Simon Glassc52c9e72019-07-08 14:25:37 -06002557 def testEntryExpand(self):
Simon Glass80a66ae2022-03-05 20:18:59 -07002558 """Test extending an entry after it is packed"""
2559 data = self._DoReadFile('121_entry_extend.dts')
Simon Glass79d3c582019-07-20 12:23:57 -06002560 self.assertEqual(b'aaa', data[:3])
2561 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2562 self.assertEqual(b'aaa', data[-3:])
Simon Glassc52c9e72019-07-08 14:25:37 -06002563
Simon Glass80a66ae2022-03-05 20:18:59 -07002564 def testEntryExtendBad(self):
2565 """Test extending an entry after it is packed, twice"""
Simon Glassc52c9e72019-07-08 14:25:37 -06002566 with self.assertRaises(ValueError) as e:
Simon Glass80a66ae2022-03-05 20:18:59 -07002567 self._DoReadFile('122_entry_extend_twice.dts')
Simon Glass61ec04f2019-07-20 12:23:58 -06002568 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glassc52c9e72019-07-08 14:25:37 -06002569 str(e.exception))
2570
Simon Glass80a66ae2022-03-05 20:18:59 -07002571 def testEntryExtendSection(self):
2572 """Test extending an entry within a section after it is packed"""
2573 data = self._DoReadFile('123_entry_extend_section.dts')
Simon Glass79d3c582019-07-20 12:23:57 -06002574 self.assertEqual(b'aaa', data[:3])
2575 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2576 self.assertEqual(b'aaa', data[-3:])
Simon Glassc52c9e72019-07-08 14:25:37 -06002577
Simon Glass6c223fd2019-07-08 14:25:38 -06002578 def testCompressDtb(self):
2579 """Test that compress of device-tree files is supported"""
2580 self._CheckLz4()
2581 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2582 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2583 comp_data = data[len(U_BOOT_DATA):]
2584 orig = self._decompress(comp_data)
2585 dtb = fdt.Fdt.FromData(orig)
2586 dtb.Scan()
2587 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2588 expected = {
2589 'u-boot:size': len(U_BOOT_DATA),
2590 'u-boot-dtb:uncomp-size': len(orig),
2591 'u-boot-dtb:size': len(comp_data),
2592 'size': len(data),
2593 }
2594 self.assertEqual(expected, props)
2595
Simon Glass69f7cb32019-07-08 14:25:41 -06002596 def testCbfsUpdateFdt(self):
2597 """Test that we can update the device tree with CBFS offset/size info"""
2598 self._CheckLz4()
2599 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2600 update_dtb=True)
2601 dtb = fdt.Fdt(out_dtb_fname)
2602 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002603 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass69f7cb32019-07-08 14:25:41 -06002604 del props['cbfs/u-boot:size']
2605 self.assertEqual({
2606 'offset': 0,
2607 'size': len(data),
2608 'image-pos': 0,
2609 'cbfs:offset': 0,
2610 'cbfs:size': len(data),
2611 'cbfs:image-pos': 0,
2612 'cbfs/u-boot:offset': 0x38,
2613 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2614 'cbfs/u-boot:image-pos': 0x38,
2615 'cbfs/u-boot-dtb:offset': 0xb8,
2616 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2617 'cbfs/u-boot-dtb:image-pos': 0xb8,
2618 }, props)
2619
Simon Glass8a1ad062019-07-08 14:25:42 -06002620 def testCbfsBadType(self):
2621 """Test an image header with a no specified location is detected"""
2622 with self.assertRaises(ValueError) as e:
2623 self._DoReadFile('126_cbfs_bad_type.dts')
2624 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2625
Simon Glass41b8ba02019-07-08 14:25:43 -06002626 def testList(self):
2627 """Test listing the files in an image"""
2628 self._CheckLz4()
2629 data = self._DoReadFile('127_list.dts')
2630 image = control.images['image']
2631 entries = image.BuildEntryList()
2632 self.assertEqual(7, len(entries))
2633
2634 ent = entries[0]
2635 self.assertEqual(0, ent.indent)
2636 self.assertEqual('main-section', ent.name)
2637 self.assertEqual('section', ent.etype)
2638 self.assertEqual(len(data), ent.size)
2639 self.assertEqual(0, ent.image_pos)
2640 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002641 self.assertEqual(0, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002642
2643 ent = entries[1]
2644 self.assertEqual(1, ent.indent)
2645 self.assertEqual('u-boot', ent.name)
2646 self.assertEqual('u-boot', ent.etype)
2647 self.assertEqual(len(U_BOOT_DATA), ent.size)
2648 self.assertEqual(0, ent.image_pos)
2649 self.assertEqual(None, ent.uncomp_size)
2650 self.assertEqual(0, ent.offset)
2651
2652 ent = entries[2]
2653 self.assertEqual(1, ent.indent)
2654 self.assertEqual('section', ent.name)
2655 self.assertEqual('section', ent.etype)
2656 section_size = ent.size
2657 self.assertEqual(0x100, ent.image_pos)
2658 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002659 self.assertEqual(0x100, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002660
2661 ent = entries[3]
2662 self.assertEqual(2, ent.indent)
2663 self.assertEqual('cbfs', ent.name)
2664 self.assertEqual('cbfs', ent.etype)
2665 self.assertEqual(0x400, ent.size)
2666 self.assertEqual(0x100, ent.image_pos)
2667 self.assertEqual(None, ent.uncomp_size)
2668 self.assertEqual(0, ent.offset)
2669
2670 ent = entries[4]
2671 self.assertEqual(3, ent.indent)
2672 self.assertEqual('u-boot', ent.name)
2673 self.assertEqual('u-boot', ent.etype)
2674 self.assertEqual(len(U_BOOT_DATA), ent.size)
2675 self.assertEqual(0x138, ent.image_pos)
2676 self.assertEqual(None, ent.uncomp_size)
2677 self.assertEqual(0x38, ent.offset)
2678
2679 ent = entries[5]
2680 self.assertEqual(3, ent.indent)
2681 self.assertEqual('u-boot-dtb', ent.name)
2682 self.assertEqual('text', ent.etype)
2683 self.assertGreater(len(COMPRESS_DATA), ent.size)
2684 self.assertEqual(0x178, ent.image_pos)
2685 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2686 self.assertEqual(0x78, ent.offset)
2687
2688 ent = entries[6]
2689 self.assertEqual(2, ent.indent)
2690 self.assertEqual('u-boot-dtb', ent.name)
2691 self.assertEqual('u-boot-dtb', ent.etype)
2692 self.assertEqual(0x500, ent.image_pos)
2693 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2694 dtb_size = ent.size
2695 # Compressing this data expands it since headers are added
2696 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2697 self.assertEqual(0x400, ent.offset)
2698
2699 self.assertEqual(len(data), 0x100 + section_size)
2700 self.assertEqual(section_size, 0x400 + dtb_size)
2701
Simon Glasse1925fa2019-07-08 14:25:44 -06002702 def testFindFdtmap(self):
2703 """Test locating an FDT map in an image"""
2704 self._CheckLz4()
2705 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2706 image = control.images['image']
2707 entries = image.GetEntries()
2708 entry = entries['fdtmap']
2709 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2710
2711 def testFindFdtmapMissing(self):
2712 """Test failing to locate an FDP map"""
2713 data = self._DoReadFile('005_simple.dts')
2714 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2715
Simon Glass2d260032019-07-08 14:25:45 -06002716 def testFindImageHeader(self):
2717 """Test locating a image header"""
2718 self._CheckLz4()
Simon Glassffded752019-07-08 14:25:46 -06002719 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002720 image = control.images['image']
2721 entries = image.GetEntries()
2722 entry = entries['fdtmap']
2723 # The header should point to the FDT map
2724 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2725
2726 def testFindImageHeaderStart(self):
2727 """Test locating a image header located at the start of an image"""
Simon Glassffded752019-07-08 14:25:46 -06002728 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002729 image = control.images['image']
2730 entries = image.GetEntries()
2731 entry = entries['fdtmap']
2732 # The header should point to the FDT map
2733 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2734
2735 def testFindImageHeaderMissing(self):
2736 """Test failing to locate an image header"""
2737 data = self._DoReadFile('005_simple.dts')
2738 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2739
Simon Glassffded752019-07-08 14:25:46 -06002740 def testReadImage(self):
2741 """Test reading an image and accessing its FDT map"""
2742 self._CheckLz4()
2743 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002744 image_fname = tools.get_output_filename('image.bin')
Simon Glassffded752019-07-08 14:25:46 -06002745 orig_image = control.images['image']
2746 image = Image.FromFile(image_fname)
2747 self.assertEqual(orig_image.GetEntries().keys(),
2748 image.GetEntries().keys())
2749
2750 orig_entry = orig_image.GetEntries()['fdtmap']
2751 entry = image.GetEntries()['fdtmap']
2752 self.assertEquals(orig_entry.offset, entry.offset)
2753 self.assertEquals(orig_entry.size, entry.size)
2754 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2755
2756 def testReadImageNoHeader(self):
2757 """Test accessing an image's FDT map without an image header"""
2758 self._CheckLz4()
2759 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002760 image_fname = tools.get_output_filename('image.bin')
Simon Glassffded752019-07-08 14:25:46 -06002761 image = Image.FromFile(image_fname)
2762 self.assertTrue(isinstance(image, Image))
Simon Glass10f9d002019-07-20 12:23:50 -06002763 self.assertEqual('image', image.image_name[-5:])
Simon Glassffded752019-07-08 14:25:46 -06002764
2765 def testReadImageFail(self):
2766 """Test failing to read an image image's FDT map"""
2767 self._DoReadFile('005_simple.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002768 image_fname = tools.get_output_filename('image.bin')
Simon Glassffded752019-07-08 14:25:46 -06002769 with self.assertRaises(ValueError) as e:
2770 image = Image.FromFile(image_fname)
2771 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glasse073d4e2019-07-08 13:18:56 -06002772
Simon Glass61f564d2019-07-08 14:25:48 -06002773 def testListCmd(self):
2774 """Test listing the files in an image using an Fdtmap"""
2775 self._CheckLz4()
2776 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2777
2778 # lz4 compression size differs depending on the version
2779 image = control.images['image']
2780 entries = image.GetEntries()
2781 section_size = entries['section'].size
2782 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2783 fdtmap_offset = entries['fdtmap'].offset
2784
Simon Glassf86a7362019-07-20 12:24:10 -06002785 try:
2786 tmpdir, updated_fname = self._SetupImageInTmpdir()
2787 with test_util.capture_sys_output() as (stdout, stderr):
2788 self._DoBinman('ls', '-i', updated_fname)
2789 finally:
2790 shutil.rmtree(tmpdir)
Simon Glass61f564d2019-07-08 14:25:48 -06002791 lines = stdout.getvalue().splitlines()
2792 expected = [
2793'Name Image-pos Size Entry-type Offset Uncomp-size',
2794'----------------------------------------------------------------------',
2795'main-section 0 c00 section 0',
2796' u-boot 0 4 u-boot 0',
2797' section 100 %x section 100' % section_size,
2798' cbfs 100 400 cbfs 0',
2799' u-boot 138 4 u-boot 38',
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002800' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glass61f564d2019-07-08 14:25:48 -06002801' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002802' fdtmap %x 3bd fdtmap %x' %
Simon Glass61f564d2019-07-08 14:25:48 -06002803 (fdtmap_offset, fdtmap_offset),
2804' image-header bf8 8 image-header bf8',
2805 ]
2806 self.assertEqual(expected, lines)
2807
2808 def testListCmdFail(self):
2809 """Test failing to list an image"""
2810 self._DoReadFile('005_simple.dts')
Simon Glassf86a7362019-07-20 12:24:10 -06002811 try:
2812 tmpdir, updated_fname = self._SetupImageInTmpdir()
2813 with self.assertRaises(ValueError) as e:
2814 self._DoBinman('ls', '-i', updated_fname)
2815 finally:
2816 shutil.rmtree(tmpdir)
Simon Glass61f564d2019-07-08 14:25:48 -06002817 self.assertIn("Cannot find FDT map in image", str(e.exception))
2818
2819 def _RunListCmd(self, paths, expected):
2820 """List out entries and check the result
2821
2822 Args:
2823 paths: List of paths to pass to the list command
2824 expected: Expected list of filenames to be returned, in order
2825 """
2826 self._CheckLz4()
2827 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002828 image_fname = tools.get_output_filename('image.bin')
Simon Glass61f564d2019-07-08 14:25:48 -06002829 image = Image.FromFile(image_fname)
2830 lines = image.GetListEntries(paths)[1]
2831 files = [line[0].strip() for line in lines[1:]]
2832 self.assertEqual(expected, files)
2833
2834 def testListCmdSection(self):
2835 """Test listing the files in a section"""
2836 self._RunListCmd(['section'],
2837 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2838
2839 def testListCmdFile(self):
2840 """Test listing a particular file"""
2841 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2842
2843 def testListCmdWildcard(self):
2844 """Test listing a wildcarded file"""
2845 self._RunListCmd(['*boot*'],
2846 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2847
2848 def testListCmdWildcardMulti(self):
2849 """Test listing a wildcarded file"""
2850 self._RunListCmd(['*cb*', '*head*'],
2851 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2852
2853 def testListCmdEmpty(self):
2854 """Test listing a wildcarded file"""
2855 self._RunListCmd(['nothing'], [])
2856
2857 def testListCmdPath(self):
2858 """Test listing the files in a sub-entry of a section"""
2859 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2860
Simon Glassf667e452019-07-08 14:25:50 -06002861 def _RunExtractCmd(self, entry_name, decomp=True):
2862 """Extract an entry from an image
2863
2864 Args:
2865 entry_name: Entry name to extract
2866 decomp: True to decompress the data if compressed, False to leave
2867 it in its raw uncompressed format
2868
2869 Returns:
2870 data from entry
2871 """
2872 self._CheckLz4()
2873 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002874 image_fname = tools.get_output_filename('image.bin')
Simon Glassf667e452019-07-08 14:25:50 -06002875 return control.ReadEntry(image_fname, entry_name, decomp)
2876
2877 def testExtractSimple(self):
2878 """Test extracting a single file"""
2879 data = self._RunExtractCmd('u-boot')
2880 self.assertEqual(U_BOOT_DATA, data)
2881
Simon Glass71ce0ba2019-07-08 14:25:52 -06002882 def testExtractSection(self):
2883 """Test extracting the files in a section"""
2884 data = self._RunExtractCmd('section')
2885 cbfs_data = data[:0x400]
2886 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002887 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass71ce0ba2019-07-08 14:25:52 -06002888 dtb_data = data[0x400:]
2889 dtb = self._decompress(dtb_data)
2890 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2891
2892 def testExtractCompressed(self):
2893 """Test extracting compressed data"""
2894 data = self._RunExtractCmd('section/u-boot-dtb')
2895 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2896
2897 def testExtractRaw(self):
2898 """Test extracting compressed data without decompressing it"""
2899 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2900 dtb = self._decompress(data)
2901 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2902
2903 def testExtractCbfs(self):
2904 """Test extracting CBFS data"""
2905 data = self._RunExtractCmd('section/cbfs/u-boot')
2906 self.assertEqual(U_BOOT_DATA, data)
2907
2908 def testExtractCbfsCompressed(self):
2909 """Test extracting CBFS compressed data"""
2910 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2911 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2912
2913 def testExtractCbfsRaw(self):
2914 """Test extracting CBFS compressed data without decompressing it"""
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +02002915 bintool = self.comp_bintools['lzma_alone']
2916 self._CheckBintool(bintool)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002917 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +02002918 dtb = bintool.decompress(data)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002919 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2920
Simon Glassf667e452019-07-08 14:25:50 -06002921 def testExtractBadEntry(self):
2922 """Test extracting a bad section path"""
2923 with self.assertRaises(ValueError) as e:
2924 self._RunExtractCmd('section/does-not-exist')
2925 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2926 str(e.exception))
2927
2928 def testExtractMissingFile(self):
2929 """Test extracting file that does not exist"""
2930 with self.assertRaises(IOError) as e:
2931 control.ReadEntry('missing-file', 'name')
2932
2933 def testExtractBadFile(self):
2934 """Test extracting an invalid file"""
2935 fname = os.path.join(self._indir, 'badfile')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002936 tools.write_file(fname, b'')
Simon Glassf667e452019-07-08 14:25:50 -06002937 with self.assertRaises(ValueError) as e:
2938 control.ReadEntry(fname, 'name')
2939
Simon Glass71ce0ba2019-07-08 14:25:52 -06002940 def testExtractCmd(self):
2941 """Test extracting a file fron an image on the command line"""
2942 self._CheckLz4()
2943 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass71ce0ba2019-07-08 14:25:52 -06002944 fname = os.path.join(self._indir, 'output.extact')
Simon Glassf86a7362019-07-20 12:24:10 -06002945 try:
2946 tmpdir, updated_fname = self._SetupImageInTmpdir()
2947 with test_util.capture_sys_output() as (stdout, stderr):
2948 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2949 '-f', fname)
2950 finally:
2951 shutil.rmtree(tmpdir)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002952 data = tools.read_file(fname)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002953 self.assertEqual(U_BOOT_DATA, data)
2954
2955 def testExtractOneEntry(self):
2956 """Test extracting a single entry fron an image """
2957 self._CheckLz4()
2958 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002959 image_fname = tools.get_output_filename('image.bin')
Simon Glass71ce0ba2019-07-08 14:25:52 -06002960 fname = os.path.join(self._indir, 'output.extact')
2961 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
Simon Glassc1aa66e2022-01-29 14:14:04 -07002962 data = tools.read_file(fname)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002963 self.assertEqual(U_BOOT_DATA, data)
2964
2965 def _CheckExtractOutput(self, decomp):
2966 """Helper to test file output with and without decompression
2967
2968 Args:
2969 decomp: True to decompress entry data, False to output it raw
2970 """
2971 def _CheckPresent(entry_path, expect_data, expect_size=None):
2972 """Check and remove expected file
2973
2974 This checks the data/size of a file and removes the file both from
2975 the outfiles set and from the output directory. Once all files are
2976 processed, both the set and directory should be empty.
2977
2978 Args:
2979 entry_path: Entry path
2980 expect_data: Data to expect in file, or None to skip check
2981 expect_size: Size of data to expect in file, or None to skip
2982 """
2983 path = os.path.join(outdir, entry_path)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002984 data = tools.read_file(path)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002985 os.remove(path)
2986 if expect_data:
2987 self.assertEqual(expect_data, data)
2988 elif expect_size:
2989 self.assertEqual(expect_size, len(data))
2990 outfiles.remove(path)
2991
2992 def _CheckDirPresent(name):
2993 """Remove expected directory
2994
2995 This gives an error if the directory does not exist as expected
2996
2997 Args:
2998 name: Name of directory to remove
2999 """
3000 path = os.path.join(outdir, name)
3001 os.rmdir(path)
3002
3003 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003004 image_fname = tools.get_output_filename('image.bin')
Simon Glass71ce0ba2019-07-08 14:25:52 -06003005 outdir = os.path.join(self._indir, 'extract')
3006 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
3007
3008 # Create a set of all file that were output (should be 9)
3009 outfiles = set()
3010 for root, dirs, files in os.walk(outdir):
3011 outfiles |= set([os.path.join(root, fname) for fname in files])
3012 self.assertEqual(9, len(outfiles))
3013 self.assertEqual(9, len(einfos))
3014
3015 image = control.images['image']
3016 entries = image.GetEntries()
3017
3018 # Check the 9 files in various ways
3019 section = entries['section']
3020 section_entries = section.GetEntries()
3021 cbfs_entries = section_entries['cbfs'].GetEntries()
3022 _CheckPresent('u-boot', U_BOOT_DATA)
3023 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
3024 dtb_len = EXTRACT_DTB_SIZE
3025 if not decomp:
3026 dtb_len = cbfs_entries['u-boot-dtb'].size
3027 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
3028 if not decomp:
3029 dtb_len = section_entries['u-boot-dtb'].size
3030 _CheckPresent('section/u-boot-dtb', None, dtb_len)
3031
3032 fdtmap = entries['fdtmap']
3033 _CheckPresent('fdtmap', fdtmap.data)
3034 hdr = entries['image-header']
3035 _CheckPresent('image-header', hdr.data)
3036
3037 _CheckPresent('section/root', section.data)
3038 cbfs = section_entries['cbfs']
3039 _CheckPresent('section/cbfs/root', cbfs.data)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003040 data = tools.read_file(image_fname)
Simon Glass71ce0ba2019-07-08 14:25:52 -06003041 _CheckPresent('root', data)
3042
3043 # There should be no files left. Remove all the directories to check.
3044 # If there are any files/dirs remaining, one of these checks will fail.
3045 self.assertEqual(0, len(outfiles))
3046 _CheckDirPresent('section/cbfs')
3047 _CheckDirPresent('section')
3048 _CheckDirPresent('')
3049 self.assertFalse(os.path.exists(outdir))
3050
3051 def testExtractAllEntries(self):
3052 """Test extracting all entries"""
3053 self._CheckLz4()
3054 self._CheckExtractOutput(decomp=True)
3055
3056 def testExtractAllEntriesRaw(self):
3057 """Test extracting all entries without decompressing them"""
3058 self._CheckLz4()
3059 self._CheckExtractOutput(decomp=False)
3060
3061 def testExtractSelectedEntries(self):
3062 """Test extracting some entries"""
3063 self._CheckLz4()
3064 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003065 image_fname = tools.get_output_filename('image.bin')
Simon Glass71ce0ba2019-07-08 14:25:52 -06003066 outdir = os.path.join(self._indir, 'extract')
3067 einfos = control.ExtractEntries(image_fname, None, outdir,
3068 ['*cb*', '*head*'])
3069
3070 # File output is tested by testExtractAllEntries(), so just check that
3071 # the expected entries are selected
3072 names = [einfo.name for einfo in einfos]
3073 self.assertEqual(names,
3074 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
3075
3076 def testExtractNoEntryPaths(self):
3077 """Test extracting some entries"""
3078 self._CheckLz4()
3079 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003080 image_fname = tools.get_output_filename('image.bin')
Simon Glass71ce0ba2019-07-08 14:25:52 -06003081 with self.assertRaises(ValueError) as e:
3082 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassbb5edc12019-07-20 12:24:14 -06003083 self.assertIn('Must specify an entry path to write with -f',
Simon Glass71ce0ba2019-07-08 14:25:52 -06003084 str(e.exception))
3085
3086 def testExtractTooManyEntryPaths(self):
3087 """Test extracting some entries"""
3088 self._CheckLz4()
3089 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003090 image_fname = tools.get_output_filename('image.bin')
Simon Glass71ce0ba2019-07-08 14:25:52 -06003091 with self.assertRaises(ValueError) as e:
3092 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassbb5edc12019-07-20 12:24:14 -06003093 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass71ce0ba2019-07-08 14:25:52 -06003094 str(e.exception))
3095
Simon Glasse2705fa2019-07-08 14:25:53 -06003096 def testPackAlignSection(self):
3097 """Test that sections can have alignment"""
3098 self._DoReadFile('131_pack_align_section.dts')
3099
3100 self.assertIn('image', control.images)
3101 image = control.images['image']
3102 entries = image.GetEntries()
3103 self.assertEqual(3, len(entries))
3104
3105 # First u-boot
3106 self.assertIn('u-boot', entries)
3107 entry = entries['u-boot']
3108 self.assertEqual(0, entry.offset)
3109 self.assertEqual(0, entry.image_pos)
3110 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3111 self.assertEqual(len(U_BOOT_DATA), entry.size)
3112
3113 # Section0
3114 self.assertIn('section0', entries)
3115 section0 = entries['section0']
3116 self.assertEqual(0x10, section0.offset)
3117 self.assertEqual(0x10, section0.image_pos)
3118 self.assertEqual(len(U_BOOT_DATA), section0.size)
3119
3120 # Second u-boot
3121 section_entries = section0.GetEntries()
3122 self.assertIn('u-boot', section_entries)
3123 entry = section_entries['u-boot']
3124 self.assertEqual(0, entry.offset)
3125 self.assertEqual(0x10, entry.image_pos)
3126 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3127 self.assertEqual(len(U_BOOT_DATA), entry.size)
3128
3129 # Section1
3130 self.assertIn('section1', entries)
3131 section1 = entries['section1']
3132 self.assertEqual(0x14, section1.offset)
3133 self.assertEqual(0x14, section1.image_pos)
3134 self.assertEqual(0x20, section1.size)
3135
3136 # Second u-boot
3137 section_entries = section1.GetEntries()
3138 self.assertIn('u-boot', section_entries)
3139 entry = section_entries['u-boot']
3140 self.assertEqual(0, entry.offset)
3141 self.assertEqual(0x14, entry.image_pos)
3142 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3143 self.assertEqual(len(U_BOOT_DATA), entry.size)
3144
3145 # Section2
3146 self.assertIn('section2', section_entries)
3147 section2 = section_entries['section2']
3148 self.assertEqual(0x4, section2.offset)
3149 self.assertEqual(0x18, section2.image_pos)
3150 self.assertEqual(4, section2.size)
3151
3152 # Third u-boot
3153 section_entries = section2.GetEntries()
3154 self.assertIn('u-boot', section_entries)
3155 entry = section_entries['u-boot']
3156 self.assertEqual(0, entry.offset)
3157 self.assertEqual(0x18, entry.image_pos)
3158 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3159 self.assertEqual(len(U_BOOT_DATA), entry.size)
3160
Simon Glass51014aa2019-07-20 12:23:56 -06003161 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3162 dts='132_replace.dts'):
Simon Glass10f9d002019-07-20 12:23:50 -06003163 """Replace an entry in an image
3164
3165 This writes the entry data to update it, then opens the updated file and
3166 returns the value that it now finds there.
3167
3168 Args:
3169 entry_name: Entry name to replace
3170 data: Data to replace it with
3171 decomp: True to compress the data if needed, False if data is
3172 already compressed so should be used as is
Simon Glass51014aa2019-07-20 12:23:56 -06003173 allow_resize: True to allow entries to change size, False to raise
3174 an exception
Simon Glass10f9d002019-07-20 12:23:50 -06003175
3176 Returns:
3177 Tuple:
3178 data from entry
3179 data from fdtmap (excluding header)
Simon Glass51014aa2019-07-20 12:23:56 -06003180 Image object that was modified
Simon Glass10f9d002019-07-20 12:23:50 -06003181 """
Simon Glass51014aa2019-07-20 12:23:56 -06003182 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass10f9d002019-07-20 12:23:50 -06003183 update_dtb=True)[1]
3184
3185 self.assertIn('image', control.images)
3186 image = control.images['image']
3187 entries = image.GetEntries()
3188 orig_dtb_data = entries['u-boot-dtb'].data
3189 orig_fdtmap_data = entries['fdtmap'].data
3190
Simon Glassc1aa66e2022-01-29 14:14:04 -07003191 image_fname = tools.get_output_filename('image.bin')
3192 updated_fname = tools.get_output_filename('image-updated.bin')
3193 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glass51014aa2019-07-20 12:23:56 -06003194 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3195 allow_resize)
Simon Glass10f9d002019-07-20 12:23:50 -06003196 data = control.ReadEntry(updated_fname, entry_name, decomp)
3197
Simon Glass51014aa2019-07-20 12:23:56 -06003198 # The DT data should not change unless resized:
3199 if not allow_resize:
3200 new_dtb_data = entries['u-boot-dtb'].data
3201 self.assertEqual(new_dtb_data, orig_dtb_data)
3202 new_fdtmap_data = entries['fdtmap'].data
3203 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass10f9d002019-07-20 12:23:50 -06003204
Simon Glass51014aa2019-07-20 12:23:56 -06003205 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass10f9d002019-07-20 12:23:50 -06003206
3207 def testReplaceSimple(self):
3208 """Test replacing a single file"""
3209 expected = b'x' * len(U_BOOT_DATA)
Simon Glass51014aa2019-07-20 12:23:56 -06003210 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3211 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06003212 self.assertEqual(expected, data)
3213
3214 # Test that the state looks right. There should be an FDT for the fdtmap
3215 # that we jsut read back in, and it should match what we find in the
3216 # 'control' tables. Checking for an FDT that does not exist should
3217 # return None.
3218 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glass51014aa2019-07-20 12:23:56 -06003219 self.assertIsNotNone(path)
Simon Glass10f9d002019-07-20 12:23:50 -06003220 self.assertEqual(expected_fdtmap, fdtmap)
3221
3222 dtb = state.GetFdtForEtype('fdtmap')
3223 self.assertEqual(dtb.GetContents(), fdtmap)
3224
3225 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3226 self.assertIsNone(missing_path)
3227 self.assertIsNone(missing_fdtmap)
3228
3229 missing_dtb = state.GetFdtForEtype('missing')
3230 self.assertIsNone(missing_dtb)
3231
3232 self.assertEqual('/binman', state.fdt_path_prefix)
3233
3234 def testReplaceResizeFail(self):
3235 """Test replacing a file by something larger"""
3236 expected = U_BOOT_DATA + b'x'
3237 with self.assertRaises(ValueError) as e:
Simon Glass51014aa2019-07-20 12:23:56 -06003238 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3239 dts='139_replace_repack.dts')
Simon Glass10f9d002019-07-20 12:23:50 -06003240 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3241 str(e.exception))
3242
3243 def testReplaceMulti(self):
3244 """Test replacing entry data where multiple images are generated"""
3245 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3246 update_dtb=True)[0]
3247 expected = b'x' * len(U_BOOT_DATA)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003248 updated_fname = tools.get_output_filename('image-updated.bin')
3249 tools.write_file(updated_fname, data)
Simon Glass10f9d002019-07-20 12:23:50 -06003250 entry_name = 'u-boot'
Simon Glass51014aa2019-07-20 12:23:56 -06003251 control.WriteEntry(updated_fname, entry_name, expected,
3252 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06003253 data = control.ReadEntry(updated_fname, entry_name)
3254 self.assertEqual(expected, data)
3255
3256 # Check the state looks right.
3257 self.assertEqual('/binman/image', state.fdt_path_prefix)
3258
3259 # Now check we can write the first image
Simon Glassc1aa66e2022-01-29 14:14:04 -07003260 image_fname = tools.get_output_filename('first-image.bin')
3261 updated_fname = tools.get_output_filename('first-updated.bin')
3262 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glass10f9d002019-07-20 12:23:50 -06003263 entry_name = 'u-boot'
Simon Glass51014aa2019-07-20 12:23:56 -06003264 control.WriteEntry(updated_fname, entry_name, expected,
3265 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06003266 data = control.ReadEntry(updated_fname, entry_name)
3267 self.assertEqual(expected, data)
3268
3269 # Check the state looks right.
3270 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass8beb11e2019-07-08 14:25:47 -06003271
Simon Glass12bb1a92019-07-20 12:23:51 -06003272 def testUpdateFdtAllRepack(self):
3273 """Test that all device trees are updated with offset/size info"""
3274 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3275 SECTION_SIZE = 0x300
3276 DTB_SIZE = 602
3277 FDTMAP_SIZE = 608
3278 base_expected = {
3279 'offset': 0,
3280 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3281 'image-pos': 0,
3282 'section:offset': 0,
3283 'section:size': SECTION_SIZE,
3284 'section:image-pos': 0,
3285 'section/u-boot-dtb:offset': 4,
3286 'section/u-boot-dtb:size': 636,
3287 'section/u-boot-dtb:image-pos': 4,
3288 'u-boot-spl-dtb:offset': SECTION_SIZE,
3289 'u-boot-spl-dtb:size': DTB_SIZE,
3290 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3291 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3292 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3293 'u-boot-tpl-dtb:size': DTB_SIZE,
3294 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3295 'fdtmap:size': FDTMAP_SIZE,
3296 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3297 }
3298 main_expected = {
3299 'section:orig-size': SECTION_SIZE,
3300 'section/u-boot-dtb:orig-offset': 4,
3301 }
3302
3303 # We expect three device-tree files in the output, with the first one
3304 # within a fixed-size section.
3305 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3306 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3307 # main U-Boot tree. All three should have the same positions and offset
3308 # except that the main tree should include the main_expected properties
3309 start = 4
3310 for item in ['', 'spl', 'tpl', None]:
3311 if item is None:
3312 start += 16 # Move past fdtmap header
3313 dtb = fdt.Fdt.FromData(data[start:])
3314 dtb.Scan()
3315 props = self._GetPropTree(dtb,
3316 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3317 prefix='/' if item is None else '/binman/')
3318 expected = dict(base_expected)
3319 if item:
3320 expected[item] = 0
3321 else:
3322 # Main DTB and fdtdec should include the 'orig-' properties
3323 expected.update(main_expected)
3324 # Helpful for debugging:
3325 #for prop in sorted(props):
3326 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3327 self.assertEqual(expected, props)
3328 if item == '':
3329 start = SECTION_SIZE
3330 else:
3331 start += dtb._fdt_obj.totalsize()
3332
Simon Glasseba1f0c2019-07-20 12:23:55 -06003333 def testFdtmapHeaderMiddle(self):
3334 """Test an FDT map in the middle of an image when it should be at end"""
3335 with self.assertRaises(ValueError) as e:
3336 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3337 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3338 str(e.exception))
3339
3340 def testFdtmapHeaderStartBad(self):
3341 """Test an FDT map in middle of an image when it should be at start"""
3342 with self.assertRaises(ValueError) as e:
3343 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3344 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3345 str(e.exception))
3346
3347 def testFdtmapHeaderEndBad(self):
3348 """Test an FDT map at the start of an image when it should be at end"""
3349 with self.assertRaises(ValueError) as e:
3350 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3351 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3352 str(e.exception))
3353
3354 def testFdtmapHeaderNoSize(self):
3355 """Test an image header at the end of an image with undefined size"""
3356 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3357
Simon Glass51014aa2019-07-20 12:23:56 -06003358 def testReplaceResize(self):
3359 """Test replacing a single file in an entry with a larger file"""
3360 expected = U_BOOT_DATA + b'x'
3361 data, _, image = self._RunReplaceCmd('u-boot', expected,
3362 dts='139_replace_repack.dts')
3363 self.assertEqual(expected, data)
3364
3365 entries = image.GetEntries()
3366 dtb_data = entries['u-boot-dtb'].data
3367 dtb = fdt.Fdt.FromData(dtb_data)
3368 dtb.Scan()
3369
3370 # The u-boot section should now be larger in the dtb
3371 node = dtb.GetNode('/binman/u-boot')
3372 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3373
3374 # Same for the fdtmap
3375 fdata = entries['fdtmap'].data
3376 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3377 fdtb.Scan()
3378 fnode = fdtb.GetNode('/u-boot')
3379 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3380
3381 def testReplaceResizeNoRepack(self):
3382 """Test replacing an entry with a larger file when not allowed"""
3383 expected = U_BOOT_DATA + b'x'
3384 with self.assertRaises(ValueError) as e:
3385 self._RunReplaceCmd('u-boot', expected)
3386 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3387 str(e.exception))
3388
Simon Glass61ec04f2019-07-20 12:23:58 -06003389 def testEntryShrink(self):
3390 """Test contracting an entry after it is packed"""
3391 try:
3392 state.SetAllowEntryContraction(True)
3393 data = self._DoReadFileDtb('140_entry_shrink.dts',
3394 update_dtb=True)[0]
3395 finally:
3396 state.SetAllowEntryContraction(False)
3397 self.assertEqual(b'a', data[:1])
3398 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3399 self.assertEqual(b'a', data[-1:])
3400
3401 def testEntryShrinkFail(self):
3402 """Test not being allowed to contract an entry after it is packed"""
3403 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3404
3405 # In this case there is a spare byte at the end of the data. The size of
3406 # the contents is only 1 byte but we still have the size before it
3407 # shrunk.
3408 self.assertEqual(b'a\0', data[:2])
3409 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3410 self.assertEqual(b'a\0', data[-2:])
3411
Simon Glass27145fd2019-07-20 12:24:01 -06003412 def testDescriptorOffset(self):
3413 """Test that the Intel descriptor is always placed at at the start"""
3414 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3415 image = control.images['image']
3416 entries = image.GetEntries()
3417 desc = entries['intel-descriptor']
3418 self.assertEqual(0xff800000, desc.offset);
3419 self.assertEqual(0xff800000, desc.image_pos);
3420
Simon Glasseb0f4a42019-07-20 12:24:06 -06003421 def testReplaceCbfs(self):
3422 """Test replacing a single file in CBFS without changing the size"""
3423 self._CheckLz4()
3424 expected = b'x' * len(U_BOOT_DATA)
3425 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003426 updated_fname = tools.get_output_filename('image-updated.bin')
3427 tools.write_file(updated_fname, data)
Simon Glasseb0f4a42019-07-20 12:24:06 -06003428 entry_name = 'section/cbfs/u-boot'
3429 control.WriteEntry(updated_fname, entry_name, expected,
3430 allow_resize=True)
3431 data = control.ReadEntry(updated_fname, entry_name)
3432 self.assertEqual(expected, data)
3433
3434 def testReplaceResizeCbfs(self):
3435 """Test replacing a single file in CBFS with one of a different size"""
3436 self._CheckLz4()
3437 expected = U_BOOT_DATA + b'x'
3438 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003439 updated_fname = tools.get_output_filename('image-updated.bin')
3440 tools.write_file(updated_fname, data)
Simon Glasseb0f4a42019-07-20 12:24:06 -06003441 entry_name = 'section/cbfs/u-boot'
3442 control.WriteEntry(updated_fname, entry_name, expected,
3443 allow_resize=True)
3444 data = control.ReadEntry(updated_fname, entry_name)
3445 self.assertEqual(expected, data)
3446
Simon Glassa6cb9952019-07-20 12:24:15 -06003447 def _SetupForReplace(self):
3448 """Set up some files to use to replace entries
3449
3450 This generates an image, copies it to a new file, extracts all the files
3451 in it and updates some of them
3452
3453 Returns:
3454 List
3455 Image filename
3456 Output directory
3457 Expected values for updated entries, each a string
3458 """
3459 data = self._DoReadFileRealDtb('143_replace_all.dts')
3460
Simon Glassc1aa66e2022-01-29 14:14:04 -07003461 updated_fname = tools.get_output_filename('image-updated.bin')
3462 tools.write_file(updated_fname, data)
Simon Glassa6cb9952019-07-20 12:24:15 -06003463
3464 outdir = os.path.join(self._indir, 'extract')
3465 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3466
3467 expected1 = b'x' + U_BOOT_DATA + b'y'
3468 u_boot_fname1 = os.path.join(outdir, 'u-boot')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003469 tools.write_file(u_boot_fname1, expected1)
Simon Glassa6cb9952019-07-20 12:24:15 -06003470
3471 expected2 = b'a' + U_BOOT_DATA + b'b'
3472 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003473 tools.write_file(u_boot_fname2, expected2)
Simon Glassa6cb9952019-07-20 12:24:15 -06003474
3475 expected_text = b'not the same text'
3476 text_fname = os.path.join(outdir, 'text')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003477 tools.write_file(text_fname, expected_text)
Simon Glassa6cb9952019-07-20 12:24:15 -06003478
3479 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3480 dtb = fdt.FdtScan(dtb_fname)
3481 node = dtb.GetNode('/binman/text')
3482 node.AddString('my-property', 'the value')
3483 dtb.Sync(auto_resize=True)
3484 dtb.Flush()
3485
3486 return updated_fname, outdir, expected1, expected2, expected_text
3487
3488 def _CheckReplaceMultiple(self, entry_paths):
3489 """Handle replacing the contents of multiple entries
3490
3491 Args:
3492 entry_paths: List of entry paths to replace
3493
3494 Returns:
3495 List
3496 Dict of entries in the image:
3497 key: Entry name
3498 Value: Entry object
3499 Expected values for updated entries, each a string
3500 """
3501 updated_fname, outdir, expected1, expected2, expected_text = (
3502 self._SetupForReplace())
3503 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3504
3505 image = Image.FromFile(updated_fname)
3506 image.LoadData()
3507 return image.GetEntries(), expected1, expected2, expected_text
3508
3509 def testReplaceAll(self):
3510 """Test replacing the contents of all entries"""
3511 entries, expected1, expected2, expected_text = (
3512 self._CheckReplaceMultiple([]))
3513 data = entries['u-boot'].data
3514 self.assertEqual(expected1, data)
3515
3516 data = entries['u-boot2'].data
3517 self.assertEqual(expected2, data)
3518
3519 data = entries['text'].data
3520 self.assertEqual(expected_text, data)
3521
3522 # Check that the device tree is updated
3523 data = entries['u-boot-dtb'].data
3524 dtb = fdt.Fdt.FromData(data)
3525 dtb.Scan()
3526 node = dtb.GetNode('/binman/text')
3527 self.assertEqual('the value', node.props['my-property'].value)
3528
3529 def testReplaceSome(self):
3530 """Test replacing the contents of a few entries"""
3531 entries, expected1, expected2, expected_text = (
3532 self._CheckReplaceMultiple(['u-boot2', 'text']))
3533
3534 # This one should not change
3535 data = entries['u-boot'].data
3536 self.assertEqual(U_BOOT_DATA, data)
3537
3538 data = entries['u-boot2'].data
3539 self.assertEqual(expected2, data)
3540
3541 data = entries['text'].data
3542 self.assertEqual(expected_text, data)
3543
3544 def testReplaceCmd(self):
3545 """Test replacing a file fron an image on the command line"""
3546 self._DoReadFileRealDtb('143_replace_all.dts')
3547
3548 try:
3549 tmpdir, updated_fname = self._SetupImageInTmpdir()
3550
3551 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3552 expected = b'x' * len(U_BOOT_DATA)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003553 tools.write_file(fname, expected)
Simon Glassa6cb9952019-07-20 12:24:15 -06003554
3555 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003556 data = tools.read_file(updated_fname)
Simon Glassa6cb9952019-07-20 12:24:15 -06003557 self.assertEqual(expected, data[:len(expected)])
3558 map_fname = os.path.join(tmpdir, 'image-updated.map')
3559 self.assertFalse(os.path.exists(map_fname))
3560 finally:
3561 shutil.rmtree(tmpdir)
3562
3563 def testReplaceCmdSome(self):
3564 """Test replacing some files fron an image on the command line"""
3565 updated_fname, outdir, expected1, expected2, expected_text = (
3566 self._SetupForReplace())
3567
3568 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3569 'u-boot2', 'text')
3570
Simon Glassc1aa66e2022-01-29 14:14:04 -07003571 tools.prepare_output_dir(None)
Simon Glassa6cb9952019-07-20 12:24:15 -06003572 image = Image.FromFile(updated_fname)
3573 image.LoadData()
3574 entries = image.GetEntries()
3575
3576 # This one should not change
3577 data = entries['u-boot'].data
3578 self.assertEqual(U_BOOT_DATA, data)
3579
3580 data = entries['u-boot2'].data
3581 self.assertEqual(expected2, data)
3582
3583 data = entries['text'].data
3584 self.assertEqual(expected_text, data)
3585
3586 def testReplaceMissing(self):
3587 """Test replacing entries where the file is missing"""
3588 updated_fname, outdir, expected1, expected2, expected_text = (
3589 self._SetupForReplace())
3590
3591 # Remove one of the files, to generate a warning
3592 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3593 os.remove(u_boot_fname1)
3594
3595 with test_util.capture_sys_output() as (stdout, stderr):
3596 control.ReplaceEntries(updated_fname, None, outdir, [])
3597 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass38fdb4c2020-07-09 18:39:39 -06003598 stderr.getvalue())
Simon Glassa6cb9952019-07-20 12:24:15 -06003599
3600 def testReplaceCmdMap(self):
3601 """Test replacing a file fron an image on the command line"""
3602 self._DoReadFileRealDtb('143_replace_all.dts')
3603
3604 try:
3605 tmpdir, updated_fname = self._SetupImageInTmpdir()
3606
3607 fname = os.path.join(self._indir, 'update-u-boot.bin')
3608 expected = b'x' * len(U_BOOT_DATA)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003609 tools.write_file(fname, expected)
Simon Glassa6cb9952019-07-20 12:24:15 -06003610
3611 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3612 '-f', fname, '-m')
3613 map_fname = os.path.join(tmpdir, 'image-updated.map')
3614 self.assertTrue(os.path.exists(map_fname))
3615 finally:
3616 shutil.rmtree(tmpdir)
3617
3618 def testReplaceNoEntryPaths(self):
3619 """Test replacing an entry without an entry path"""
3620 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003621 image_fname = tools.get_output_filename('image.bin')
Simon Glassa6cb9952019-07-20 12:24:15 -06003622 with self.assertRaises(ValueError) as e:
3623 control.ReplaceEntries(image_fname, 'fname', None, [])
3624 self.assertIn('Must specify an entry path to read with -f',
3625 str(e.exception))
3626
3627 def testReplaceTooManyEntryPaths(self):
3628 """Test extracting some entries"""
3629 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003630 image_fname = tools.get_output_filename('image.bin')
Simon Glassa6cb9952019-07-20 12:24:15 -06003631 with self.assertRaises(ValueError) as e:
3632 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3633 self.assertIn('Must specify exactly one entry path to write with -f',
3634 str(e.exception))
3635
Simon Glass2250ee62019-08-24 07:22:48 -06003636 def testPackReset16(self):
3637 """Test that an image with an x86 reset16 region can be created"""
3638 data = self._DoReadFile('144_x86_reset16.dts')
3639 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3640
3641 def testPackReset16Spl(self):
3642 """Test that an image with an x86 reset16-spl region can be created"""
3643 data = self._DoReadFile('145_x86_reset16_spl.dts')
3644 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3645
3646 def testPackReset16Tpl(self):
3647 """Test that an image with an x86 reset16-tpl region can be created"""
3648 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3649 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3650
Simon Glass5af12072019-08-24 07:22:50 -06003651 def testPackIntelFit(self):
3652 """Test that an image with an Intel FIT and pointer can be created"""
3653 data = self._DoReadFile('147_intel_fit.dts')
3654 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3655 fit = data[16:32];
3656 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3657 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3658
3659 image = control.images['image']
3660 entries = image.GetEntries()
3661 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3662 self.assertEqual(expected_ptr, ptr)
3663
3664 def testPackIntelFitMissing(self):
3665 """Test detection of a FIT pointer with not FIT region"""
3666 with self.assertRaises(ValueError) as e:
3667 self._DoReadFile('148_intel_fit_missing.dts')
3668 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3669 str(e.exception))
3670
Simon Glass7c150132019-11-06 17:22:44 -07003671 def _CheckSymbolsTplSection(self, dts, expected_vals):
3672 data = self._DoReadFile(dts)
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003673 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE, *expected_vals)
Simon Glass2090f1e2019-08-24 07:23:00 -06003674 upto1 = 4 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003675 expected1 = tools.get_bytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass2090f1e2019-08-24 07:23:00 -06003676 self.assertEqual(expected1, data[:upto1])
3677
3678 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003679 expected2 = tools.get_bytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass2090f1e2019-08-24 07:23:00 -06003680 self.assertEqual(expected2, data[upto1:upto2])
3681
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003682 upto3 = 0x3c + len(U_BOOT_DATA)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003683 expected3 = tools.get_bytes(0xff, 1) + U_BOOT_DATA
Simon Glass2090f1e2019-08-24 07:23:00 -06003684 self.assertEqual(expected3, data[upto2:upto3])
3685
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003686 expected4 = sym_values + U_BOOT_TPL_DATA[24:]
Simon Glass7c150132019-11-06 17:22:44 -07003687 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3688
3689 def testSymbolsTplSection(self):
3690 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3691 self._SetupSplElf('u_boot_binman_syms')
3692 self._SetupTplElf('u_boot_binman_syms')
3693 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003694 [0x04, 0x20, 0x10 + 0x3c, 0x04])
Simon Glass7c150132019-11-06 17:22:44 -07003695
3696 def testSymbolsTplSectionX86(self):
3697 """Test binman can assign symbols in a section with end-at-4gb"""
3698 self._SetupSplElf('u_boot_binman_syms_x86')
3699 self._SetupTplElf('u_boot_binman_syms_x86')
3700 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003701 [0xffffff04, 0xffffff20, 0xffffff3c,
Simon Glass7c150132019-11-06 17:22:44 -07003702 0x04])
Simon Glass2090f1e2019-08-24 07:23:00 -06003703
Simon Glassbf4d0e22019-08-24 07:23:03 -06003704 def testPackX86RomIfwiSectiom(self):
3705 """Test that a section can be placed in an IFWI region"""
3706 self._SetupIfwi('fitimage.bin')
3707 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3708 self._CheckIfwi(data)
3709
Simon Glassea0fff92019-08-24 07:23:07 -06003710 def testPackFspM(self):
3711 """Test that an image with a FSP memory-init binary can be created"""
3712 data = self._DoReadFile('152_intel_fsp_m.dts')
3713 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3714
Simon Glassbc6a88f2019-10-20 21:31:35 -06003715 def testPackFspS(self):
3716 """Test that an image with a FSP silicon-init binary can be created"""
3717 data = self._DoReadFile('153_intel_fsp_s.dts')
3718 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassea0fff92019-08-24 07:23:07 -06003719
Simon Glass998d1482019-10-20 21:31:36 -06003720 def testPackFspT(self):
3721 """Test that an image with a FSP temp-ram-init binary can be created"""
3722 data = self._DoReadFile('154_intel_fsp_t.dts')
3723 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3724
Simon Glass0dc706f2020-07-09 18:39:31 -06003725 def testMkimage(self):
3726 """Test using mkimage to build an image"""
3727 data = self._DoReadFile('156_mkimage.dts')
3728
3729 # Just check that the data appears in the file somewhere
3730 self.assertIn(U_BOOT_SPL_DATA, data)
3731
Simon Glass4f9ee832022-01-09 20:14:09 -07003732 def testMkimageMissing(self):
3733 """Test that binman still produces an image if mkimage is missing"""
3734 with test_util.capture_sys_output() as (_, stderr):
3735 self._DoTestFile('156_mkimage.dts',
3736 force_missing_bintools='mkimage')
3737 err = stderr.getvalue()
3738 self.assertRegex(err,
3739 "Image 'main-section'.*missing bintools.*: mkimage")
3740
Simon Glassce867ad2020-07-09 18:39:36 -06003741 def testExtblob(self):
3742 """Test an image with an external blob"""
3743 data = self._DoReadFile('157_blob_ext.dts')
3744 self.assertEqual(REFCODE_DATA, data)
3745
3746 def testExtblobMissing(self):
3747 """Test an image with a missing external blob"""
3748 with self.assertRaises(ValueError) as e:
3749 self._DoReadFile('158_blob_ext_missing.dts')
3750 self.assertIn("Filename 'missing-file' not found in input path",
3751 str(e.exception))
3752
Simon Glass4f9f1052020-07-09 18:39:38 -06003753 def testExtblobMissingOk(self):
3754 """Test an image with an missing external blob that is allowed"""
Simon Glassb1cca952020-07-09 18:39:40 -06003755 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glassb38da152022-11-09 19:14:42 -07003756 ret = self._DoTestFile('158_blob_ext_missing.dts',
3757 allow_missing=True)
3758 self.assertEqual(103, ret)
Simon Glassb1cca952020-07-09 18:39:40 -06003759 err = stderr.getvalue()
3760 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
Simon Glassb38da152022-11-09 19:14:42 -07003761 self.assertIn('Some images are invalid', err)
3762
3763 def testExtblobMissingOkFlag(self):
3764 """Test an image with an missing external blob allowed with -W"""
3765 with test_util.capture_sys_output() as (stdout, stderr):
3766 ret = self._DoTestFile('158_blob_ext_missing.dts',
3767 allow_missing=True, ignore_missing=True)
3768 self.assertEqual(0, ret)
3769 err = stderr.getvalue()
3770 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
3771 self.assertIn('Some images are invalid', err)
Simon Glassb1cca952020-07-09 18:39:40 -06003772
3773 def testExtblobMissingOkSect(self):
3774 """Test an image with an missing external blob that is allowed"""
3775 with test_util.capture_sys_output() as (stdout, stderr):
3776 self._DoTestFile('159_blob_ext_missing_sect.dts',
3777 allow_missing=True)
3778 err = stderr.getvalue()
3779 self.assertRegex(err, "Image 'main-section'.*missing.*: "
3780 "blob-ext blob-ext2")
Simon Glass4f9f1052020-07-09 18:39:38 -06003781
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003782 def testPackX86RomMeMissingDesc(self):
3783 """Test that an missing Intel descriptor entry is allowed"""
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003784 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass52b10dd2020-07-25 15:11:19 -06003785 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003786 err = stderr.getvalue()
3787 self.assertRegex(err,
3788 "Image 'main-section'.*missing.*: intel-descriptor")
3789
3790 def testPackX86RomMissingIfwi(self):
3791 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3792 self._SetupIfwi('fitimage.bin')
3793 pathname = os.path.join(self._indir, 'fitimage.bin')
3794 os.remove(pathname)
3795 with test_util.capture_sys_output() as (stdout, stderr):
3796 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3797 err = stderr.getvalue()
3798 self.assertRegex(err, "Image 'main-section'.*missing.*: intel-ifwi")
3799
Simon Glass8d2ef3e2022-02-11 13:23:21 -07003800 def testPackOverlapZero(self):
Simon Glassb3295fd2020-07-09 18:39:42 -06003801 """Test that zero-size overlapping regions are ignored"""
3802 self._DoTestFile('160_pack_overlap_zero.dts')
3803
Alper Nebi Yasak21353312022-02-08 01:08:04 +03003804 def _CheckSimpleFitData(self, fit_data, kernel_data, fdt1_data):
Simon Glassfdc34362020-07-09 18:39:45 -06003805 # The data should be inside the FIT
3806 dtb = fdt.Fdt.FromData(fit_data)
3807 dtb.Scan()
3808 fnode = dtb.GetNode('/images/kernel')
3809 self.assertIn('data', fnode.props)
3810
3811 fname = os.path.join(self._indir, 'fit_data.fit')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003812 tools.write_file(fname, fit_data)
3813 out = tools.run('dumpimage', '-l', fname)
Simon Glassfdc34362020-07-09 18:39:45 -06003814
3815 # Check a few features to make sure the plumbing works. We don't need
3816 # to test the operation of mkimage or dumpimage here. First convert the
3817 # output into a dict where the keys are the fields printed by dumpimage
3818 # and the values are a list of values for each field
3819 lines = out.splitlines()
3820
3821 # Converts "Compression: gzip compressed" into two groups:
3822 # 'Compression' and 'gzip compressed'
3823 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3824 vals = collections.defaultdict(list)
3825 for line in lines:
3826 mat = re_line.match(line)
3827 vals[mat.group(1)].append(mat.group(2))
3828
3829 self.assertEquals('FIT description: test-desc', lines[0])
3830 self.assertIn('Created:', lines[1])
3831 self.assertIn('Image 0 (kernel)', vals)
3832 self.assertIn('Hash value', vals)
3833 data_sizes = vals.get('Data Size')
3834 self.assertIsNotNone(data_sizes)
3835 self.assertEqual(2, len(data_sizes))
3836 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
Alper Nebi Yasak21353312022-02-08 01:08:04 +03003837 self.assertEqual(len(kernel_data), int(data_sizes[0].split()[0]))
3838 self.assertEqual(len(fdt1_data), int(data_sizes[1].split()[0]))
3839
Alper Nebi Yasake7368782022-03-27 18:31:47 +03003840 # Check if entry listing correctly omits /images/
3841 image = control.images['image']
3842 fit_entry = image.GetEntries()['fit']
3843 subentries = list(fit_entry.GetEntries().keys())
3844 expected = ['kernel', 'fdt-1']
3845 self.assertEqual(expected, subentries)
3846
Alper Nebi Yasak21353312022-02-08 01:08:04 +03003847 def testSimpleFit(self):
3848 """Test an image with a FIT inside"""
3849 data = self._DoReadFile('161_fit.dts')
3850 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3851 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3852 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3853
3854 self._CheckSimpleFitData(fit_data, U_BOOT_DATA, U_BOOT_SPL_DTB_DATA)
3855
3856 def testSimpleFitExpandsSubentries(self):
3857 """Test that FIT images expand their subentries"""
3858 data = self._DoReadFileDtb('161_fit.dts', use_expanded=True)[0]
3859 self.assertEqual(U_BOOT_EXP_DATA, data[:len(U_BOOT_EXP_DATA)])
3860 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3861 fit_data = data[len(U_BOOT_EXP_DATA):-len(U_BOOT_NODTB_DATA)]
3862
3863 self._CheckSimpleFitData(fit_data, U_BOOT_EXP_DATA, U_BOOT_SPL_DTB_DATA)
Simon Glassfdc34362020-07-09 18:39:45 -06003864
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003865 def testSimpleFitImagePos(self):
3866 """Test that we have correct image-pos for FIT subentries"""
3867 data, _, _, out_dtb_fname = self._DoReadFileDtb('161_fit.dts',
3868 update_dtb=True)
3869 dtb = fdt.Fdt(out_dtb_fname)
3870 dtb.Scan()
3871 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3872
Simon Glass38397d02022-03-05 20:19:01 -07003873 self.maxDiff = None
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003874 self.assertEqual({
3875 'image-pos': 0,
3876 'offset': 0,
3877 'size': 1890,
3878
3879 'u-boot:image-pos': 0,
3880 'u-boot:offset': 0,
3881 'u-boot:size': 4,
3882
3883 'fit:image-pos': 4,
3884 'fit:offset': 4,
3885 'fit:size': 1840,
3886
Simon Glass38397d02022-03-05 20:19:01 -07003887 'fit/images/kernel:image-pos': 304,
3888 'fit/images/kernel:offset': 300,
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003889 'fit/images/kernel:size': 4,
3890
Simon Glass38397d02022-03-05 20:19:01 -07003891 'fit/images/kernel/u-boot:image-pos': 304,
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003892 'fit/images/kernel/u-boot:offset': 0,
3893 'fit/images/kernel/u-boot:size': 4,
3894
Simon Glass38397d02022-03-05 20:19:01 -07003895 'fit/images/fdt-1:image-pos': 552,
3896 'fit/images/fdt-1:offset': 548,
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003897 'fit/images/fdt-1:size': 6,
3898
Simon Glass38397d02022-03-05 20:19:01 -07003899 'fit/images/fdt-1/u-boot-spl-dtb:image-pos': 552,
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003900 'fit/images/fdt-1/u-boot-spl-dtb:offset': 0,
3901 'fit/images/fdt-1/u-boot-spl-dtb:size': 6,
3902
3903 'u-boot-nodtb:image-pos': 1844,
3904 'u-boot-nodtb:offset': 1844,
3905 'u-boot-nodtb:size': 46,
3906 }, props)
3907
3908 # Actually check the data is where we think it is
3909 for node, expected in [
3910 ("u-boot", U_BOOT_DATA),
3911 ("fit/images/kernel", U_BOOT_DATA),
3912 ("fit/images/kernel/u-boot", U_BOOT_DATA),
3913 ("fit/images/fdt-1", U_BOOT_SPL_DTB_DATA),
3914 ("fit/images/fdt-1/u-boot-spl-dtb", U_BOOT_SPL_DTB_DATA),
3915 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
3916 ]:
3917 image_pos = props[f"{node}:image-pos"]
3918 size = props[f"{node}:size"]
3919 self.assertEqual(len(expected), size)
3920 self.assertEqual(expected, data[image_pos:image_pos+size])
3921
Simon Glassfdc34362020-07-09 18:39:45 -06003922 def testFitExternal(self):
Simon Glasse9d336d2020-09-01 05:13:55 -06003923 """Test an image with an FIT with external images"""
Simon Glassfdc34362020-07-09 18:39:45 -06003924 data = self._DoReadFile('162_fit_external.dts')
3925 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3926
Simon Glass8bc78b72022-01-09 20:13:39 -07003927 # Size of the external-data region as set up by mkimage
3928 external_data_size = len(U_BOOT_DATA) + 2
3929 expected_size = (len(U_BOOT_DATA) + 0x400 +
Simon Glassc1aa66e2022-01-29 14:14:04 -07003930 tools.align(external_data_size, 4) +
Simon Glass8bc78b72022-01-09 20:13:39 -07003931 len(U_BOOT_NODTB_DATA))
3932
Simon Glassfdc34362020-07-09 18:39:45 -06003933 # The data should be outside the FIT
3934 dtb = fdt.Fdt.FromData(fit_data)
3935 dtb.Scan()
3936 fnode = dtb.GetNode('/images/kernel')
3937 self.assertNotIn('data', fnode.props)
Simon Glass8bc78b72022-01-09 20:13:39 -07003938 self.assertEqual(len(U_BOOT_DATA),
3939 fdt_util.fdt32_to_cpu(fnode.props['data-size'].value))
3940 fit_pos = 0x400;
3941 self.assertEqual(
3942 fit_pos,
3943 fdt_util.fdt32_to_cpu(fnode.props['data-position'].value))
3944
3945 self.assertEquals(expected_size, len(data))
3946 actual_pos = len(U_BOOT_DATA) + fit_pos
3947 self.assertEqual(U_BOOT_DATA + b'aa',
3948 data[actual_pos:actual_pos + external_data_size])
Simon Glass12bb1a92019-07-20 12:23:51 -06003949
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003950 def testFitExternalImagePos(self):
3951 """Test that we have correct image-pos for external FIT subentries"""
3952 data, _, _, out_dtb_fname = self._DoReadFileDtb('162_fit_external.dts',
3953 update_dtb=True)
3954 dtb = fdt.Fdt(out_dtb_fname)
3955 dtb.Scan()
3956 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3957
3958 self.assertEqual({
3959 'image-pos': 0,
3960 'offset': 0,
3961 'size': 1082,
3962
3963 'u-boot:image-pos': 0,
3964 'u-boot:offset': 0,
3965 'u-boot:size': 4,
3966
3967 'fit:size': 1032,
3968 'fit:offset': 4,
3969 'fit:image-pos': 4,
3970
3971 'fit/images/kernel:size': 4,
3972 'fit/images/kernel:offset': 1024,
3973 'fit/images/kernel:image-pos': 1028,
3974
3975 'fit/images/kernel/u-boot:size': 4,
3976 'fit/images/kernel/u-boot:offset': 0,
3977 'fit/images/kernel/u-boot:image-pos': 1028,
3978
3979 'fit/images/fdt-1:size': 2,
3980 'fit/images/fdt-1:offset': 1028,
3981 'fit/images/fdt-1:image-pos': 1032,
3982
3983 'fit/images/fdt-1/_testing:size': 2,
3984 'fit/images/fdt-1/_testing:offset': 0,
3985 'fit/images/fdt-1/_testing:image-pos': 1032,
3986
3987 'u-boot-nodtb:image-pos': 1036,
3988 'u-boot-nodtb:offset': 1036,
3989 'u-boot-nodtb:size': 46,
3990 }, props)
3991
3992 # Actually check the data is where we think it is
3993 for node, expected in [
3994 ("u-boot", U_BOOT_DATA),
3995 ("fit/images/kernel", U_BOOT_DATA),
3996 ("fit/images/kernel/u-boot", U_BOOT_DATA),
3997 ("fit/images/fdt-1", b'aa'),
3998 ("fit/images/fdt-1/_testing", b'aa'),
3999 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
4000 ]:
4001 image_pos = props[f"{node}:image-pos"]
4002 size = props[f"{node}:size"]
4003 self.assertEqual(len(expected), size)
4004 self.assertEqual(expected, data[image_pos:image_pos+size])
4005
Simon Glass4f9ee832022-01-09 20:14:09 -07004006 def testFitMissing(self):
4007 """Test that binman still produces a FIT image if mkimage is missing"""
4008 with test_util.capture_sys_output() as (_, stderr):
4009 self._DoTestFile('162_fit_external.dts',
4010 force_missing_bintools='mkimage')
4011 err = stderr.getvalue()
4012 self.assertRegex(err,
4013 "Image 'main-section'.*missing bintools.*: mkimage")
4014
Alper Nebi Yasak8001d0b2020-08-31 12:58:18 +03004015 def testSectionIgnoreHashSignature(self):
4016 """Test that sections ignore hash, signature nodes for its data"""
4017 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
4018 expected = (U_BOOT_DATA + U_BOOT_DATA)
4019 self.assertEqual(expected, data)
4020
Alper Nebi Yasak3fdeb142020-08-31 12:58:19 +03004021 def testPadInSections(self):
4022 """Test pad-before, pad-after for entries in sections"""
Simon Glassf90d9062020-10-26 17:40:09 -06004023 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4024 '166_pad_in_sections.dts', update_dtb=True)
Simon Glassc1aa66e2022-01-29 14:14:04 -07004025 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4026 U_BOOT_DATA + tools.get_bytes(ord('!'), 6) +
Alper Nebi Yasak3fdeb142020-08-31 12:58:19 +03004027 U_BOOT_DATA)
4028 self.assertEqual(expected, data)
4029
Simon Glassf90d9062020-10-26 17:40:09 -06004030 dtb = fdt.Fdt(out_dtb_fname)
4031 dtb.Scan()
4032 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
4033 expected = {
4034 'image-pos': 0,
4035 'offset': 0,
4036 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
4037
4038 'section:image-pos': 0,
4039 'section:offset': 0,
4040 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
4041
4042 'section/before:image-pos': 0,
4043 'section/before:offset': 0,
4044 'section/before:size': len(U_BOOT_DATA),
4045
4046 'section/u-boot:image-pos': 4,
4047 'section/u-boot:offset': 4,
4048 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
4049
4050 'section/after:image-pos': 26,
4051 'section/after:offset': 26,
4052 'section/after:size': len(U_BOOT_DATA),
4053 }
4054 self.assertEqual(expected, props)
4055
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03004056 def testFitImageSubentryAlignment(self):
4057 """Test relative alignability of FIT image subentries"""
Alper Nebi Yasakf3078d42022-02-08 01:08:07 +03004058 self._SetupSplElf()
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03004059 entry_args = {
4060 'test-id': TEXT_DATA,
4061 }
4062 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
4063 entry_args=entry_args)
4064 dtb = fdt.Fdt.FromData(data)
4065 dtb.Scan()
4066
4067 node = dtb.GetNode('/images/kernel')
4068 data = dtb.GetProps(node)["data"].bytes
4069 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
Simon Glassc1aa66e2022-01-29 14:14:04 -07004070 expected = (tools.get_bytes(0, 0x20) + U_BOOT_SPL_DATA +
4071 tools.get_bytes(0, align_pad) + U_BOOT_DATA)
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03004072 self.assertEqual(expected, data)
4073
4074 node = dtb.GetNode('/images/fdt-1')
4075 data = dtb.GetProps(node)["data"].bytes
Simon Glassc1aa66e2022-01-29 14:14:04 -07004076 expected = (U_BOOT_SPL_DTB_DATA + tools.get_bytes(0, 20) +
4077 tools.to_bytes(TEXT_DATA) + tools.get_bytes(0, 30) +
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03004078 U_BOOT_DTB_DATA)
4079 self.assertEqual(expected, data)
4080
4081 def testFitExtblobMissingOk(self):
4082 """Test a FIT with a missing external blob that is allowed"""
4083 with test_util.capture_sys_output() as (stdout, stderr):
4084 self._DoTestFile('168_fit_missing_blob.dts',
4085 allow_missing=True)
4086 err = stderr.getvalue()
Simon Glassb2381432020-09-06 10:39:09 -06004087 self.assertRegex(err, "Image 'main-section'.*missing.*: atf-bl31")
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03004088
Simon Glass3decfa32020-09-01 05:13:54 -06004089 def testBlobNamedByArgMissing(self):
4090 """Test handling of a missing entry arg"""
4091 with self.assertRaises(ValueError) as e:
4092 self._DoReadFile('068_blob_named_by_arg.dts')
4093 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
4094 str(e.exception))
4095
Simon Glassdc2f81a2020-09-01 05:13:58 -06004096 def testPackBl31(self):
4097 """Test that an image with an ATF BL31 binary can be created"""
4098 data = self._DoReadFile('169_atf_bl31.dts')
4099 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
4100
Samuel Holland18bd4552020-10-21 21:12:15 -05004101 def testPackScp(self):
4102 """Test that an image with an SCP binary can be created"""
4103 data = self._DoReadFile('172_scp.dts')
4104 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
4105
Simon Glass6cf99532020-09-01 05:13:59 -06004106 def testFitFdt(self):
4107 """Test an image with an FIT with multiple FDT images"""
4108 def _CheckFdt(seq, expected_data):
4109 """Check the FDT nodes
4110
4111 Args:
4112 seq: Sequence number to check (0 or 1)
4113 expected_data: Expected contents of 'data' property
4114 """
4115 name = 'fdt-%d' % seq
4116 fnode = dtb.GetNode('/images/%s' % name)
4117 self.assertIsNotNone(fnode)
4118 self.assertEqual({'description','type', 'compression', 'data'},
4119 set(fnode.props.keys()))
4120 self.assertEqual(expected_data, fnode.props['data'].bytes)
4121 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
4122 fnode.props['description'].value)
Jan Kiszkab2106612022-02-28 17:06:20 +01004123 self.assertEqual(fnode.subnodes[0].name, 'hash')
Simon Glass6cf99532020-09-01 05:13:59 -06004124
4125 def _CheckConfig(seq, expected_data):
4126 """Check the configuration nodes
4127
4128 Args:
4129 seq: Sequence number to check (0 or 1)
4130 expected_data: Expected contents of 'data' property
4131 """
4132 cnode = dtb.GetNode('/configurations')
4133 self.assertIn('default', cnode.props)
Simon Glassc0f1ebe2020-09-06 10:39:08 -06004134 self.assertEqual('config-2', cnode.props['default'].value)
Simon Glass6cf99532020-09-01 05:13:59 -06004135
4136 name = 'config-%d' % seq
4137 fnode = dtb.GetNode('/configurations/%s' % name)
4138 self.assertIsNotNone(fnode)
4139 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
4140 set(fnode.props.keys()))
4141 self.assertEqual('conf-test-fdt%d.dtb' % seq,
4142 fnode.props['description'].value)
4143 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
4144
4145 entry_args = {
4146 'of-list': 'test-fdt1 test-fdt2',
Simon Glassc0f1ebe2020-09-06 10:39:08 -06004147 'default-dt': 'test-fdt2',
Simon Glass6cf99532020-09-01 05:13:59 -06004148 }
4149 data = self._DoReadFileDtb(
Bin Mengaa75ce92021-05-10 20:23:32 +08004150 '170_fit_fdt.dts',
Simon Glass6cf99532020-09-01 05:13:59 -06004151 entry_args=entry_args,
4152 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4153 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4154 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4155
4156 dtb = fdt.Fdt.FromData(fit_data)
4157 dtb.Scan()
4158 fnode = dtb.GetNode('/images/kernel')
4159 self.assertIn('data', fnode.props)
4160
4161 # Check all the properties in fdt-1 and fdt-2
4162 _CheckFdt(1, TEST_FDT1_DATA)
4163 _CheckFdt(2, TEST_FDT2_DATA)
4164
4165 # Check configurations
4166 _CheckConfig(1, TEST_FDT1_DATA)
4167 _CheckConfig(2, TEST_FDT2_DATA)
4168
4169 def testFitFdtMissingList(self):
4170 """Test handling of a missing 'of-list' entry arg"""
4171 with self.assertRaises(ValueError) as e:
Bin Mengaa75ce92021-05-10 20:23:32 +08004172 self._DoReadFile('170_fit_fdt.dts')
Simon Glass6cf99532020-09-01 05:13:59 -06004173 self.assertIn("Generator node requires 'of-list' entry argument",
4174 str(e.exception))
4175
4176 def testFitFdtEmptyList(self):
4177 """Test handling of an empty 'of-list' entry arg"""
4178 entry_args = {
4179 'of-list': '',
4180 }
4181 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
4182
4183 def testFitFdtMissingProp(self):
4184 """Test handling of a missing 'fit,fdt-list' property"""
4185 with self.assertRaises(ValueError) as e:
4186 self._DoReadFile('171_fit_fdt_missing_prop.dts')
4187 self.assertIn("Generator node requires 'fit,fdt-list' property",
4188 str(e.exception))
Simon Glassdc2f81a2020-09-01 05:13:58 -06004189
Simon Glassc0f1ebe2020-09-06 10:39:08 -06004190 def testFitFdtMissing(self):
4191 """Test handling of a missing 'default-dt' entry arg"""
4192 entry_args = {
4193 'of-list': 'test-fdt1 test-fdt2',
4194 }
4195 with self.assertRaises(ValueError) as e:
4196 self._DoReadFileDtb(
Bin Mengaa75ce92021-05-10 20:23:32 +08004197 '170_fit_fdt.dts',
Simon Glassc0f1ebe2020-09-06 10:39:08 -06004198 entry_args=entry_args,
4199 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4200 self.assertIn("Generated 'default' node requires default-dt entry argument",
4201 str(e.exception))
4202
4203 def testFitFdtNotInList(self):
4204 """Test handling of a default-dt that is not in the of-list"""
4205 entry_args = {
4206 'of-list': 'test-fdt1 test-fdt2',
4207 'default-dt': 'test-fdt3',
4208 }
4209 with self.assertRaises(ValueError) as e:
4210 self._DoReadFileDtb(
Bin Mengaa75ce92021-05-10 20:23:32 +08004211 '170_fit_fdt.dts',
Simon Glassc0f1ebe2020-09-06 10:39:08 -06004212 entry_args=entry_args,
4213 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4214 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
4215 str(e.exception))
4216
Simon Glassb2381432020-09-06 10:39:09 -06004217 def testFitExtblobMissingHelp(self):
4218 """Test display of help messages when an external blob is missing"""
4219 control.missing_blob_help = control._ReadMissingBlobHelp()
4220 control.missing_blob_help['wibble'] = 'Wibble test'
4221 control.missing_blob_help['another'] = 'Another test'
4222 with test_util.capture_sys_output() as (stdout, stderr):
4223 self._DoTestFile('168_fit_missing_blob.dts',
4224 allow_missing=True)
4225 err = stderr.getvalue()
4226
4227 # We can get the tag from the name, the type or the missing-msg
4228 # property. Check all three.
4229 self.assertIn('You may need to build ARM Trusted', err)
4230 self.assertIn('Wibble test', err)
4231 self.assertIn('Another test', err)
4232
Simon Glass204aa782020-09-06 10:35:32 -06004233 def testMissingBlob(self):
4234 """Test handling of a blob containing a missing file"""
4235 with self.assertRaises(ValueError) as e:
4236 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
4237 self.assertIn("Filename 'missing' not found in input path",
4238 str(e.exception))
4239
Simon Glassfb91d562020-09-06 10:35:33 -06004240 def testEnvironment(self):
4241 """Test adding a U-Boot environment"""
4242 data = self._DoReadFile('174_env.dts')
4243 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
4244 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4245 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4246 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
4247 env)
4248
4249 def testEnvironmentNoSize(self):
4250 """Test that a missing 'size' property is detected"""
4251 with self.assertRaises(ValueError) as e:
Simon Glassa4dfe3e2020-10-26 17:40:00 -06004252 self._DoTestFile('175_env_no_size.dts')
Simon Glassfb91d562020-09-06 10:35:33 -06004253 self.assertIn("'u-boot-env' entry must have a size property",
4254 str(e.exception))
4255
4256 def testEnvironmentTooSmall(self):
4257 """Test handling of an environment that does not fit"""
4258 with self.assertRaises(ValueError) as e:
Simon Glassa4dfe3e2020-10-26 17:40:00 -06004259 self._DoTestFile('176_env_too_small.dts')
Simon Glassfb91d562020-09-06 10:35:33 -06004260
4261 # checksum, start byte, environment with \0 terminator, final \0
4262 need = 4 + 1 + len(ENV_DATA) + 1 + 1
4263 short = need - 0x8
4264 self.assertIn("too small to hold data (need %#x more bytes)" % short,
4265 str(e.exception))
4266
Simon Glassf2c0dd82020-10-26 17:40:01 -06004267 def testSkipAtStart(self):
4268 """Test handling of skip-at-start section"""
4269 data = self._DoReadFile('177_skip_at_start.dts')
4270 self.assertEqual(U_BOOT_DATA, data)
4271
4272 image = control.images['image']
4273 entries = image.GetEntries()
4274 section = entries['section']
4275 self.assertEqual(0, section.offset)
4276 self.assertEqual(len(U_BOOT_DATA), section.size)
4277 self.assertEqual(U_BOOT_DATA, section.GetData())
4278
4279 entry = section.GetEntries()['u-boot']
4280 self.assertEqual(16, entry.offset)
4281 self.assertEqual(len(U_BOOT_DATA), entry.size)
4282 self.assertEqual(U_BOOT_DATA, entry.data)
4283
4284 def testSkipAtStartPad(self):
4285 """Test handling of skip-at-start section with padded entry"""
4286 data = self._DoReadFile('178_skip_at_start_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004287 before = tools.get_bytes(0, 8)
4288 after = tools.get_bytes(0, 4)
Simon Glassf2c0dd82020-10-26 17:40:01 -06004289 all = before + U_BOOT_DATA + after
4290 self.assertEqual(all, data)
4291
4292 image = control.images['image']
4293 entries = image.GetEntries()
4294 section = entries['section']
4295 self.assertEqual(0, section.offset)
4296 self.assertEqual(len(all), section.size)
4297 self.assertEqual(all, section.GetData())
4298
4299 entry = section.GetEntries()['u-boot']
4300 self.assertEqual(16, entry.offset)
4301 self.assertEqual(len(all), entry.size)
4302 self.assertEqual(U_BOOT_DATA, entry.data)
4303
4304 def testSkipAtStartSectionPad(self):
4305 """Test handling of skip-at-start section with padding"""
4306 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004307 before = tools.get_bytes(0, 8)
4308 after = tools.get_bytes(0, 4)
Simon Glassf2c0dd82020-10-26 17:40:01 -06004309 all = before + U_BOOT_DATA + after
Simon Glassd1d3ad72020-10-26 17:40:13 -06004310 self.assertEqual(all, data)
Simon Glassf2c0dd82020-10-26 17:40:01 -06004311
4312 image = control.images['image']
4313 entries = image.GetEntries()
4314 section = entries['section']
4315 self.assertEqual(0, section.offset)
4316 self.assertEqual(len(all), section.size)
Simon Glass63e7ba62020-10-26 17:40:16 -06004317 self.assertEqual(U_BOOT_DATA, section.data)
Simon Glassd1d3ad72020-10-26 17:40:13 -06004318 self.assertEqual(all, section.GetPaddedData())
Simon Glassf2c0dd82020-10-26 17:40:01 -06004319
4320 entry = section.GetEntries()['u-boot']
4321 self.assertEqual(16, entry.offset)
4322 self.assertEqual(len(U_BOOT_DATA), entry.size)
4323 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassfb91d562020-09-06 10:35:33 -06004324
Simon Glass7d398bb2020-10-26 17:40:14 -06004325 def testSectionPad(self):
4326 """Testing padding with sections"""
4327 data = self._DoReadFile('180_section_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004328 expected = (tools.get_bytes(ord('&'), 3) +
4329 tools.get_bytes(ord('!'), 5) +
Simon Glass7d398bb2020-10-26 17:40:14 -06004330 U_BOOT_DATA +
Simon Glassc1aa66e2022-01-29 14:14:04 -07004331 tools.get_bytes(ord('!'), 1) +
4332 tools.get_bytes(ord('&'), 2))
Simon Glass7d398bb2020-10-26 17:40:14 -06004333 self.assertEqual(expected, data)
4334
4335 def testSectionAlign(self):
4336 """Testing alignment with sections"""
4337 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4338 expected = (b'\0' + # fill section
Simon Glassc1aa66e2022-01-29 14:14:04 -07004339 tools.get_bytes(ord('&'), 1) + # padding to section align
Simon Glass7d398bb2020-10-26 17:40:14 -06004340 b'\0' + # fill section
Simon Glassc1aa66e2022-01-29 14:14:04 -07004341 tools.get_bytes(ord('!'), 3) + # padding to u-boot align
Simon Glass7d398bb2020-10-26 17:40:14 -06004342 U_BOOT_DATA +
Simon Glassc1aa66e2022-01-29 14:14:04 -07004343 tools.get_bytes(ord('!'), 4) + # padding to u-boot size
4344 tools.get_bytes(ord('!'), 4)) # padding to section size
Simon Glass7d398bb2020-10-26 17:40:14 -06004345 self.assertEqual(expected, data)
4346
Simon Glass8f5ef892020-10-26 17:40:25 -06004347 def testCompressImage(self):
4348 """Test compression of the entire image"""
4349 self._CheckLz4()
4350 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4351 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4352 dtb = fdt.Fdt(out_dtb_fname)
4353 dtb.Scan()
4354 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4355 'uncomp-size'])
4356 orig = self._decompress(data)
4357 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4358
4359 # Do a sanity check on various fields
4360 image = control.images['image']
4361 entries = image.GetEntries()
4362 self.assertEqual(2, len(entries))
4363
4364 entry = entries['blob']
4365 self.assertEqual(COMPRESS_DATA, entry.data)
4366 self.assertEqual(len(COMPRESS_DATA), entry.size)
4367
4368 entry = entries['u-boot']
4369 self.assertEqual(U_BOOT_DATA, entry.data)
4370 self.assertEqual(len(U_BOOT_DATA), entry.size)
4371
4372 self.assertEqual(len(data), image.size)
4373 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4374 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4375 orig = self._decompress(image.data)
4376 self.assertEqual(orig, image.uncomp_data)
4377
4378 expected = {
4379 'blob:offset': 0,
4380 'blob:size': len(COMPRESS_DATA),
4381 'u-boot:offset': len(COMPRESS_DATA),
4382 'u-boot:size': len(U_BOOT_DATA),
4383 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4384 'offset': 0,
4385 'image-pos': 0,
4386 'size': len(data),
4387 }
4388 self.assertEqual(expected, props)
4389
4390 def testCompressImageLess(self):
4391 """Test compression where compression reduces the image size"""
4392 self._CheckLz4()
4393 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4394 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4395 dtb = fdt.Fdt(out_dtb_fname)
4396 dtb.Scan()
4397 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4398 'uncomp-size'])
4399 orig = self._decompress(data)
4400
4401 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
4402
4403 # Do a sanity check on various fields
4404 image = control.images['image']
4405 entries = image.GetEntries()
4406 self.assertEqual(2, len(entries))
4407
4408 entry = entries['blob']
4409 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4410 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4411
4412 entry = entries['u-boot']
4413 self.assertEqual(U_BOOT_DATA, entry.data)
4414 self.assertEqual(len(U_BOOT_DATA), entry.size)
4415
4416 self.assertEqual(len(data), image.size)
4417 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4418 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4419 image.uncomp_size)
4420 orig = self._decompress(image.data)
4421 self.assertEqual(orig, image.uncomp_data)
4422
4423 expected = {
4424 'blob:offset': 0,
4425 'blob:size': len(COMPRESS_DATA_BIG),
4426 'u-boot:offset': len(COMPRESS_DATA_BIG),
4427 'u-boot:size': len(U_BOOT_DATA),
4428 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4429 'offset': 0,
4430 'image-pos': 0,
4431 'size': len(data),
4432 }
4433 self.assertEqual(expected, props)
4434
4435 def testCompressSectionSize(self):
4436 """Test compression of a section with a fixed size"""
4437 self._CheckLz4()
4438 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4439 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4440 dtb = fdt.Fdt(out_dtb_fname)
4441 dtb.Scan()
4442 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4443 'uncomp-size'])
4444 orig = self._decompress(data)
4445 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4446 expected = {
4447 'section/blob:offset': 0,
4448 'section/blob:size': len(COMPRESS_DATA),
4449 'section/u-boot:offset': len(COMPRESS_DATA),
4450 'section/u-boot:size': len(U_BOOT_DATA),
4451 'section:offset': 0,
4452 'section:image-pos': 0,
4453 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4454 'section:size': 0x30,
4455 'offset': 0,
4456 'image-pos': 0,
4457 'size': 0x30,
4458 }
4459 self.assertEqual(expected, props)
4460
4461 def testCompressSection(self):
4462 """Test compression of a section with no fixed size"""
4463 self._CheckLz4()
4464 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4465 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4466 dtb = fdt.Fdt(out_dtb_fname)
4467 dtb.Scan()
4468 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4469 'uncomp-size'])
4470 orig = self._decompress(data)
4471 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4472 expected = {
4473 'section/blob:offset': 0,
4474 'section/blob:size': len(COMPRESS_DATA),
4475 'section/u-boot:offset': len(COMPRESS_DATA),
4476 'section/u-boot:size': len(U_BOOT_DATA),
4477 'section:offset': 0,
4478 'section:image-pos': 0,
4479 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4480 'section:size': len(data),
4481 'offset': 0,
4482 'image-pos': 0,
4483 'size': len(data),
4484 }
4485 self.assertEqual(expected, props)
4486
Stefan Herbrechtsmeierc3665a82022-08-19 16:25:31 +02004487 def testLz4Missing(self):
4488 """Test that binman still produces an image if lz4 is missing"""
4489 with test_util.capture_sys_output() as (_, stderr):
4490 self._DoTestFile('185_compress_section.dts',
4491 force_missing_bintools='lz4')
4492 err = stderr.getvalue()
4493 self.assertRegex(err,
4494 "Image 'main-section'.*missing bintools.*: lz4")
4495
Simon Glass8f5ef892020-10-26 17:40:25 -06004496 def testCompressExtra(self):
4497 """Test compression of a section with no fixed size"""
4498 self._CheckLz4()
4499 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4500 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4501 dtb = fdt.Fdt(out_dtb_fname)
4502 dtb.Scan()
4503 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4504 'uncomp-size'])
4505
4506 base = data[len(U_BOOT_DATA):]
4507 self.assertEquals(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
4508 rest = base[len(U_BOOT_DATA):]
4509
4510 # Check compressed data
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +02004511 bintool = self.comp_bintools['lz4']
4512 expect1 = bintool.compress(COMPRESS_DATA + U_BOOT_DATA)
Stefan Herbrechtsmeierfa24f552022-08-19 16:25:23 +02004513 data1 = rest[:len(expect1)]
4514 section1 = self._decompress(data1)
4515 self.assertEquals(expect1, data1)
Simon Glass8f5ef892020-10-26 17:40:25 -06004516 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, section1)
4517 rest1 = rest[len(expect1):]
4518
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +02004519 expect2 = bintool.compress(COMPRESS_DATA + COMPRESS_DATA)
Stefan Herbrechtsmeierfa24f552022-08-19 16:25:23 +02004520 data2 = rest1[:len(expect2)]
4521 section2 = self._decompress(data2)
4522 self.assertEquals(expect2, data2)
Simon Glass8f5ef892020-10-26 17:40:25 -06004523 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA, section2)
4524 rest2 = rest1[len(expect2):]
4525
4526 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4527 len(expect2) + len(U_BOOT_DATA))
4528 #self.assertEquals(expect_size, len(data))
4529
4530 #self.assertEquals(U_BOOT_DATA, rest2)
4531
4532 self.maxDiff = None
4533 expected = {
4534 'u-boot:offset': 0,
4535 'u-boot:image-pos': 0,
4536 'u-boot:size': len(U_BOOT_DATA),
4537
4538 'base:offset': len(U_BOOT_DATA),
4539 'base:image-pos': len(U_BOOT_DATA),
4540 'base:size': len(data) - len(U_BOOT_DATA),
4541 'base/u-boot:offset': 0,
4542 'base/u-boot:image-pos': len(U_BOOT_DATA),
4543 'base/u-boot:size': len(U_BOOT_DATA),
4544 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4545 len(expect2),
4546 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4547 len(expect2),
4548 'base/u-boot2:size': len(U_BOOT_DATA),
4549
4550 'base/section:offset': len(U_BOOT_DATA),
4551 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4552 'base/section:size': len(expect1),
4553 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4554 'base/section/blob:offset': 0,
4555 'base/section/blob:size': len(COMPRESS_DATA),
4556 'base/section/u-boot:offset': len(COMPRESS_DATA),
4557 'base/section/u-boot:size': len(U_BOOT_DATA),
4558
4559 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4560 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4561 'base/section2:size': len(expect2),
4562 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4563 'base/section2/blob:offset': 0,
4564 'base/section2/blob:size': len(COMPRESS_DATA),
4565 'base/section2/blob2:offset': len(COMPRESS_DATA),
4566 'base/section2/blob2:size': len(COMPRESS_DATA),
4567
4568 'offset': 0,
4569 'image-pos': 0,
4570 'size': len(data),
4571 }
4572 self.assertEqual(expected, props)
4573
Simon Glass870a9ea2021-01-06 21:35:15 -07004574 def testSymbolsSubsection(self):
4575 """Test binman can assign symbols from a subsection"""
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03004576 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glass870a9ea2021-01-06 21:35:15 -07004577
Simon Glass939d1062021-01-06 21:35:16 -07004578 def testReadImageEntryArg(self):
4579 """Test reading an image that would need an entry arg to generate"""
4580 entry_args = {
4581 'cros-ec-rw-path': 'ecrw.bin',
4582 }
4583 data = self.data = self._DoReadFileDtb(
4584 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4585 entry_args=entry_args)
4586
Simon Glassc1aa66e2022-01-29 14:14:04 -07004587 image_fname = tools.get_output_filename('image.bin')
Simon Glass939d1062021-01-06 21:35:16 -07004588 orig_image = control.images['image']
4589
4590 # This should not generate an error about the missing 'cros-ec-rw-path'
4591 # since we are reading the image from a file. Compare with
4592 # testEntryArgsRequired()
4593 image = Image.FromFile(image_fname)
4594 self.assertEqual(orig_image.GetEntries().keys(),
4595 image.GetEntries().keys())
4596
Simon Glass6eb99322021-01-06 21:35:18 -07004597 def testFilesAlign(self):
4598 """Test alignment with files"""
4599 data = self._DoReadFile('190_files_align.dts')
4600
4601 # The first string is 15 bytes so will align to 16
4602 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4603 self.assertEqual(expect, data)
4604
Simon Glass5c6ba712021-01-06 21:35:19 -07004605 def testReadImageSkip(self):
4606 """Test reading an image and accessing its FDT map"""
4607 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004608 image_fname = tools.get_output_filename('image.bin')
Simon Glass5c6ba712021-01-06 21:35:19 -07004609 orig_image = control.images['image']
4610 image = Image.FromFile(image_fname)
4611 self.assertEqual(orig_image.GetEntries().keys(),
4612 image.GetEntries().keys())
4613
4614 orig_entry = orig_image.GetEntries()['fdtmap']
4615 entry = image.GetEntries()['fdtmap']
4616 self.assertEqual(orig_entry.offset, entry.offset)
4617 self.assertEqual(orig_entry.size, entry.size)
4618 self.assertEqual(16, entry.image_pos)
4619
4620 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4621
4622 self.assertEquals(U_BOOT_DATA, u_boot.ReadData())
4623
Simon Glass77a64e02021-03-18 20:24:57 +13004624 def testTplNoDtb(self):
4625 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
Simon Glass0fe44dc2021-04-25 08:39:32 +12004626 self._SetupTplElf()
Simon Glass77a64e02021-03-18 20:24:57 +13004627 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4628 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4629 data[:len(U_BOOT_TPL_NODTB_DATA)])
4630
Simon Glassd26efc82021-03-18 20:24:58 +13004631 def testTplBssPad(self):
4632 """Test that we can pad TPL's BSS with zeros"""
4633 # ELF file with a '__bss_size' symbol
4634 self._SetupTplElf()
4635 data = self._DoReadFile('193_tpl_bss_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004636 self.assertEqual(U_BOOT_TPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glassd26efc82021-03-18 20:24:58 +13004637 data)
4638
4639 def testTplBssPadMissing(self):
4640 """Test that a missing symbol is detected"""
4641 self._SetupTplElf('u_boot_ucode_ptr')
4642 with self.assertRaises(ValueError) as e:
4643 self._DoReadFile('193_tpl_bss_pad.dts')
4644 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4645 str(e.exception))
4646
Simon Glass06684922021-03-18 20:25:07 +13004647 def checkDtbSizes(self, data, pad_len, start):
4648 """Check the size arguments in a dtb embedded in an image
4649
4650 Args:
4651 data: The image data
4652 pad_len: Length of the pad section in the image, in bytes
4653 start: Start offset of the devicetree to examine, within the image
4654
4655 Returns:
4656 Size of the devicetree in bytes
4657 """
4658 dtb_data = data[start:]
4659 dtb = fdt.Fdt.FromData(dtb_data)
4660 fdt_size = dtb.GetFdtObj().totalsize()
4661 dtb.Scan()
4662 props = self._GetPropTree(dtb, 'size')
4663 self.assertEqual({
4664 'size': len(data),
4665 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4666 'u-boot-spl/u-boot-spl-dtb:size': 801,
4667 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4668 'u-boot-spl:size': 860,
4669 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4670 'u-boot/u-boot-dtb:size': 781,
4671 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4672 'u-boot:size': 827,
4673 }, props)
4674 return fdt_size
4675
4676 def testExpanded(self):
4677 """Test that an expanded entry type is selected when needed"""
4678 self._SetupSplElf()
4679 self._SetupTplElf()
4680
4681 # SPL has a devicetree, TPL does not
4682 entry_args = {
4683 'spl-dtb': '1',
4684 'spl-bss-pad': 'y',
4685 'tpl-dtb': '',
4686 }
4687 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4688 entry_args=entry_args)
4689 image = control.images['image']
4690 entries = image.GetEntries()
4691 self.assertEqual(3, len(entries))
4692
4693 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4694 self.assertIn('u-boot', entries)
4695 entry = entries['u-boot']
4696 self.assertEqual('u-boot-expanded', entry.etype)
4697 subent = entry.GetEntries()
4698 self.assertEqual(2, len(subent))
4699 self.assertIn('u-boot-nodtb', subent)
4700 self.assertIn('u-boot-dtb', subent)
4701
4702 # Second, u-boot-spl, which should be expanded into three parts
4703 self.assertIn('u-boot-spl', entries)
4704 entry = entries['u-boot-spl']
4705 self.assertEqual('u-boot-spl-expanded', entry.etype)
4706 subent = entry.GetEntries()
4707 self.assertEqual(3, len(subent))
4708 self.assertIn('u-boot-spl-nodtb', subent)
4709 self.assertIn('u-boot-spl-bss-pad', subent)
4710 self.assertIn('u-boot-spl-dtb', subent)
4711
4712 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4713 # devicetree
4714 self.assertIn('u-boot-tpl', entries)
4715 entry = entries['u-boot-tpl']
4716 self.assertEqual('u-boot-tpl', entry.etype)
4717 self.assertEqual(None, entry.GetEntries())
4718
4719 def testExpandedTpl(self):
4720 """Test that an expanded entry type is selected for TPL when needed"""
4721 self._SetupTplElf()
4722
4723 entry_args = {
4724 'tpl-bss-pad': 'y',
4725 'tpl-dtb': 'y',
4726 }
4727 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4728 entry_args=entry_args)
4729 image = control.images['image']
4730 entries = image.GetEntries()
4731 self.assertEqual(1, len(entries))
4732
4733 # We only have u-boot-tpl, which be expanded
4734 self.assertIn('u-boot-tpl', entries)
4735 entry = entries['u-boot-tpl']
4736 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4737 subent = entry.GetEntries()
4738 self.assertEqual(3, len(subent))
4739 self.assertIn('u-boot-tpl-nodtb', subent)
4740 self.assertIn('u-boot-tpl-bss-pad', subent)
4741 self.assertIn('u-boot-tpl-dtb', subent)
4742
4743 def testExpandedNoPad(self):
4744 """Test an expanded entry without BSS pad enabled"""
4745 self._SetupSplElf()
4746 self._SetupTplElf()
4747
4748 # SPL has a devicetree, TPL does not
4749 entry_args = {
4750 'spl-dtb': 'something',
4751 'spl-bss-pad': 'n',
4752 'tpl-dtb': '',
4753 }
4754 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4755 entry_args=entry_args)
4756 image = control.images['image']
4757 entries = image.GetEntries()
4758
4759 # Just check u-boot-spl, which should be expanded into two parts
4760 self.assertIn('u-boot-spl', entries)
4761 entry = entries['u-boot-spl']
4762 self.assertEqual('u-boot-spl-expanded', entry.etype)
4763 subent = entry.GetEntries()
4764 self.assertEqual(2, len(subent))
4765 self.assertIn('u-boot-spl-nodtb', subent)
4766 self.assertIn('u-boot-spl-dtb', subent)
4767
4768 def testExpandedTplNoPad(self):
4769 """Test that an expanded entry type with padding disabled in TPL"""
4770 self._SetupTplElf()
4771
4772 entry_args = {
4773 'tpl-bss-pad': '',
4774 'tpl-dtb': 'y',
4775 }
4776 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4777 entry_args=entry_args)
4778 image = control.images['image']
4779 entries = image.GetEntries()
4780 self.assertEqual(1, len(entries))
4781
4782 # We only have u-boot-tpl, which be expanded
4783 self.assertIn('u-boot-tpl', entries)
4784 entry = entries['u-boot-tpl']
4785 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4786 subent = entry.GetEntries()
4787 self.assertEqual(2, len(subent))
4788 self.assertIn('u-boot-tpl-nodtb', subent)
4789 self.assertIn('u-boot-tpl-dtb', subent)
4790
4791 def testFdtInclude(self):
4792 """Test that an Fdt is update within all binaries"""
4793 self._SetupSplElf()
4794 self._SetupTplElf()
4795
4796 # SPL has a devicetree, TPL does not
4797 self.maxDiff = None
4798 entry_args = {
4799 'spl-dtb': '1',
4800 'spl-bss-pad': 'y',
4801 'tpl-dtb': '',
4802 }
4803 # Build the image. It includes two separate devicetree binaries, each
4804 # with their own contents, but all contain the binman definition.
4805 data = self._DoReadFileDtb(
4806 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4807 update_dtb=True, entry_args=entry_args)[0]
4808 pad_len = 10
4809
4810 # Check the U-Boot dtb
4811 start = len(U_BOOT_NODTB_DATA)
4812 fdt_size = self.checkDtbSizes(data, pad_len, start)
4813
4814 # Now check SPL
4815 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4816 fdt_size = self.checkDtbSizes(data, pad_len, start)
4817
4818 # TPL has no devicetree
4819 start += fdt_size + len(U_BOOT_TPL_DATA)
4820 self.assertEqual(len(data), start)
Simon Glass7d398bb2020-10-26 17:40:14 -06004821
Simon Glass3d433382021-03-21 18:24:30 +13004822 def testSymbolsExpanded(self):
4823 """Test binman can assign symbols in expanded entries"""
4824 entry_args = {
4825 'spl-dtb': '1',
4826 }
4827 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4828 U_BOOT_SPL_DTB_DATA, 0x38,
4829 entry_args=entry_args, use_expanded=True)
4830
Simon Glass189f2912021-03-21 18:24:31 +13004831 def testCollection(self):
4832 """Test a collection"""
4833 data = self._DoReadFile('198_collection.dts')
4834 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
Simon Glassc1aa66e2022-01-29 14:14:04 -07004835 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
4836 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
Simon Glass189f2912021-03-21 18:24:31 +13004837 data)
4838
Simon Glass631f7522021-03-21 18:24:32 +13004839 def testCollectionSection(self):
4840 """Test a collection where a section must be built first"""
4841 # Sections never have their contents when GetData() is called, but when
Simon Glassd34bcdd2021-11-23 11:03:47 -07004842 # BuildSectionData() is called with required=True, a section will force
Simon Glass631f7522021-03-21 18:24:32 +13004843 # building the contents, producing an error is anything is still
4844 # missing.
4845 data = self._DoReadFile('199_collection_section.dts')
4846 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
Simon Glassc1aa66e2022-01-29 14:14:04 -07004847 self.assertEqual(section + U_BOOT_DATA + tools.get_bytes(0xff, 2) +
4848 section + tools.get_bytes(0xfe, 3) + U_BOOT_DATA,
Simon Glass631f7522021-03-21 18:24:32 +13004849 data)
4850
Simon Glass5ff9fed2021-03-21 18:24:33 +13004851 def testAlignDefault(self):
4852 """Test that default alignment works on sections"""
4853 data = self._DoReadFile('200_align_default.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004854 expected = (U_BOOT_DATA + tools.get_bytes(0, 8 - len(U_BOOT_DATA)) +
Simon Glass5ff9fed2021-03-21 18:24:33 +13004855 U_BOOT_DATA)
4856 # Special alignment for section
Simon Glassc1aa66e2022-01-29 14:14:04 -07004857 expected += tools.get_bytes(0, 32 - len(expected))
Simon Glass5ff9fed2021-03-21 18:24:33 +13004858 # No alignment within the nested section
4859 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
4860 # Now the final piece, which should be default-aligned
Simon Glassc1aa66e2022-01-29 14:14:04 -07004861 expected += tools.get_bytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
Simon Glass5ff9fed2021-03-21 18:24:33 +13004862 self.assertEqual(expected, data)
Simon Glass631f7522021-03-21 18:24:32 +13004863
Bin Meng4c4d6072021-05-10 20:23:33 +08004864 def testPackOpenSBI(self):
4865 """Test that an image with an OpenSBI binary can be created"""
4866 data = self._DoReadFile('201_opensbi.dts')
4867 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
4868
Simon Glassc69d19c2021-07-06 10:36:37 -06004869 def testSectionsSingleThread(self):
4870 """Test sections without multithreading"""
4871 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
Simon Glassc1aa66e2022-01-29 14:14:04 -07004872 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4873 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
4874 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glassc69d19c2021-07-06 10:36:37 -06004875 self.assertEqual(expected, data)
4876
4877 def testThreadTimeout(self):
4878 """Test handling a thread that takes too long"""
4879 with self.assertRaises(ValueError) as e:
4880 self._DoTestFile('202_section_timeout.dts',
4881 test_section_timeout=True)
Simon Glassb2dfe832021-10-18 12:13:15 -06004882 self.assertIn("Timed out obtaining contents", str(e.exception))
Simon Glassc69d19c2021-07-06 10:36:37 -06004883
Simon Glass03ebc202021-07-06 10:36:41 -06004884 def testTiming(self):
4885 """Test output of timing information"""
4886 data = self._DoReadFile('055_sections.dts')
4887 with test_util.capture_sys_output() as (stdout, stderr):
4888 state.TimingShow()
4889 self.assertIn('read:', stdout.getvalue())
4890 self.assertIn('compress:', stdout.getvalue())
4891
Simon Glass0427bed2021-11-03 21:09:18 -06004892 def testUpdateFdtInElf(self):
4893 """Test that we can update the devicetree in an ELF file"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02004894 if not elf.ELF_TOOLS:
4895 self.skipTest('Python elftools not available')
Simon Glass0427bed2021-11-03 21:09:18 -06004896 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4897 outfile = os.path.join(self._indir, 'u-boot.out')
4898 begin_sym = 'dtb_embed_begin'
4899 end_sym = 'dtb_embed_end'
4900 retcode = self._DoTestFile(
4901 '060_fdt_update.dts', update_dtb=True,
4902 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4903 self.assertEqual(0, retcode)
4904
4905 # Check that the output file does in fact contact a dtb with the binman
4906 # definition in the correct place
4907 syms = elf.GetSymbolFileOffset(infile,
4908 ['dtb_embed_begin', 'dtb_embed_end'])
Simon Glassc1aa66e2022-01-29 14:14:04 -07004909 data = tools.read_file(outfile)
Simon Glass0427bed2021-11-03 21:09:18 -06004910 dtb_data = data[syms['dtb_embed_begin'].offset:
4911 syms['dtb_embed_end'].offset]
4912
4913 dtb = fdt.Fdt.FromData(dtb_data)
4914 dtb.Scan()
4915 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4916 self.assertEqual({
4917 'image-pos': 0,
4918 'offset': 0,
4919 '_testing:offset': 32,
4920 '_testing:size': 2,
4921 '_testing:image-pos': 32,
4922 'section@0/u-boot:offset': 0,
4923 'section@0/u-boot:size': len(U_BOOT_DATA),
4924 'section@0/u-boot:image-pos': 0,
4925 'section@0:offset': 0,
4926 'section@0:size': 16,
4927 'section@0:image-pos': 0,
4928
4929 'section@1/u-boot:offset': 0,
4930 'section@1/u-boot:size': len(U_BOOT_DATA),
4931 'section@1/u-boot:image-pos': 16,
4932 'section@1:offset': 16,
4933 'section@1:size': 16,
4934 'section@1:image-pos': 16,
4935 'size': 40
4936 }, props)
4937
4938 def testUpdateFdtInElfInvalid(self):
4939 """Test that invalid args are detected with --update-fdt-in-elf"""
4940 with self.assertRaises(ValueError) as e:
4941 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
4942 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
4943 str(e.exception))
4944
4945 def testUpdateFdtInElfNoSyms(self):
4946 """Test that missing symbols are detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02004947 if not elf.ELF_TOOLS:
4948 self.skipTest('Python elftools not available')
Simon Glass0427bed2021-11-03 21:09:18 -06004949 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4950 outfile = ''
4951 begin_sym = 'wrong_begin'
4952 end_sym = 'wrong_end'
4953 with self.assertRaises(ValueError) as e:
4954 self._DoTestFile(
4955 '060_fdt_update.dts',
4956 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4957 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
4958 str(e.exception))
4959
4960 def testUpdateFdtInElfTooSmall(self):
4961 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02004962 if not elf.ELF_TOOLS:
4963 self.skipTest('Python elftools not available')
Simon Glass0427bed2021-11-03 21:09:18 -06004964 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
4965 outfile = os.path.join(self._indir, 'u-boot.out')
4966 begin_sym = 'dtb_embed_begin'
4967 end_sym = 'dtb_embed_end'
4968 with self.assertRaises(ValueError) as e:
4969 self._DoTestFile(
4970 '060_fdt_update.dts', update_dtb=True,
4971 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4972 self.assertRegex(
4973 str(e.exception),
4974 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
4975
Simon Glassc475dec2021-11-23 11:03:42 -07004976 def testVersion(self):
4977 """Test we can get the binman version"""
4978 version = '(unreleased)'
4979 self.assertEqual(version, state.GetVersion(self._indir))
4980
4981 with self.assertRaises(SystemExit):
4982 with test_util.capture_sys_output() as (_, stderr):
4983 self._DoBinman('-V')
4984 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
4985
4986 # Try running the tool too, just to be safe
4987 result = self._RunBinman('-V')
4988 self.assertEqual('Binman %s\n' % version, result.stderr)
4989
4990 # Set up a version file to make sure that works
4991 version = 'v2025.01-rc2'
Simon Glassc1aa66e2022-01-29 14:14:04 -07004992 tools.write_file(os.path.join(self._indir, 'version'), version,
Simon Glassc475dec2021-11-23 11:03:42 -07004993 binary=False)
4994 self.assertEqual(version, state.GetVersion(self._indir))
4995
Simon Glass943bf782021-11-23 21:09:50 -07004996 def testAltFormat(self):
4997 """Test that alternative formats can be used to extract"""
4998 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
4999
5000 try:
5001 tmpdir, updated_fname = self._SetupImageInTmpdir()
5002 with test_util.capture_sys_output() as (stdout, _):
5003 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
5004 self.assertEqual(
5005 '''Flag (-F) Entry type Description
5006fdt fdtmap Extract the devicetree blob from the fdtmap
5007''',
5008 stdout.getvalue())
5009
5010 dtb = os.path.join(tmpdir, 'fdt.dtb')
5011 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
5012 dtb, 'fdtmap')
5013
5014 # Check that we can read it and it can be scanning, meaning it does
5015 # not have a 16-byte fdtmap header
Simon Glassc1aa66e2022-01-29 14:14:04 -07005016 data = tools.read_file(dtb)
Simon Glass943bf782021-11-23 21:09:50 -07005017 dtb = fdt.Fdt.FromData(data)
5018 dtb.Scan()
5019
5020 # Now check u-boot which has no alt_format
5021 fname = os.path.join(tmpdir, 'fdt.dtb')
5022 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
5023 '-f', fname, 'u-boot')
Simon Glassc1aa66e2022-01-29 14:14:04 -07005024 data = tools.read_file(fname)
Simon Glass943bf782021-11-23 21:09:50 -07005025 self.assertEqual(U_BOOT_DATA, data)
5026
5027 finally:
5028 shutil.rmtree(tmpdir)
5029
Simon Glasscc2c5002021-11-23 21:09:52 -07005030 def testExtblobList(self):
5031 """Test an image with an external blob list"""
5032 data = self._DoReadFile('215_blob_ext_list.dts')
5033 self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
5034
5035 def testExtblobListMissing(self):
5036 """Test an image with a missing external blob"""
5037 with self.assertRaises(ValueError) as e:
5038 self._DoReadFile('216_blob_ext_list_missing.dts')
5039 self.assertIn("Filename 'missing-file' not found in input path",
5040 str(e.exception))
5041
5042 def testExtblobListMissingOk(self):
5043 """Test an image with an missing external blob that is allowed"""
5044 with test_util.capture_sys_output() as (stdout, stderr):
5045 self._DoTestFile('216_blob_ext_list_missing.dts',
5046 allow_missing=True)
5047 err = stderr.getvalue()
5048 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
5049
Simon Glass75989722021-11-23 21:08:59 -07005050 def testFip(self):
5051 """Basic test of generation of an ARM Firmware Image Package (FIP)"""
5052 data = self._DoReadFile('203_fip.dts')
5053 hdr, fents = fip_util.decode_fip(data)
5054 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5055 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5056 self.assertEqual(0x123, hdr.flags)
5057
5058 self.assertEqual(2, len(fents))
5059
5060 fent = fents[0]
5061 self.assertEqual(
5062 bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
5063 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
5064 self.assertEqual('soc-fw', fent.fip_type)
5065 self.assertEqual(0x88, fent.offset)
5066 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5067 self.assertEqual(0x123456789abcdef, fent.flags)
5068 self.assertEqual(ATF_BL31_DATA, fent.data)
5069 self.assertEqual(True, fent.valid)
5070
5071 fent = fents[1]
5072 self.assertEqual(
5073 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
5074 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
5075 self.assertEqual('scp-fwu-cfg', fent.fip_type)
5076 self.assertEqual(0x8c, fent.offset)
5077 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5078 self.assertEqual(0, fent.flags)
5079 self.assertEqual(ATF_BL2U_DATA, fent.data)
5080 self.assertEqual(True, fent.valid)
5081
5082 def testFipOther(self):
5083 """Basic FIP with something that isn't a external blob"""
5084 data = self._DoReadFile('204_fip_other.dts')
5085 hdr, fents = fip_util.decode_fip(data)
5086
5087 self.assertEqual(2, len(fents))
5088 fent = fents[1]
5089 self.assertEqual('rot-cert', fent.fip_type)
5090 self.assertEqual(b'aa', fent.data)
5091
Simon Glass75989722021-11-23 21:08:59 -07005092 def testFipNoType(self):
5093 """FIP with an entry of an unknown type"""
5094 with self.assertRaises(ValueError) as e:
5095 self._DoReadFile('205_fip_no_type.dts')
5096 self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
5097 str(e.exception))
5098
5099 def testFipUuid(self):
5100 """Basic FIP with a manual uuid"""
5101 data = self._DoReadFile('206_fip_uuid.dts')
5102 hdr, fents = fip_util.decode_fip(data)
5103
5104 self.assertEqual(2, len(fents))
5105 fent = fents[1]
5106 self.assertEqual(None, fent.fip_type)
5107 self.assertEqual(
5108 bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
5109 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
5110 fent.uuid)
5111 self.assertEqual(U_BOOT_DATA, fent.data)
5112
5113 def testFipLs(self):
5114 """Test listing a FIP"""
5115 data = self._DoReadFileRealDtb('207_fip_ls.dts')
5116 hdr, fents = fip_util.decode_fip(data)
5117
5118 try:
5119 tmpdir, updated_fname = self._SetupImageInTmpdir()
5120 with test_util.capture_sys_output() as (stdout, stderr):
5121 self._DoBinman('ls', '-i', updated_fname)
5122 finally:
5123 shutil.rmtree(tmpdir)
5124 lines = stdout.getvalue().splitlines()
5125 expected = [
5126'Name Image-pos Size Entry-type Offset Uncomp-size',
5127'----------------------------------------------------------------',
5128'main-section 0 2d3 section 0',
5129' atf-fip 0 90 atf-fip 0',
5130' soc-fw 88 4 blob-ext 88',
5131' u-boot 8c 4 u-boot 8c',
5132' fdtmap 90 243 fdtmap 90',
5133]
5134 self.assertEqual(expected, lines)
5135
5136 image = control.images['image']
5137 entries = image.GetEntries()
5138 fdtmap = entries['fdtmap']
5139
5140 fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
5141 magic = fdtmap_data[:8]
5142 self.assertEqual(b'_FDTMAP_', magic)
Simon Glassc1aa66e2022-01-29 14:14:04 -07005143 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass75989722021-11-23 21:08:59 -07005144
5145 fdt_data = fdtmap_data[16:]
5146 dtb = fdt.Fdt.FromData(fdt_data)
5147 dtb.Scan()
5148 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
5149 self.assertEqual({
5150 'atf-fip/soc-fw:image-pos': 136,
5151 'atf-fip/soc-fw:offset': 136,
5152 'atf-fip/soc-fw:size': 4,
5153 'atf-fip/u-boot:image-pos': 140,
5154 'atf-fip/u-boot:offset': 140,
5155 'atf-fip/u-boot:size': 4,
5156 'atf-fip:image-pos': 0,
5157 'atf-fip:offset': 0,
5158 'atf-fip:size': 144,
5159 'image-pos': 0,
5160 'offset': 0,
5161 'fdtmap:image-pos': fdtmap.image_pos,
5162 'fdtmap:offset': fdtmap.offset,
5163 'fdtmap:size': len(fdtmap_data),
5164 'size': len(data),
5165 }, props)
5166
5167 def testFipExtractOneEntry(self):
5168 """Test extracting a single entry fron an FIP"""
5169 self._DoReadFileRealDtb('207_fip_ls.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07005170 image_fname = tools.get_output_filename('image.bin')
Simon Glass75989722021-11-23 21:08:59 -07005171 fname = os.path.join(self._indir, 'output.extact')
5172 control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
Simon Glassc1aa66e2022-01-29 14:14:04 -07005173 data = tools.read_file(fname)
Simon Glass75989722021-11-23 21:08:59 -07005174 self.assertEqual(U_BOOT_DATA, data)
5175
5176 def testFipReplace(self):
5177 """Test replacing a single file in a FIP"""
Simon Glassc1aa66e2022-01-29 14:14:04 -07005178 expected = U_BOOT_DATA + tools.get_bytes(0x78, 50)
Simon Glass75989722021-11-23 21:08:59 -07005179 data = self._DoReadFileRealDtb('208_fip_replace.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07005180 updated_fname = tools.get_output_filename('image-updated.bin')
5181 tools.write_file(updated_fname, data)
Simon Glass75989722021-11-23 21:08:59 -07005182 entry_name = 'atf-fip/u-boot'
5183 control.WriteEntry(updated_fname, entry_name, expected,
5184 allow_resize=True)
5185 actual = control.ReadEntry(updated_fname, entry_name)
5186 self.assertEqual(expected, actual)
5187
Simon Glassc1aa66e2022-01-29 14:14:04 -07005188 new_data = tools.read_file(updated_fname)
Simon Glass75989722021-11-23 21:08:59 -07005189 hdr, fents = fip_util.decode_fip(new_data)
5190
5191 self.assertEqual(2, len(fents))
5192
5193 # Check that the FIP entry is updated
5194 fent = fents[1]
5195 self.assertEqual(0x8c, fent.offset)
5196 self.assertEqual(len(expected), fent.size)
5197 self.assertEqual(0, fent.flags)
5198 self.assertEqual(expected, fent.data)
5199 self.assertEqual(True, fent.valid)
5200
5201 def testFipMissing(self):
5202 with test_util.capture_sys_output() as (stdout, stderr):
5203 self._DoTestFile('209_fip_missing.dts', allow_missing=True)
5204 err = stderr.getvalue()
5205 self.assertRegex(err, "Image 'main-section'.*missing.*: rmm-fw")
5206
5207 def testFipSize(self):
5208 """Test a FIP with a size property"""
5209 data = self._DoReadFile('210_fip_size.dts')
5210 self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
5211 hdr, fents = fip_util.decode_fip(data)
5212 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5213 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5214
5215 self.assertEqual(1, len(fents))
5216
5217 fent = fents[0]
5218 self.assertEqual('soc-fw', fent.fip_type)
5219 self.assertEqual(0x60, fent.offset)
5220 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5221 self.assertEqual(ATF_BL31_DATA, fent.data)
5222 self.assertEqual(True, fent.valid)
5223
5224 rest = data[0x60 + len(ATF_BL31_DATA):0x100]
Simon Glassc1aa66e2022-01-29 14:14:04 -07005225 self.assertEqual(tools.get_bytes(0xff, len(rest)), rest)
Simon Glass75989722021-11-23 21:08:59 -07005226
5227 def testFipBadAlign(self):
5228 """Test that an invalid alignment value in a FIP is detected"""
5229 with self.assertRaises(ValueError) as e:
5230 self._DoTestFile('211_fip_bad_align.dts')
5231 self.assertIn(
5232 "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
5233 str(e.exception))
5234
5235 def testFipCollection(self):
5236 """Test using a FIP in a collection"""
5237 data = self._DoReadFile('212_fip_collection.dts')
5238 entry1 = control.images['image'].GetEntries()['collection']
5239 data1 = data[:entry1.size]
5240 hdr1, fents2 = fip_util.decode_fip(data1)
5241
5242 entry2 = control.images['image'].GetEntries()['atf-fip']
5243 data2 = data[entry2.offset:entry2.offset + entry2.size]
5244 hdr1, fents2 = fip_util.decode_fip(data2)
5245
5246 # The 'collection' entry should have U-Boot included at the end
5247 self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
5248 self.assertEqual(data1, data2 + U_BOOT_DATA)
5249 self.assertEqual(U_BOOT_DATA, data1[-4:])
5250
5251 # There should be a U-Boot after the final FIP
5252 self.assertEqual(U_BOOT_DATA, data[-4:])
Simon Glassc69d19c2021-07-06 10:36:37 -06005253
Simon Glass32d4f102022-01-12 13:10:35 -07005254 def testFakeBlob(self):
5255 """Test handling of faking an external blob"""
5256 with test_util.capture_sys_output() as (stdout, stderr):
5257 self._DoTestFile('217_fake_blob.dts', allow_missing=True,
5258 allow_fake_blobs=True)
5259 err = stderr.getvalue()
5260 self.assertRegex(
5261 err,
5262 "Image '.*' has faked external blobs and is non-functional: .*")
Simon Glass32d4f102022-01-12 13:10:35 -07005263
Simon Glassf4590e02022-01-09 20:13:46 -07005264 def testExtblobListFaked(self):
5265 """Test an extblob with missing external blob that are faked"""
5266 with test_util.capture_sys_output() as (stdout, stderr):
5267 self._DoTestFile('216_blob_ext_list_missing.dts',
5268 allow_fake_blobs=True)
5269 err = stderr.getvalue()
5270 self.assertRegex(err, "Image 'main-section'.*faked.*: blob-ext-list")
5271
Simon Glass56ee85e2022-01-09 20:13:57 -07005272 def testListBintools(self):
5273 args = ['tool', '--list']
5274 with test_util.capture_sys_output() as (stdout, _):
5275 self._DoBinman(*args)
5276 out = stdout.getvalue().splitlines()
5277 self.assertTrue(len(out) >= 2)
5278
5279 def testFetchBintools(self):
5280 def fail_download(url):
Simon Glassc1aa66e2022-01-29 14:14:04 -07005281 """Take the tools.download() function by raising an exception"""
Simon Glass56ee85e2022-01-09 20:13:57 -07005282 raise urllib.error.URLError('my error')
5283
5284 args = ['tool']
5285 with self.assertRaises(ValueError) as e:
5286 self._DoBinman(*args)
5287 self.assertIn("Invalid arguments to 'tool' subcommand",
5288 str(e.exception))
5289
5290 args = ['tool', '--fetch']
5291 with self.assertRaises(ValueError) as e:
5292 self._DoBinman(*args)
5293 self.assertIn('Please specify bintools to fetch', str(e.exception))
5294
5295 args = ['tool', '--fetch', '_testing']
Simon Glassc1aa66e2022-01-29 14:14:04 -07005296 with unittest.mock.patch.object(tools, 'download',
Simon Glass56ee85e2022-01-09 20:13:57 -07005297 side_effect=fail_download):
5298 with test_util.capture_sys_output() as (stdout, _):
5299 self._DoBinman(*args)
5300 self.assertIn('failed to fetch with all methods', stdout.getvalue())
5301
Simon Glassbc570642022-01-09 20:14:11 -07005302 def testBintoolDocs(self):
5303 """Test for creation of bintool documentation"""
5304 with test_util.capture_sys_output() as (stdout, stderr):
5305 control.write_bintool_docs(control.bintool.Bintool.get_tool_list())
5306 self.assertTrue(len(stdout.getvalue()) > 0)
5307
5308 def testBintoolDocsMissing(self):
5309 """Test handling of missing bintool documentation"""
5310 with self.assertRaises(ValueError) as e:
5311 with test_util.capture_sys_output() as (stdout, stderr):
5312 control.write_bintool_docs(
5313 control.bintool.Bintool.get_tool_list(), 'mkimage')
5314 self.assertIn('Documentation is missing for modules: mkimage',
5315 str(e.exception))
5316
Jan Kiszkafcc87ef2022-01-28 20:37:53 +01005317 def testListWithGenNode(self):
5318 """Check handling of an FDT map when the section cannot be found"""
5319 entry_args = {
5320 'of-list': 'test-fdt1 test-fdt2',
5321 }
5322 data = self._DoReadFileDtb(
5323 '219_fit_gennode.dts',
5324 entry_args=entry_args,
5325 use_real_dtb=True,
5326 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])
5327
5328 try:
5329 tmpdir, updated_fname = self._SetupImageInTmpdir()
5330 with test_util.capture_sys_output() as (stdout, stderr):
5331 self._RunBinman('ls', '-i', updated_fname)
5332 finally:
5333 shutil.rmtree(tmpdir)
5334
Alper Nebi Yasaked293c32022-02-08 01:08:05 +03005335 def testFitSubentryUsesBintool(self):
5336 """Test that binman FIT subentries can use bintools"""
5337 command.test_result = self._HandleGbbCommand
5338 entry_args = {
5339 'keydir': 'devkeys',
5340 'bmpblk': 'bmpblk.bin',
5341 }
5342 data, _, _, _ = self._DoReadFileDtb('220_fit_subentry_bintool.dts',
5343 entry_args=entry_args)
5344
Alper Nebi Yasakf3078d42022-02-08 01:08:07 +03005345 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
5346 tools.get_bytes(0, 0x2180 - 16))
Alper Nebi Yasaked293c32022-02-08 01:08:05 +03005347 self.assertIn(expected, data)
5348
5349 def testFitSubentryMissingBintool(self):
5350 """Test that binman reports missing bintools for FIT subentries"""
5351 entry_args = {
5352 'keydir': 'devkeys',
5353 }
5354 with test_util.capture_sys_output() as (_, stderr):
5355 self._DoTestFile('220_fit_subentry_bintool.dts',
5356 force_missing_bintools='futility', entry_args=entry_args)
5357 err = stderr.getvalue()
5358 self.assertRegex(err,
5359 "Image 'main-section'.*missing bintools.*: futility")
Simon 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):
5822 """Test replacing a simple section with arbitrary data"""
5823 new_data = b'w' * len(COMPRESS_DATA + U_BOOT_DATA)
Simon Glass73593e42022-08-13 11:40:46 -06005824 with self.assertRaises(ValueError) as exc:
5825 self._RunReplaceCmd('section', new_data,
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005826 dts='241_replace_section_simple.dts')
Simon Glass73593e42022-08-13 11:40:46 -06005827 self.assertIn(
5828 "Node '/section': Replacing sections is not implemented yet",
5829 str(exc.exception))
Alper Nebi Yasak82337bb2022-03-27 18:31:50 +03005830
Simon Glassdfe1db42022-08-13 11:40:48 -06005831 def testMkimageImagename(self):
5832 """Test using mkimage with -n holding the data too"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005833 data = self._DoReadFile('242_mkimage_name.dts')
Simon Glassdfe1db42022-08-13 11:40:48 -06005834
5835 # Check that the data appears in the file somewhere
5836 self.assertIn(U_BOOT_SPL_DATA, data)
5837
Simon Glassf3543e62022-09-06 20:26:52 -06005838 # Get struct legacy_img_hdr -> ih_name
Simon Glassdfe1db42022-08-13 11:40:48 -06005839 name = data[0x20:0x40]
5840
5841 # Build the filename that we expect to be placed in there, by virtue of
5842 # the -n paraameter
5843 expect = os.path.join(tools.get_output_dir(), 'mkimage.mkimage')
5844
5845 # Check that the image name is set to the temporary filename used
5846 self.assertEqual(expect.encode('utf-8')[:0x20], name)
5847
Simon Glass9db9e932022-08-13 11:40:49 -06005848 def testMkimageImage(self):
5849 """Test using mkimage with -n holding the data too"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005850 data = self._DoReadFile('243_mkimage_image.dts')
Simon Glass9db9e932022-08-13 11:40:49 -06005851
5852 # Check that the data appears in the file somewhere
5853 self.assertIn(U_BOOT_SPL_DATA, data)
5854
Simon Glassf3543e62022-09-06 20:26:52 -06005855 # Get struct legacy_img_hdr -> ih_name
Simon Glass9db9e932022-08-13 11:40:49 -06005856 name = data[0x20:0x40]
5857
5858 # Build the filename that we expect to be placed in there, by virtue of
5859 # the -n paraameter
5860 expect = os.path.join(tools.get_output_dir(), 'mkimage-n.mkimage')
5861
5862 # Check that the image name is set to the temporary filename used
5863 self.assertEqual(expect.encode('utf-8')[:0x20], name)
5864
5865 # Check the corect data is in the imagename file
5866 self.assertEqual(U_BOOT_DATA, tools.read_file(expect))
5867
5868 def testMkimageImageNoContent(self):
5869 """Test using mkimage with -n and no data"""
5870 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005871 self._DoReadFile('244_mkimage_image_no_content.dts')
Simon Glass9db9e932022-08-13 11:40:49 -06005872 self.assertIn('Could not complete processing of contents',
5873 str(exc.exception))
5874
5875 def testMkimageImageBad(self):
5876 """Test using mkimage with imagename node and data-to-imagename"""
5877 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005878 self._DoReadFile('245_mkimage_image_bad.dts')
Simon Glass9db9e932022-08-13 11:40:49 -06005879 self.assertIn('Cannot use both imagename node and data-to-imagename',
5880 str(exc.exception))
5881
Simon Glassd626e822022-08-13 11:40:50 -06005882 def testCollectionOther(self):
5883 """Test a collection where the data comes from another section"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005884 data = self._DoReadFile('246_collection_other.dts')
Simon Glassd626e822022-08-13 11:40:50 -06005885 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
5886 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
5887 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
5888 data)
5889
5890 def testMkimageCollection(self):
5891 """Test using a collection referring to an entry in a mkimage entry"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005892 data = self._DoReadFile('247_mkimage_coll.dts')
Simon Glassd626e822022-08-13 11:40:50 -06005893 expect = U_BOOT_SPL_DATA + U_BOOT_DATA
5894 self.assertEqual(expect, data[:len(expect)])
5895
Stefan Herbrechtsmeier6aa80002022-08-19 16:25:25 +02005896 def testCompressDtbPrependInvalid(self):
5897 """Test that invalid header is detected"""
5898 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005899 self._DoReadFileDtb('248_compress_dtb_prepend_invalid.dts')
Stefan Herbrechtsmeier6aa80002022-08-19 16:25:25 +02005900 self.assertIn("Node '/binman/u-boot-dtb': Invalid prepend in "
5901 "'u-boot-dtb': 'invalid'", str(e.exception))
5902
5903 def testCompressDtbPrependLength(self):
5904 """Test that compress with length header works as expected"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005905 data = self._DoReadFileRealDtb('249_compress_dtb_prepend_length.dts')
Stefan Herbrechtsmeier6aa80002022-08-19 16:25:25 +02005906 image = control.images['image']
5907 entries = image.GetEntries()
5908 self.assertIn('u-boot-dtb', entries)
5909 u_boot_dtb = entries['u-boot-dtb']
5910 self.assertIn('fdtmap', entries)
5911 fdtmap = entries['fdtmap']
5912
5913 image_fname = tools.get_output_filename('image.bin')
5914 orig = control.ReadEntry(image_fname, 'u-boot-dtb')
5915 dtb = fdt.Fdt.FromData(orig)
5916 dtb.Scan()
5917 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
5918 expected = {
5919 'u-boot:size': len(U_BOOT_DATA),
5920 'u-boot-dtb:uncomp-size': len(orig),
5921 'u-boot-dtb:size': u_boot_dtb.size,
5922 'fdtmap:size': fdtmap.size,
5923 'size': len(data),
5924 }
5925 self.assertEqual(expected, props)
5926
5927 # Check implementation
5928 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
5929 rest = data[len(U_BOOT_DATA):]
5930 comp_data_len = struct.unpack('<I', rest[:4])[0]
5931 comp_data = rest[4:4 + comp_data_len]
5932 orig2 = self._decompress(comp_data)
5933 self.assertEqual(orig, orig2)
5934
Stefan Herbrechtsmeierec7d27d2022-08-19 16:25:30 +02005935 def testInvalidCompress(self):
5936 """Test that invalid compress algorithm is detected"""
5937 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005938 self._DoTestFile('250_compress_dtb_invalid.dts')
Stefan Herbrechtsmeierec7d27d2022-08-19 16:25:30 +02005939 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
5940
Stefan Herbrechtsmeierda1af352022-08-19 16:25:32 +02005941 def testCompUtilCompressions(self):
5942 """Test compression algorithms"""
5943 for bintool in self.comp_bintools.values():
5944 self._CheckBintool(bintool)
5945 data = bintool.compress(COMPRESS_DATA)
5946 self.assertNotEqual(COMPRESS_DATA, data)
5947 orig = bintool.decompress(data)
5948 self.assertEquals(COMPRESS_DATA, orig)
5949
5950 def testCompUtilVersions(self):
5951 """Test tool version of compression algorithms"""
5952 for bintool in self.comp_bintools.values():
5953 self._CheckBintool(bintool)
5954 version = bintool.version()
5955 self.assertRegex(version, '^v?[0-9]+[0-9.]*')
5956
5957 def testCompUtilPadding(self):
5958 """Test padding of compression algorithms"""
Stefan Herbrechtsmeiercd15b642022-08-19 16:25:38 +02005959 # Skip zstd because it doesn't support padding
5960 for bintool in [v for k,v in self.comp_bintools.items() if k != 'zstd']:
Stefan Herbrechtsmeierda1af352022-08-19 16:25:32 +02005961 self._CheckBintool(bintool)
5962 data = bintool.compress(COMPRESS_DATA)
5963 self.assertNotEqual(COMPRESS_DATA, data)
5964 data += tools.get_bytes(0, 64)
5965 orig = bintool.decompress(data)
5966 self.assertEquals(COMPRESS_DATA, orig)
5967
Stefan Herbrechtsmeiercd15b642022-08-19 16:25:38 +02005968 def testCompressDtbZstd(self):
5969 """Test that zstd compress of device-tree files failed"""
5970 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005971 self._DoTestFile('251_compress_dtb_zstd.dts')
Stefan Herbrechtsmeiercd15b642022-08-19 16:25:38 +02005972 self.assertIn("Node '/binman/u-boot-dtb': The zstd compression "
5973 "requires a length header", str(e.exception))
5974
Quentin Schulz4d91df02022-09-02 15:10:48 +02005975 def testMkimageMultipleDataFiles(self):
5976 """Test passing multiple files to mkimage in a mkimage entry"""
5977 data = self._DoReadFile('252_mkimage_mult_data.dts')
5978 # Size of files are packed in their 4B big-endian format
5979 expect = struct.pack('>I', len(U_BOOT_TPL_DATA))
5980 expect += struct.pack('>I', len(U_BOOT_SPL_DATA))
5981 # Size info is always followed by a 4B zero value.
5982 expect += tools.get_bytes(0, 4)
5983 expect += U_BOOT_TPL_DATA
5984 # All but last files are 4B-aligned
5985 align_pad = len(U_BOOT_TPL_DATA) % 4
5986 if align_pad:
5987 expect += tools.get_bytes(0, align_pad)
5988 expect += U_BOOT_SPL_DATA
5989 self.assertEqual(expect, data[-len(expect):])
5990
5991 def testMkimageMultipleNoContent(self):
5992 """Test passing multiple data files to mkimage with one data file having no content"""
5993 with self.assertRaises(ValueError) as exc:
5994 self._DoReadFile('253_mkimage_mult_no_content.dts')
5995 self.assertIn('Could not complete processing of contents',
5996 str(exc.exception))
5997
Quentin Schulz6cc29dc2022-09-02 15:10:49 +02005998 def testMkimageFilename(self):
5999 """Test using mkimage to build a binary with a filename"""
6000 retcode = self._DoTestFile('254_mkimage_filename.dts')
6001 self.assertEqual(0, retcode)
6002 fname = tools.get_output_filename('mkimage-test.bin')
6003 self.assertTrue(os.path.exists(fname))
6004
Simon Glass6ad24522022-02-28 07:16:54 -07006005 def testVpl(self):
6006 """Test that an image with VPL and its device tree can be created"""
6007 # ELF file with a '__bss_size' symbol
6008 self._SetupVplElf()
6009 data = self._DoReadFile('255_u_boot_vpl.dts')
6010 self.assertEqual(U_BOOT_VPL_DATA + U_BOOT_VPL_DTB_DATA, data)
6011
6012 def testVplNoDtb(self):
6013 """Test that an image with vpl/u-boot-vpl-nodtb.bin can be created"""
6014 self._SetupVplElf()
6015 data = self._DoReadFile('256_u_boot_vpl_nodtb.dts')
6016 self.assertEqual(U_BOOT_VPL_NODTB_DATA,
6017 data[:len(U_BOOT_VPL_NODTB_DATA)])
6018
6019 def testExpandedVpl(self):
6020 """Test that an expanded entry type is selected for TPL when needed"""
6021 self._SetupVplElf()
6022
6023 entry_args = {
6024 'vpl-bss-pad': 'y',
6025 'vpl-dtb': 'y',
6026 }
6027 self._DoReadFileDtb('257_fdt_incl_vpl.dts', use_expanded=True,
6028 entry_args=entry_args)
6029 image = control.images['image']
6030 entries = image.GetEntries()
6031 self.assertEqual(1, len(entries))
6032
6033 # We only have u-boot-vpl, which be expanded
6034 self.assertIn('u-boot-vpl', entries)
6035 entry = entries['u-boot-vpl']
6036 self.assertEqual('u-boot-vpl-expanded', entry.etype)
6037 subent = entry.GetEntries()
6038 self.assertEqual(3, len(subent))
6039 self.assertIn('u-boot-vpl-nodtb', subent)
6040 self.assertIn('u-boot-vpl-bss-pad', subent)
6041 self.assertIn('u-boot-vpl-dtb', subent)
6042
6043 def testVplBssPadMissing(self):
6044 """Test that a missing symbol is detected"""
6045 self._SetupVplElf('u_boot_ucode_ptr')
6046 with self.assertRaises(ValueError) as e:
6047 self._DoReadFile('258_vpl_bss_pad.dts')
6048 self.assertIn('Expected __bss_size symbol in vpl/u-boot-vpl',
6049 str(e.exception))
6050
Neha Malcom Francis3545e852022-10-17 16:36:25 +05306051 def testSymlink(self):
6052 """Test that image files can be named"""
6053 retcode = self._DoTestFile('259_symlink.dts', debug=True, map=True)
6054 self.assertEqual(0, retcode)
6055 image = control.images['test_image']
6056 fname = tools.get_output_filename('test_image.bin')
6057 sname = tools.get_output_filename('symlink_to_test.bin')
6058 self.assertTrue(os.path.islink(sname))
6059 self.assertEqual(os.readlink(sname), fname)
Alper Nebi Yasak8ee4ec92022-03-27 18:31:45 +03006060
Simon Glassd2afb9e2022-10-20 18:22:47 -06006061 def testSymbolsElf(self):
6062 """Test binman can assign symbols embedded in an ELF file"""
6063 if not elf.ELF_TOOLS:
6064 self.skipTest('Python elftools not available')
6065 self._SetupTplElf('u_boot_binman_syms')
6066 self._SetupVplElf('u_boot_binman_syms')
6067 self._SetupSplElf('u_boot_binman_syms')
6068 data = self._DoReadFileDtb('260_symbols_elf.dts')[0]
6069 image_fname = tools.get_output_filename('image.bin')
6070
6071 image = control.images['image']
6072 entries = image.GetEntries()
6073
6074 for entry in entries.values():
6075 # No symbols in u-boot and it has faked contents anyway
6076 if entry.name == 'u-boot':
6077 continue
6078 edata = data[entry.image_pos:entry.image_pos + entry.size]
6079 efname = tools.get_output_filename(f'edata-{entry.name}')
6080 tools.write_file(efname, edata)
6081
6082 syms = elf.GetSymbolFileOffset(efname, ['_binman_u_boot'])
6083 re_name = re.compile('_binman_(u_boot_(.*))_prop_(.*)')
6084 for name, sym in syms.items():
6085 msg = 'test'
6086 val = elf.GetSymbolValue(sym, edata, msg)
6087 entry_m = re_name.match(name)
6088 if entry_m:
6089 ename, prop = entry_m.group(1), entry_m.group(3)
6090 entry, entry_name, prop_name = image.LookupEntry(entries,
6091 name, msg)
6092 if prop_name == 'offset':
6093 expect_val = entry.offset
6094 elif prop_name == 'image_pos':
6095 expect_val = entry.image_pos
6096 elif prop_name == 'size':
6097 expect_val = entry.size
6098 self.assertEqual(expect_val, val)
6099
6100 def testSymbolsElfBad(self):
6101 """Check error when trying to write symbols without the elftools lib"""
6102 if not elf.ELF_TOOLS:
6103 self.skipTest('Python elftools not available')
6104 self._SetupTplElf('u_boot_binman_syms')
6105 self._SetupVplElf('u_boot_binman_syms')
6106 self._SetupSplElf('u_boot_binman_syms')
6107 try:
6108 elf.ELF_TOOLS = False
6109 with self.assertRaises(ValueError) as exc:
6110 self._DoReadFileDtb('260_symbols_elf.dts')
6111 finally:
6112 elf.ELF_TOOLS = True
6113 self.assertIn(
6114 "Section '/binman': entry '/binman/u-boot-spl-elf': "
6115 'Cannot write symbols to an ELF file without Python elftools',
6116 str(exc.exception))
6117
Simon Glassefddab62023-01-07 14:07:08 -07006118 def testSectionFilename(self):
6119 """Check writing of section contents to a file"""
6120 data = self._DoReadFile('261_section_fname.dts')
6121 expected = (b'&&' + U_BOOT_DATA + b'&&&' +
6122 tools.get_bytes(ord('!'), 7) +
6123 U_BOOT_DATA + tools.get_bytes(ord('&'), 12))
6124 self.assertEqual(expected, data)
6125
6126 sect_fname = tools.get_output_filename('outfile.bin')
6127 self.assertTrue(os.path.exists(sect_fname))
6128 sect_data = tools.read_file(sect_fname)
6129 self.assertEqual(U_BOOT_DATA, sect_data)
6130
Simon Glassc8c9f312023-01-07 14:07:12 -07006131 def testAbsent(self):
6132 """Check handling of absent entries"""
6133 data = self._DoReadFile('262_absent.dts')
6134 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6135
Simon Glass2f80c5e2023-01-07 14:07:14 -07006136 def testPackTeeOsOptional(self):
6137 """Test that an image with an optional TEE binary can be created"""
6138 entry_args = {
6139 'tee-os-path': 'tee.elf',
6140 }
6141 data = self._DoReadFileDtb('263_tee_os_opt.dts',
6142 entry_args=entry_args)[0]
6143 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6144
6145 def checkFitTee(self, dts, tee_fname):
6146 """Check that a tee-os entry works and returns data
6147
6148 Args:
6149 dts (str): Device tree filename to use
6150 tee_fname (str): filename containing tee-os
6151
6152 Returns:
6153 bytes: Image contents
6154 """
6155 if not elf.ELF_TOOLS:
6156 self.skipTest('Python elftools not available')
6157 entry_args = {
6158 'of-list': 'test-fdt1 test-fdt2',
6159 'default-dt': 'test-fdt2',
6160 'tee-os-path': tee_fname,
6161 }
6162 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
6163 data = self._DoReadFileDtb(dts, entry_args=entry_args,
6164 extra_indirs=[test_subdir])[0]
6165 return data
6166
6167 def testFitTeeOsOptionalFit(self):
6168 """Test an image with a FIT with an optional OP-TEE binary"""
6169 data = self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bin')
6170
6171 # There should be only one node, holding the data set up in SetUpClass()
6172 # for tee.bin
6173 dtb = fdt.Fdt.FromData(data)
6174 dtb.Scan()
6175 node = dtb.GetNode('/images/tee-1')
6176 self.assertEqual(TEE_ADDR,
6177 fdt_util.fdt32_to_cpu(node.props['load'].value))
6178 self.assertEqual(TEE_ADDR,
6179 fdt_util.fdt32_to_cpu(node.props['entry'].value))
6180 self.assertEqual(U_BOOT_DATA, node.props['data'].bytes)
6181
6182 def testFitTeeOsOptionalFitBad(self):
6183 """Test an image with a FIT with an optional OP-TEE binary"""
6184 with self.assertRaises(ValueError) as exc:
6185 self.checkFitTee('265_tee_os_opt_fit_bad.dts', 'tee.bin')
6186 self.assertIn(
6187 "Node '/binman/fit': subnode 'images/@tee-SEQ': Failed to read ELF file: Magic number does not match",
6188 str(exc.exception))
6189
6190 def testFitTeeOsBad(self):
6191 """Test an OP-TEE binary with wrong formats"""
6192 self.make_tee_bin('tee.bad1', 123)
6193 with self.assertRaises(ValueError) as exc:
6194 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad1')
6195 self.assertIn(
6196 "Node '/binman/fit/images/@tee-SEQ/tee-os': OP-TEE paged mode not supported",
6197 str(exc.exception))
6198
6199 self.make_tee_bin('tee.bad2', 0, b'extra data')
6200 with self.assertRaises(ValueError) as exc:
6201 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad2')
6202 self.assertIn(
6203 "Node '/binman/fit/images/@tee-SEQ/tee-os': Invalid OP-TEE file: size mismatch (expected 0x4, have 0xe)",
6204 str(exc.exception))
6205
Simon Glass67a05012023-01-07 14:07:15 -07006206 def testExtblobOptional(self):
6207 """Test an image with an external blob that is optional"""
6208 with test_util.capture_sys_output() as (stdout, stderr):
6209 data = self._DoReadFile('266_blob_ext_opt.dts')
6210 self.assertEqual(REFCODE_DATA, data)
6211 err = stderr.getvalue()
6212 self.assertRegex(
6213 err,
6214 "Image '.*' is missing external blobs but is still functional: missing")
6215
Simon Glass0b079fc2023-01-11 16:10:12 -07006216 def testSectionInner(self):
6217 """Test an inner section with a size"""
6218 data = self._DoReadFile('267_section_inner.dts')
6219 expected = U_BOOT_DATA + tools.get_bytes(0, 12)
6220 self.assertEqual(expected, data)
6221
Simon Glass62ef2f72023-01-11 16:10:14 -07006222 def testNull(self):
6223 """Test an image with a null entry"""
6224 data = self._DoReadFile('268_null.dts')
6225 self.assertEqual(U_BOOT_DATA + b'\xff\xff\xff\xff' + U_BOOT_IMG_DATA, data)
6226
Simon Glass9766f692023-01-11 16:10:16 -07006227 def testOverlap(self):
6228 """Test an image with a overlapping entry"""
6229 data = self._DoReadFile('269_overlap.dts')
6230 self.assertEqual(U_BOOT_DATA[:1] + b'aa' + U_BOOT_DATA[3:], data)
6231
6232 image = control.images['image']
6233 entries = image.GetEntries()
6234
6235 self.assertIn('inset', entries)
6236 inset = entries['inset']
6237 self.assertEqual(1, inset.offset);
6238 self.assertEqual(1, inset.image_pos);
6239 self.assertEqual(2, inset.size);
6240
6241 def testOverlapNull(self):
6242 """Test an image with a null overlap"""
6243 data = self._DoReadFile('270_overlap_null.dts')
6244 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6245
6246 # Check the FMAP
6247 fhdr, fentries = fmap_util.DecodeFmap(data[len(U_BOOT_DATA):])
6248 self.assertEqual(4, fhdr.nareas)
6249 fiter = iter(fentries)
6250
6251 fentry = next(fiter)
6252 self.assertEqual(b'SECTION', fentry.name)
6253 self.assertEqual(0, fentry.offset)
6254 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6255 self.assertEqual(0, fentry.flags)
6256
6257 fentry = next(fiter)
6258 self.assertEqual(b'U_BOOT', fentry.name)
6259 self.assertEqual(0, fentry.offset)
6260 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6261 self.assertEqual(0, fentry.flags)
6262
6263 # Make sure that the NULL entry appears in the FMAP
6264 fentry = next(fiter)
6265 self.assertEqual(b'NULL', fentry.name)
6266 self.assertEqual(1, fentry.offset)
6267 self.assertEqual(2, fentry.size)
6268 self.assertEqual(0, fentry.flags)
6269
6270 fentry = next(fiter)
6271 self.assertEqual(b'FMAP', fentry.name)
6272 self.assertEqual(len(U_BOOT_DATA), fentry.offset)
6273
6274 def testOverlapBad(self):
6275 """Test an image with a bad overlapping entry"""
6276 with self.assertRaises(ValueError) as exc:
6277 self._DoReadFile('271_overlap_bad.dts')
6278 self.assertIn(
6279 "Node '/binman/inset': Offset 0x10 (16) ending at 0x12 (18) must overlap with existing entries",
6280 str(exc.exception))
6281
6282 def testOverlapNoOffset(self):
6283 """Test an image with a bad overlapping entry"""
6284 with self.assertRaises(ValueError) as exc:
6285 self._DoReadFile('272_overlap_no_size.dts')
6286 self.assertIn(
6287 "Node '/binman/inset': 'fill' entry is missing properties: size",
6288 str(exc.exception))
6289
Simon Glassc1157862023-01-11 16:10:17 -07006290 def testBlobSymbol(self):
6291 """Test a blob with symbols read from an ELF file"""
6292 elf_fname = self.ElfTestFile('blob_syms')
6293 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6294 TestFunctional._MakeInputFile('blob_syms.bin',
6295 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6296
6297 data = self._DoReadFile('273_blob_symbol.dts')
6298
6299 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6300 addr = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6301 self.assertEqual(syms['_binman_sym_magic'].address, addr)
6302 self.assertEqual(syms['_binman_inset_prop_offset'].address, addr + 4)
6303 self.assertEqual(syms['_binman_inset_prop_size'].address, addr + 8)
6304
6305 sym_values = struct.pack('<LLL', elf.BINMAN_SYM_MAGIC_VALUE, 4, 8)
6306 expected = sym_values
6307 self.assertEqual(expected, data[:len(expected)])
6308
Simon Glass571bc4e2023-01-11 16:10:19 -07006309 def testOffsetFromElf(self):
6310 """Test a blob with symbols read from an ELF file"""
6311 elf_fname = self.ElfTestFile('blob_syms')
6312 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6313 TestFunctional._MakeInputFile('blob_syms.bin',
6314 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6315
6316 data = self._DoReadFile('274_offset_from_elf.dts')
6317
6318 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6319 base = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6320
6321 image = control.images['image']
6322 entries = image.GetEntries()
6323
6324 self.assertIn('inset', entries)
6325 inset = entries['inset']
6326
6327 self.assertEqual(base + 4, inset.offset);
6328 self.assertEqual(base + 4, inset.image_pos);
6329 self.assertEqual(4, inset.size);
6330
6331 self.assertIn('inset2', entries)
6332 inset = entries['inset2']
6333 self.assertEqual(base + 8, inset.offset);
6334 self.assertEqual(base + 8, inset.image_pos);
6335 self.assertEqual(4, inset.size);
6336
Jonas Karlman9b2fd2d2023-01-21 19:01:39 +00006337 def testFitAlign(self):
6338 """Test an image with an FIT with aligned external data"""
6339 data = self._DoReadFile('275_fit_align.dts')
6340 self.assertEqual(4096, len(data))
6341
6342 dtb = fdt.Fdt.FromData(data)
6343 dtb.Scan()
6344
6345 props = self._GetPropTree(dtb, ['data-position'])
6346 expected = {
6347 'u-boot:data-position': 1024,
6348 'fdt-1:data-position': 2048,
6349 'fdt-2:data-position': 3072,
6350 }
6351 self.assertEqual(expected, props)
6352
Jonas Karlmanf584d442023-01-21 19:02:12 +00006353 def testFitFirmwareLoadables(self):
6354 """Test an image with an FIT that use fit,firmware"""
6355 if not elf.ELF_TOOLS:
6356 self.skipTest('Python elftools not available')
6357 entry_args = {
6358 'of-list': 'test-fdt1',
6359 'default-dt': 'test-fdt1',
6360 'atf-bl31-path': 'bl31.elf',
6361 'tee-os-path': 'missing.bin',
6362 }
6363 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
6364 data = self._DoReadFileDtb(
6365 '276_fit_firmware_loadables.dts',
6366 entry_args=entry_args,
6367 extra_indirs=[test_subdir])[0]
6368
6369 dtb = fdt.Fdt.FromData(data)
6370 dtb.Scan()
6371
6372 node = dtb.GetNode('/configurations/conf-uboot-1')
6373 self.assertEqual('u-boot', node.props['firmware'].value)
6374 self.assertEqual(['atf-1', 'atf-2'],
6375 fdt_util.GetStringList(node, 'loadables'))
6376
6377 node = dtb.GetNode('/configurations/conf-atf-1')
6378 self.assertEqual('atf-1', node.props['firmware'].value)
6379 self.assertEqual(['u-boot', 'atf-2'],
6380 fdt_util.GetStringList(node, 'loadables'))
6381
6382 node = dtb.GetNode('/configurations/conf-missing-uboot-1')
6383 self.assertEqual('u-boot', node.props['firmware'].value)
6384 self.assertEqual(['atf-1', 'atf-2'],
6385 fdt_util.GetStringList(node, 'loadables'))
6386
6387 node = dtb.GetNode('/configurations/conf-missing-atf-1')
6388 self.assertEqual('atf-1', node.props['firmware'].value)
6389 self.assertEqual(['u-boot', 'atf-2'],
6390 fdt_util.GetStringList(node, 'loadables'))
6391
6392 node = dtb.GetNode('/configurations/conf-missing-tee-1')
6393 self.assertEqual('atf-1', node.props['firmware'].value)
6394 self.assertEqual(['u-boot', 'atf-2'],
6395 fdt_util.GetStringList(node, 'loadables'))
6396
Simon Glassefddab62023-01-07 14:07:08 -07006397
Simon Glass9fc60b42017-11-12 21:52:22 -07006398if __name__ == "__main__":
6399 unittest.main()