blob: 26913bb094ae810af92e5a325db423dc16d8f417 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001# SPDX-License-Identifier: GPL-2.0+
Simon Glass4f443042016-11-25 20:15:52 -07002# Copyright (c) 2016 Google, Inc
3# Written by Simon Glass <sjg@chromium.org>
4#
Simon Glass4f443042016-11-25 20:15:52 -07005# To run a single test, change to this directory, and:
6#
7# python -m unittest func_test.TestFunctional.testHelp
8
Simon Glassfdc34362020-07-09 18:39:45 -06009import collections
Simon Glass16287932020-04-17 18:09:03 -060010import gzip
Simon Glasse0e5df92018-09-14 04:57:31 -060011import hashlib
Simon Glass4f443042016-11-25 20:15:52 -070012from optparse import OptionParser
13import os
Simon Glassfdc34362020-07-09 18:39:45 -060014import re
Simon Glass4f443042016-11-25 20:15:52 -070015import shutil
16import struct
17import sys
18import tempfile
19import unittest
Simon Glass56ee85e2022-01-09 20:13:57 -070020import unittest.mock
21import urllib.error
Simon Glass4f443042016-11-25 20:15:52 -070022
Simon Glass386c63c2022-01-09 20:13:50 -070023from binman import bintool
Simon Glass16287932020-04-17 18:09:03 -060024from binman import cbfs_util
25from binman import cmdline
26from binman import control
27from binman import elf
28from binman import elf_test
Simon Glass75989722021-11-23 21:08:59 -070029from binman import fip_util
Simon Glass16287932020-04-17 18:09:03 -060030from binman import fmap_util
Simon Glass16287932020-04-17 18:09:03 -060031from binman import state
32from dtoc import fdt
33from dtoc import fdt_util
34from binman.etype import fdtmap
35from binman.etype import image_header
Simon Glass07237982020-08-05 13:27:47 -060036from binman.image import Image
Simon Glass4583c002023-02-23 18:18:04 -070037from u_boot_pylib import command
38from u_boot_pylib import test_util
39from u_boot_pylib import tools
40from u_boot_pylib import tout
Simon Glass4f443042016-11-25 20:15:52 -070041
42# Contents of test files, corresponding to different entry types
Simon Glassc6c10e72019-05-17 22:00:46 -060043U_BOOT_DATA = b'1234'
44U_BOOT_IMG_DATA = b'img'
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +030045U_BOOT_SPL_DATA = b'56780123456789abcdefghijklm'
46U_BOOT_TPL_DATA = b'tpl9876543210fedcbazywvuts'
Simon Glass6ad24522022-02-28 07:16:54 -070047U_BOOT_VPL_DATA = b'vpl76543210fedcbazywxyz_'
Simon Glassc6c10e72019-05-17 22:00:46 -060048BLOB_DATA = b'89'
49ME_DATA = b'0abcd'
50VGA_DATA = b'vga'
51U_BOOT_DTB_DATA = b'udtb'
52U_BOOT_SPL_DTB_DATA = b'spldtb'
53U_BOOT_TPL_DTB_DATA = b'tpldtb'
Simon Glass6ad24522022-02-28 07:16:54 -070054U_BOOT_VPL_DTB_DATA = b'vpldtb'
Simon Glassc6c10e72019-05-17 22:00:46 -060055X86_START16_DATA = b'start16'
56X86_START16_SPL_DATA = b'start16spl'
57X86_START16_TPL_DATA = b'start16tpl'
Simon Glass2250ee62019-08-24 07:22:48 -060058X86_RESET16_DATA = b'reset16'
59X86_RESET16_SPL_DATA = b'reset16spl'
60X86_RESET16_TPL_DATA = b'reset16tpl'
Simon Glassc6c10e72019-05-17 22:00:46 -060061PPC_MPC85XX_BR_DATA = b'ppcmpc85xxbr'
62U_BOOT_NODTB_DATA = b'nodtb with microcode pointer somewhere in here'
63U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here'
64U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here'
Simon Glass6ad24522022-02-28 07:16:54 -070065U_BOOT_VPL_NODTB_DATA = b'vplnodtb'
Alper Nebi Yasak21353312022-02-08 01:08:04 +030066U_BOOT_EXP_DATA = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
67U_BOOT_SPL_EXP_DATA = U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA
68U_BOOT_TPL_EXP_DATA = U_BOOT_TPL_NODTB_DATA + U_BOOT_TPL_DTB_DATA
Simon Glassc6c10e72019-05-17 22:00:46 -060069FSP_DATA = b'fsp'
70CMC_DATA = b'cmc'
71VBT_DATA = b'vbt'
72MRC_DATA = b'mrc'
Simon Glassbb748372018-07-17 13:25:33 -060073TEXT_DATA = 'text'
74TEXT_DATA2 = 'text2'
75TEXT_DATA3 = 'text3'
Simon Glassc6c10e72019-05-17 22:00:46 -060076CROS_EC_RW_DATA = b'ecrw'
77GBB_DATA = b'gbbd'
78BMPBLK_DATA = b'bmp'
79VBLOCK_DATA = b'vblk'
80FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
81 b"sorry you're alive\n")
Simon Glassff5c7e32019-07-08 13:18:42 -060082COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
Simon Glass8f5ef892020-10-26 17:40:25 -060083COMPRESS_DATA_BIG = COMPRESS_DATA * 2
Simon Glassc6c10e72019-05-17 22:00:46 -060084REFCODE_DATA = b'refcode'
Simon Glassea0fff92019-08-24 07:23:07 -060085FSP_M_DATA = b'fsp_m'
Simon Glassbc6a88f2019-10-20 21:31:35 -060086FSP_S_DATA = b'fsp_s'
Simon Glass998d1482019-10-20 21:31:36 -060087FSP_T_DATA = b'fsp_t'
Simon Glassdc2f81a2020-09-01 05:13:58 -060088ATF_BL31_DATA = b'bl31'
Roger Quadros47f420a2022-02-19 20:50:04 +020089TEE_OS_DATA = b'this is some tee OS data'
Simon Glass75989722021-11-23 21:08:59 -070090ATF_BL2U_DATA = b'bl2u'
Bin Meng4c4d6072021-05-10 20:23:33 +080091OPENSBI_DATA = b'opensbi'
Samuel Holland18bd4552020-10-21 21:12:15 -050092SCP_DATA = b'scp'
Jonas Karlman05b978b2023-02-25 19:01:33 +000093ROCKCHIP_TPL_DATA = b'rockchip-tpl'
Simon Glass6cf99532020-09-01 05:13:59 -060094TEST_FDT1_DATA = b'fdt1'
95TEST_FDT2_DATA = b'test-fdt2'
Simon Glassfb91d562020-09-06 10:35:33 -060096ENV_DATA = b'var1=1\nvar2="2"'
Philippe Reynesb1c50932022-03-28 22:57:04 +020097PRE_LOAD_MAGIC = b'UBSH'
98PRE_LOAD_VERSION = 0x11223344.to_bytes(4, 'big')
99PRE_LOAD_HDR_SIZE = 0x00001000.to_bytes(4, 'big')
Neha Malcom Francis6c66ccf2023-07-22 00:14:24 +0530100TI_BOARD_CONFIG_DATA = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
Neha Malcom Francis78144822023-07-22 00:14:25 +0530101TI_UNSECURE_DATA = b'unsecuredata'
Simon Glass6cf99532020-09-01 05:13:59 -0600102
103# Subdirectory of the input dir to use to put test FDTs
104TEST_FDT_SUBDIR = 'fdts'
Simon Glassec127af2018-07-17 13:25:39 -0600105
Simon Glass6ccbfcd2019-07-20 12:23:47 -0600106# The expected size for the device tree in some tests
Simon Glassf667e452019-07-08 14:25:50 -0600107EXTRACT_DTB_SIZE = 0x3c9
108
Simon Glass6ccbfcd2019-07-20 12:23:47 -0600109# Properties expected to be in the device tree when update_dtb is used
110BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
111
Simon Glass12bb1a92019-07-20 12:23:51 -0600112# Extra properties expected to be in the device tree when allow-repack is used
113REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
114
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +0200115# Supported compression bintools
Stefan Herbrechtsmeiercd15b642022-08-19 16:25:38 +0200116COMP_BINTOOLS = ['bzip2', 'gzip', 'lz4', 'lzma_alone', 'lzop', 'xz', 'zstd']
Simon Glass4f443042016-11-25 20:15:52 -0700117
Simon Glass2f80c5e2023-01-07 14:07:14 -0700118TEE_ADDR = 0x5678
119
Simon Glass4f443042016-11-25 20:15:52 -0700120class TestFunctional(unittest.TestCase):
121 """Functional tests for binman
122
123 Most of these use a sample .dts file to build an image and then check
124 that it looks correct. The sample files are in the test/ subdirectory
125 and are numbered.
126
127 For each entry type a very small test file is created using fixed
128 string contents. This makes it easy to test that things look right, and
129 debug problems.
130
131 In some cases a 'real' file must be used - these are also supplied in
132 the test/ diurectory.
133 """
134 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600135 def setUpClass(cls):
Simon Glass4d5994f2017-11-12 21:52:20 -0700136 global entry
Simon Glass16287932020-04-17 18:09:03 -0600137 from binman import entry
Simon Glass4d5994f2017-11-12 21:52:20 -0700138
Simon Glass4f443042016-11-25 20:15:52 -0700139 # Handle the case where argv[0] is 'python'
Simon Glassb986b3b2019-08-24 07:22:43 -0600140 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
141 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
Simon Glass4f443042016-11-25 20:15:52 -0700142
143 # Create a temporary directory for input files
Simon Glassb986b3b2019-08-24 07:22:43 -0600144 cls._indir = tempfile.mkdtemp(prefix='binmant.')
Simon Glass4f443042016-11-25 20:15:52 -0700145
146 # Create some test files
147 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
148 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
149 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glassb8ef5b62018-07-17 13:25:48 -0600150 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass6ad24522022-02-28 07:16:54 -0700151 TestFunctional._MakeInputFile('vpl/u-boot-vpl.bin', U_BOOT_VPL_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700152 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -0700153 TestFunctional._MakeInputFile('me.bin', ME_DATA)
154 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glassb986b3b2019-08-24 07:22:43 -0600155 cls._ResetDtbs()
Simon Glass2250ee62019-08-24 07:22:48 -0600156
Jagdish Gediya9d368f32018-09-03 21:35:08 +0530157 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glass2250ee62019-08-24 07:22:48 -0600158
Simon Glass5e239182019-08-24 07:22:49 -0600159 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
160 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
Simon Glass87722132017-11-12 21:52:26 -0700161 X86_START16_SPL_DATA)
Simon Glass5e239182019-08-24 07:22:49 -0600162 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
Simon Glass35b384c2018-09-14 04:57:10 -0600163 X86_START16_TPL_DATA)
Simon Glass2250ee62019-08-24 07:22:48 -0600164
165 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
166 X86_RESET16_DATA)
167 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
168 X86_RESET16_SPL_DATA)
169 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
170 X86_RESET16_TPL_DATA)
171
Simon Glass4f443042016-11-25 20:15:52 -0700172 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass6b187df2017-11-12 21:52:27 -0700173 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
174 U_BOOT_SPL_NODTB_DATA)
Simon Glassf0253632018-09-14 04:57:32 -0600175 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
176 U_BOOT_TPL_NODTB_DATA)
Simon Glass6ad24522022-02-28 07:16:54 -0700177 TestFunctional._MakeInputFile('vpl/u-boot-vpl-nodtb.bin',
178 U_BOOT_VPL_NODTB_DATA)
Simon Glassda229092016-11-25 20:15:56 -0700179 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
180 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Meng59ea8c22017-08-15 22:41:54 -0700181 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassca4f4ff2017-11-12 21:52:28 -0700182 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassec127af2018-07-17 13:25:39 -0600183 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glass0ef87aa2018-07-17 13:25:44 -0600184 TestFunctional._MakeInputDir('devkeys')
185 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass3ae192c2018-10-01 12:22:31 -0600186 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glassea0fff92019-08-24 07:23:07 -0600187 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
Simon Glassbc6a88f2019-10-20 21:31:35 -0600188 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
Simon Glass998d1482019-10-20 21:31:36 -0600189 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700190
Simon Glass53e22bf2019-08-24 07:22:53 -0600191 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
192 elf_test.BuildElfTestFiles(cls._elf_testdir)
193
Simon Glasse0ff8552016-11-25 20:15:53 -0700194 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glassf514d8f2019-08-24 07:22:54 -0600195 TestFunctional._MakeInputFile('u-boot',
Simon Glassc1aa66e2022-01-29 14:14:04 -0700196 tools.read_file(cls.ElfTestFile('u_boot_ucode_ptr')))
Simon Glasse0ff8552016-11-25 20:15:53 -0700197
198 # Intel flash descriptor file
Simon Glass0ba4b3d2020-07-09 18:39:41 -0600199 cls._SetupDescriptor()
Simon Glasse0ff8552016-11-25 20:15:53 -0700200
Simon Glassb986b3b2019-08-24 07:22:43 -0600201 shutil.copytree(cls.TestFile('files'),
202 os.path.join(cls._indir, 'files'))
Simon Glass0a98b282018-09-14 04:57:28 -0600203
Neha Malcom Francis6c66ccf2023-07-22 00:14:24 +0530204 shutil.copytree(cls.TestFile('yaml'),
205 os.path.join(cls._indir, 'yaml'))
206
Simon Glass83d73c22018-09-14 04:57:26 -0600207 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
Simon Glass8f5ef892020-10-26 17:40:25 -0600208 TestFunctional._MakeInputFile('compress_big', COMPRESS_DATA_BIG)
Simon Glassdc2f81a2020-09-01 05:13:58 -0600209 TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
Roger Quadros47f420a2022-02-19 20:50:04 +0200210 TestFunctional._MakeInputFile('tee-pager.bin', TEE_OS_DATA)
Simon Glass75989722021-11-23 21:08:59 -0700211 TestFunctional._MakeInputFile('bl2u.bin', ATF_BL2U_DATA)
Bin Meng4c4d6072021-05-10 20:23:33 +0800212 TestFunctional._MakeInputFile('fw_dynamic.bin', OPENSBI_DATA)
Samuel Holland18bd4552020-10-21 21:12:15 -0500213 TestFunctional._MakeInputFile('scp.bin', SCP_DATA)
Jonas Karlman05b978b2023-02-25 19:01:33 +0000214 TestFunctional._MakeInputFile('rockchip-tpl.bin', ROCKCHIP_TPL_DATA)
Neha Malcom Francis78144822023-07-22 00:14:25 +0530215 TestFunctional._MakeInputFile('ti_unsecure.bin', TI_UNSECURE_DATA)
Simon Glass83d73c22018-09-14 04:57:26 -0600216
Simon Glass6cf99532020-09-01 05:13:59 -0600217 # Add a few .dtb files for testing
218 TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR,
219 TEST_FDT1_DATA)
220 TestFunctional._MakeInputFile('%s/test-fdt2.dtb' % TEST_FDT_SUBDIR,
221 TEST_FDT2_DATA)
222
Simon Glassfb91d562020-09-06 10:35:33 -0600223 TestFunctional._MakeInputFile('env.txt', ENV_DATA)
224
Simon Glass40c8bdd2022-03-05 20:19:12 -0700225 # ELF file with two sections in different parts of memory, used for both
226 # ATF and OP_TEE
227 TestFunctional._MakeInputFile('bl31.elf',
228 tools.read_file(cls.ElfTestFile('elf_sections')))
229 TestFunctional._MakeInputFile('tee.elf',
230 tools.read_file(cls.ElfTestFile('elf_sections')))
231
Simon Glass2f80c5e2023-01-07 14:07:14 -0700232 # Newer OP_TEE file in v1 binary format
233 cls.make_tee_bin('tee.bin')
234
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +0200235 cls.comp_bintools = {}
236 for name in COMP_BINTOOLS:
237 cls.comp_bintools[name] = bintool.Bintool.create(name)
Simon Glassac62fba2019-07-08 13:18:53 -0600238
Simon Glass4f443042016-11-25 20:15:52 -0700239 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600240 def tearDownClass(cls):
Simon Glass4f443042016-11-25 20:15:52 -0700241 """Remove the temporary input directory and its contents"""
Simon Glassb986b3b2019-08-24 07:22:43 -0600242 if cls.preserve_indir:
243 print('Preserving input dir: %s' % cls._indir)
Simon Glassd5164a72019-07-08 13:18:49 -0600244 else:
Simon Glassb986b3b2019-08-24 07:22:43 -0600245 if cls._indir:
246 shutil.rmtree(cls._indir)
247 cls._indir = None
Simon Glass4f443042016-11-25 20:15:52 -0700248
Simon Glassd5164a72019-07-08 13:18:49 -0600249 @classmethod
Simon Glass8acce602019-07-08 13:18:50 -0600250 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
Simon Glass53cd5d92019-07-08 14:25:29 -0600251 toolpath=None, verbosity=None):
Simon Glassd5164a72019-07-08 13:18:49 -0600252 """Accept arguments controlling test execution
253
254 Args:
255 preserve_indir: Preserve the shared input directory used by all
256 tests in this class.
257 preserve_outdir: Preserve the output directories used by tests. Each
258 test has its own, so this is normally only useful when running a
259 single test.
Simon Glass8acce602019-07-08 13:18:50 -0600260 toolpath: ist of paths to use for tools
Simon Glassd5164a72019-07-08 13:18:49 -0600261 """
262 cls.preserve_indir = preserve_indir
263 cls.preserve_outdirs = preserve_outdirs
Simon Glass8acce602019-07-08 13:18:50 -0600264 cls.toolpath = toolpath
Simon Glass53cd5d92019-07-08 14:25:29 -0600265 cls.verbosity = verbosity
Simon Glassd5164a72019-07-08 13:18:49 -0600266
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +0200267 def _CheckBintool(self, bintool):
268 if not bintool.is_present():
269 self.skipTest('%s not available' % bintool.name)
270
Simon Glassac62fba2019-07-08 13:18:53 -0600271 def _CheckLz4(self):
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +0200272 bintool = self.comp_bintools['lz4']
273 self._CheckBintool(bintool)
Simon Glassac62fba2019-07-08 13:18:53 -0600274
Simon Glassbf574f12019-07-20 12:24:09 -0600275 def _CleanupOutputDir(self):
276 """Remove the temporary output directory"""
277 if self.preserve_outdirs:
278 print('Preserving output dir: %s' % tools.outdir)
279 else:
Simon Glassc1aa66e2022-01-29 14:14:04 -0700280 tools._finalise_for_test()
Simon Glassbf574f12019-07-20 12:24:09 -0600281
Simon Glass4f443042016-11-25 20:15:52 -0700282 def setUp(self):
283 # Enable this to turn on debugging output
Simon Glassf3385a52022-01-29 14:14:15 -0700284 # tout.init(tout.DEBUG)
Simon Glass4f443042016-11-25 20:15:52 -0700285 command.test_result = None
286
287 def tearDown(self):
288 """Remove the temporary output directory"""
Simon Glassbf574f12019-07-20 12:24:09 -0600289 self._CleanupOutputDir()
Simon Glass4f443042016-11-25 20:15:52 -0700290
Simon Glassf86a7362019-07-20 12:24:10 -0600291 def _SetupImageInTmpdir(self):
292 """Set up the output image in a new temporary directory
293
294 This is used when an image has been generated in the output directory,
295 but we want to run binman again. This will create a new output
296 directory and fail to delete the original one.
297
298 This creates a new temporary directory, copies the image to it (with a
299 new name) and removes the old output directory.
300
301 Returns:
302 Tuple:
303 Temporary directory to use
304 New image filename
305 """
Simon Glassc1aa66e2022-01-29 14:14:04 -0700306 image_fname = tools.get_output_filename('image.bin')
Simon Glassf86a7362019-07-20 12:24:10 -0600307 tmpdir = tempfile.mkdtemp(prefix='binman.')
308 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
Simon Glassc1aa66e2022-01-29 14:14:04 -0700309 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassf86a7362019-07-20 12:24:10 -0600310 self._CleanupOutputDir()
311 return tmpdir, updated_fname
312
Simon Glassb8ef5b62018-07-17 13:25:48 -0600313 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600314 def _ResetDtbs(cls):
Simon Glassb8ef5b62018-07-17 13:25:48 -0600315 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
316 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
317 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
Simon Glass6ad24522022-02-28 07:16:54 -0700318 TestFunctional._MakeInputFile('vpl/u-boot-vpl.dtb', U_BOOT_VPL_DTB_DATA)
Simon Glassb8ef5b62018-07-17 13:25:48 -0600319
Simon Glass4f443042016-11-25 20:15:52 -0700320 def _RunBinman(self, *args, **kwargs):
321 """Run binman using the command line
322
323 Args:
324 Arguments to pass, as a list of strings
325 kwargs: Arguments to pass to Command.RunPipe()
326 """
Simon Glassd9800692022-01-29 14:14:05 -0700327 result = command.run_pipe([[self._binman_pathname] + list(args)],
Simon Glass4f443042016-11-25 20:15:52 -0700328 capture=True, capture_stderr=True, raise_on_error=False)
329 if result.return_code and kwargs.get('raise_on_error', True):
330 raise Exception("Error running '%s': %s" % (' '.join(args),
331 result.stdout + result.stderr))
332 return result
333
Simon Glass53cd5d92019-07-08 14:25:29 -0600334 def _DoBinman(self, *argv):
Simon Glass4f443042016-11-25 20:15:52 -0700335 """Run binman using directly (in the same process)
336
337 Args:
338 Arguments to pass, as a list of strings
339 Returns:
340 Return value (0 for success)
341 """
Simon Glass53cd5d92019-07-08 14:25:29 -0600342 argv = list(argv)
343 args = cmdline.ParseArgs(argv)
344 args.pager = 'binman-invalid-pager'
345 args.build_dir = self._indir
Simon Glass4f443042016-11-25 20:15:52 -0700346
347 # For testing, you can force an increase in verbosity here
Simon Glass53cd5d92019-07-08 14:25:29 -0600348 # args.verbosity = tout.DEBUG
349 return control.Binman(args)
Simon Glass4f443042016-11-25 20:15:52 -0700350
Simon Glass53af22a2018-07-17 13:25:32 -0600351 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glasseb833d82019-04-25 21:58:34 -0600352 entry_args=None, images=None, use_real_dtb=False,
Simon Glass63aeaeb2021-03-18 20:25:05 +1300353 use_expanded=False, verbosity=None, allow_missing=False,
Heiko Thierya89c8f22022-01-06 11:49:41 +0100354 allow_fake_blobs=False, extra_indirs=None, threads=None,
Simon Glass4f9ee832022-01-09 20:14:09 -0700355 test_section_timeout=False, update_fdt_in_elf=None,
Andrew Davis15432ea2023-07-22 00:14:44 +0530356 force_missing_bintools='', ignore_missing=False, output_dir=None):
Simon Glass4f443042016-11-25 20:15:52 -0700357 """Run binman with a given test file
358
359 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600360 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600361 debug: True to enable debugging output
Simon Glass3b0c3822018-06-01 09:38:20 -0600362 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600363 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600364 tree before packing it into the image
Simon Glass0bfa7b02018-09-14 04:57:12 -0600365 entry_args: Dict of entry args to supply to binman
366 key: arg name
367 value: value of that arg
368 images: List of image names to build
Simon Glasse9d336d2020-09-01 05:13:55 -0600369 use_real_dtb: True to use the test file as the contents of
370 the u-boot-dtb entry. Normally this is not needed and the
371 test contents (the U_BOOT_DTB_DATA string) can be used.
372 But in some test we need the real contents.
Simon Glass63aeaeb2021-03-18 20:25:05 +1300373 use_expanded: True to use expanded entries where available, e.g.
374 'u-boot-expanded' instead of 'u-boot'
Simon Glasse9d336d2020-09-01 05:13:55 -0600375 verbosity: Verbosity level to use (0-3, None=don't set it)
376 allow_missing: Set the '--allow-missing' flag so that missing
377 external binaries just produce a warning instead of an error
Heiko Thierya89c8f22022-01-06 11:49:41 +0100378 allow_fake_blobs: Set the '--fake-ext-blobs' flag
Simon Glass6cf99532020-09-01 05:13:59 -0600379 extra_indirs: Extra input directories to add using -I
Simon Glassc69d19c2021-07-06 10:36:37 -0600380 threads: Number of threads to use (None for default, 0 for
381 single-threaded)
Simon Glass7115f002021-11-03 21:09:17 -0600382 test_section_timeout: True to force the first time to timeout, as
383 used in testThreadTimeout()
Simon Glass0427bed2021-11-03 21:09:18 -0600384 update_fdt_in_elf: Value to pass with --update-fdt-in-elf=xxx
Simon Glass4f9ee832022-01-09 20:14:09 -0700385 force_missing_tools (str): comma-separated list of bintools to
386 regard as missing
Andrew Davis15432ea2023-07-22 00:14:44 +0530387 output_dir: Specific output directory to use for image using -O
Simon Glass7115f002021-11-03 21:09:17 -0600388
389 Returns:
390 int return code, 0 on success
Simon Glass4f443042016-11-25 20:15:52 -0700391 """
Simon Glass53cd5d92019-07-08 14:25:29 -0600392 args = []
Simon Glass7fe91732017-11-13 18:55:00 -0700393 if debug:
394 args.append('-D')
Simon Glass53cd5d92019-07-08 14:25:29 -0600395 if verbosity is not None:
396 args.append('-v%d' % verbosity)
397 elif self.verbosity:
398 args.append('-v%d' % self.verbosity)
399 if self.toolpath:
400 for path in self.toolpath:
401 args += ['--toolpath', path]
Simon Glassc69d19c2021-07-06 10:36:37 -0600402 if threads is not None:
403 args.append('-T%d' % threads)
404 if test_section_timeout:
405 args.append('--test-section-timeout')
Simon Glass53cd5d92019-07-08 14:25:29 -0600406 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass3b0c3822018-06-01 09:38:20 -0600407 if map:
408 args.append('-m')
Simon Glass16b8d6b2018-07-06 10:27:42 -0600409 if update_dtb:
Simon Glass2569e102019-07-08 13:18:47 -0600410 args.append('-u')
Simon Glass93d17412018-09-14 04:57:23 -0600411 if not use_real_dtb:
412 args.append('--fake-dtb')
Simon Glass63aeaeb2021-03-18 20:25:05 +1300413 if not use_expanded:
414 args.append('--no-expanded')
Simon Glass53af22a2018-07-17 13:25:32 -0600415 if entry_args:
Simon Glass50979152019-05-14 15:53:41 -0600416 for arg, value in entry_args.items():
Simon Glass53af22a2018-07-17 13:25:32 -0600417 args.append('-a%s=%s' % (arg, value))
Simon Glass4f9f1052020-07-09 18:39:38 -0600418 if allow_missing:
419 args.append('-M')
Simon Glassb38da152022-11-09 19:14:42 -0700420 if ignore_missing:
421 args.append('-W')
Heiko Thierya89c8f22022-01-06 11:49:41 +0100422 if allow_fake_blobs:
423 args.append('--fake-ext-blobs')
Simon Glass4f9ee832022-01-09 20:14:09 -0700424 if force_missing_bintools:
425 args += ['--force-missing-bintools', force_missing_bintools]
Simon Glass0427bed2021-11-03 21:09:18 -0600426 if update_fdt_in_elf:
427 args += ['--update-fdt-in-elf', update_fdt_in_elf]
Simon Glass0bfa7b02018-09-14 04:57:12 -0600428 if images:
429 for image in images:
430 args += ['-i', image]
Simon Glass6cf99532020-09-01 05:13:59 -0600431 if extra_indirs:
432 for indir in extra_indirs:
433 args += ['-I', indir]
Andrew Davis15432ea2023-07-22 00:14:44 +0530434 if output_dir:
435 args += ['-O', output_dir]
Simon Glass7fe91732017-11-13 18:55:00 -0700436 return self._DoBinman(*args)
Simon Glass4f443042016-11-25 20:15:52 -0700437
438 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glasse0ff8552016-11-25 20:15:53 -0700439 """Set up a new test device-tree file
440
441 The given file is compiled and set up as the device tree to be used
442 for ths test.
443
444 Args:
445 fname: Filename of .dts file to read
Simon Glass7ae5f312018-06-01 09:38:19 -0600446 outfile: Output filename for compiled device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700447
448 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600449 Contents of device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700450 """
Simon Glassa004f292019-07-20 12:23:49 -0600451 tmpdir = tempfile.mkdtemp(prefix='binmant.')
452 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
Simon Glass1d0ebf72019-05-14 15:53:42 -0600453 with open(dtb, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700454 data = fd.read()
455 TestFunctional._MakeInputFile(outfile, data)
Simon Glassa004f292019-07-20 12:23:49 -0600456 shutil.rmtree(tmpdir)
Simon Glasse0e62752018-10-01 21:12:41 -0600457 return data
Simon Glass4f443042016-11-25 20:15:52 -0700458
Simon Glass6ad24522022-02-28 07:16:54 -0700459 def _GetDtbContentsForSpls(self, dtb_data, name):
460 """Create a version of the main DTB for SPL / TPL / VPL
Simon Glass6ed45ba2018-09-14 04:57:24 -0600461
462 For testing we don't actually have different versions of the DTB. With
463 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
464 we don't normally have any unwanted nodes.
465
466 We still want the DTBs for SPL and TPL to be different though, since
467 otherwise it is confusing to know which one we are looking at. So add
468 an 'spl' or 'tpl' property to the top-level node.
Simon Glasse9d336d2020-09-01 05:13:55 -0600469
470 Args:
471 dtb_data: dtb data to modify (this should be a value devicetree)
472 name: Name of a new property to add
473
474 Returns:
475 New dtb data with the property added
Simon Glass6ed45ba2018-09-14 04:57:24 -0600476 """
477 dtb = fdt.Fdt.FromData(dtb_data)
478 dtb.Scan()
479 dtb.GetNode('/binman').AddZeroProp(name)
480 dtb.Sync(auto_resize=True)
481 dtb.Pack()
482 return dtb.GetContents()
483
Simon Glass63aeaeb2021-03-18 20:25:05 +1300484 def _DoReadFileDtb(self, fname, use_real_dtb=False, use_expanded=False,
485 map=False, update_dtb=False, entry_args=None,
Simon Glassc69d19c2021-07-06 10:36:37 -0600486 reset_dtbs=True, extra_indirs=None, threads=None):
Simon Glass4f443042016-11-25 20:15:52 -0700487 """Run binman and return the resulting image
488
489 This runs binman with a given test file and then reads the resulting
490 output file. It is a shortcut function since most tests need to do
491 these steps.
492
493 Raises an assertion failure if binman returns a non-zero exit code.
494
495 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600496 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass4f443042016-11-25 20:15:52 -0700497 use_real_dtb: True to use the test file as the contents of
498 the u-boot-dtb entry. Normally this is not needed and the
499 test contents (the U_BOOT_DTB_DATA string) can be used.
500 But in some test we need the real contents.
Simon Glass63aeaeb2021-03-18 20:25:05 +1300501 use_expanded: True to use expanded entries where available, e.g.
502 'u-boot-expanded' instead of 'u-boot'
Simon Glass3b0c3822018-06-01 09:38:20 -0600503 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600504 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600505 tree before packing it into the image
Simon Glasse9d336d2020-09-01 05:13:55 -0600506 entry_args: Dict of entry args to supply to binman
507 key: arg name
508 value: value of that arg
509 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
510 function. If reset_dtbs is True, then the original test dtb
511 is written back before this function finishes
Simon Glass6cf99532020-09-01 05:13:59 -0600512 extra_indirs: Extra input directories to add using -I
Simon Glassc69d19c2021-07-06 10:36:37 -0600513 threads: Number of threads to use (None for default, 0 for
514 single-threaded)
Simon Glasse0ff8552016-11-25 20:15:53 -0700515
516 Returns:
517 Tuple:
518 Resulting image contents
519 Device tree contents
Simon Glass3b0c3822018-06-01 09:38:20 -0600520 Map data showing contents of image (or None if none)
Simon Glassea6922e2018-07-17 13:25:27 -0600521 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass4f443042016-11-25 20:15:52 -0700522 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700523 dtb_data = None
Simon Glass4f443042016-11-25 20:15:52 -0700524 # Use the compiled test file as the u-boot-dtb input
525 if use_real_dtb:
Simon Glasse0ff8552016-11-25 20:15:53 -0700526 dtb_data = self._SetupDtb(fname)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600527
528 # For testing purposes, make a copy of the DT for SPL and TPL. Add
529 # a node indicating which it is, so aid verification.
Simon Glass6ad24522022-02-28 07:16:54 -0700530 for name in ['spl', 'tpl', 'vpl']:
Simon Glass6ed45ba2018-09-14 04:57:24 -0600531 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
532 outfile = os.path.join(self._indir, dtb_fname)
533 TestFunctional._MakeInputFile(dtb_fname,
Simon Glass6ad24522022-02-28 07:16:54 -0700534 self._GetDtbContentsForSpls(dtb_data, name))
Simon Glass4f443042016-11-25 20:15:52 -0700535
536 try:
Simon Glass53af22a2018-07-17 13:25:32 -0600537 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glass6cf99532020-09-01 05:13:59 -0600538 entry_args=entry_args, use_real_dtb=use_real_dtb,
Simon Glassc69d19c2021-07-06 10:36:37 -0600539 use_expanded=use_expanded, extra_indirs=extra_indirs,
540 threads=threads)
Simon Glass4f443042016-11-25 20:15:52 -0700541 self.assertEqual(0, retcode)
Simon Glassc1aa66e2022-01-29 14:14:04 -0700542 out_dtb_fname = tools.get_output_filename('u-boot.dtb.out')
Simon Glass4f443042016-11-25 20:15:52 -0700543
544 # Find the (only) image, read it and return its contents
545 image = control.images['image']
Simon Glassc1aa66e2022-01-29 14:14:04 -0700546 image_fname = tools.get_output_filename('image.bin')
Simon Glass16b8d6b2018-07-06 10:27:42 -0600547 self.assertTrue(os.path.exists(image_fname))
Simon Glass3b0c3822018-06-01 09:38:20 -0600548 if map:
Simon Glassc1aa66e2022-01-29 14:14:04 -0700549 map_fname = tools.get_output_filename('image.map')
Simon Glass3b0c3822018-06-01 09:38:20 -0600550 with open(map_fname) as fd:
551 map_data = fd.read()
552 else:
553 map_data = None
Simon Glass1d0ebf72019-05-14 15:53:42 -0600554 with open(image_fname, 'rb') as fd:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600555 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass4f443042016-11-25 20:15:52 -0700556 finally:
557 # Put the test file back
Simon Glass6ed45ba2018-09-14 04:57:24 -0600558 if reset_dtbs and use_real_dtb:
Simon Glassb8ef5b62018-07-17 13:25:48 -0600559 self._ResetDtbs()
Simon Glass4f443042016-11-25 20:15:52 -0700560
Simon Glass3c081312019-07-08 14:25:26 -0600561 def _DoReadFileRealDtb(self, fname):
562 """Run binman with a real .dtb file and return the resulting data
563
564 Args:
565 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
566
567 Returns:
568 Resulting image contents
569 """
570 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
571
Simon Glasse0ff8552016-11-25 20:15:53 -0700572 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass7ae5f312018-06-01 09:38:19 -0600573 """Helper function which discards the device-tree binary
574
575 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600576 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600577 use_real_dtb: True to use the test file as the contents of
578 the u-boot-dtb entry. Normally this is not needed and the
579 test contents (the U_BOOT_DTB_DATA string) can be used.
580 But in some test we need the real contents.
Simon Glassea6922e2018-07-17 13:25:27 -0600581
582 Returns:
583 Resulting image contents
Simon Glass7ae5f312018-06-01 09:38:19 -0600584 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700585 return self._DoReadFileDtb(fname, use_real_dtb)[0]
586
Simon Glass4f443042016-11-25 20:15:52 -0700587 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600588 def _MakeInputFile(cls, fname, contents):
Simon Glass4f443042016-11-25 20:15:52 -0700589 """Create a new test input file, creating directories as needed
590
591 Args:
Simon Glass3ab95982018-08-01 15:22:37 -0600592 fname: Filename to create
Simon Glass4f443042016-11-25 20:15:52 -0700593 contents: File contents to write in to the file
594 Returns:
595 Full pathname of file created
596 """
Simon Glassb986b3b2019-08-24 07:22:43 -0600597 pathname = os.path.join(cls._indir, fname)
Simon Glass4f443042016-11-25 20:15:52 -0700598 dirname = os.path.dirname(pathname)
599 if dirname and not os.path.exists(dirname):
600 os.makedirs(dirname)
601 with open(pathname, 'wb') as fd:
602 fd.write(contents)
603 return pathname
604
605 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600606 def _MakeInputDir(cls, dirname):
Simon Glass0ef87aa2018-07-17 13:25:44 -0600607 """Create a new test input directory, creating directories as needed
608
609 Args:
610 dirname: Directory name to create
611
612 Returns:
613 Full pathname of directory created
614 """
Simon Glassb986b3b2019-08-24 07:22:43 -0600615 pathname = os.path.join(cls._indir, dirname)
Simon Glass0ef87aa2018-07-17 13:25:44 -0600616 if not os.path.exists(pathname):
617 os.makedirs(pathname)
618 return pathname
619
620 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600621 def _SetupSplElf(cls, src_fname='bss_data'):
Simon Glass11ae93e2018-10-01 21:12:47 -0600622 """Set up an ELF file with a '_dt_ucode_base_size' symbol
623
624 Args:
625 Filename of ELF file to use as SPL
626 """
Simon Glassc9a0b272019-08-24 07:22:59 -0600627 TestFunctional._MakeInputFile('spl/u-boot-spl',
Simon Glassc1aa66e2022-01-29 14:14:04 -0700628 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass11ae93e2018-10-01 21:12:47 -0600629
630 @classmethod
Simon Glass2090f1e2019-08-24 07:23:00 -0600631 def _SetupTplElf(cls, src_fname='bss_data'):
632 """Set up an ELF file with a '_dt_ucode_base_size' symbol
633
634 Args:
635 Filename of ELF file to use as TPL
636 """
637 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
Simon Glassc1aa66e2022-01-29 14:14:04 -0700638 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass2090f1e2019-08-24 07:23:00 -0600639
640 @classmethod
Simon Glass6ad24522022-02-28 07:16:54 -0700641 def _SetupVplElf(cls, src_fname='bss_data'):
642 """Set up an ELF file with a '_dt_ucode_base_size' symbol
643
644 Args:
645 Filename of ELF file to use as VPL
646 """
647 TestFunctional._MakeInputFile('vpl/u-boot-vpl',
648 tools.read_file(cls.ElfTestFile(src_fname)))
649
650 @classmethod
Simon Glass0ba4b3d2020-07-09 18:39:41 -0600651 def _SetupDescriptor(cls):
652 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
653 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
654
655 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600656 def TestFile(cls, fname):
657 return os.path.join(cls._binman_dir, 'test', fname)
Simon Glass4f443042016-11-25 20:15:52 -0700658
Simon Glass53e22bf2019-08-24 07:22:53 -0600659 @classmethod
660 def ElfTestFile(cls, fname):
661 return os.path.join(cls._elf_testdir, fname)
662
Simon Glass2f80c5e2023-01-07 14:07:14 -0700663 @classmethod
664 def make_tee_bin(cls, fname, paged_sz=0, extra_data=b''):
665 init_sz, start_hi, start_lo, dummy = (len(U_BOOT_DATA), 0, TEE_ADDR, 0)
666 data = b'OPTE\x01xxx' + struct.pack('<5I', init_sz, start_hi, start_lo,
667 dummy, paged_sz) + U_BOOT_DATA
668 data += extra_data
669 TestFunctional._MakeInputFile(fname, data)
670
Simon Glass4f443042016-11-25 20:15:52 -0700671 def AssertInList(self, grep_list, target):
672 """Assert that at least one of a list of things is in a target
673
674 Args:
675 grep_list: List of strings to check
676 target: Target string
677 """
678 for grep in grep_list:
679 if grep in target:
680 return
Simon Glass1fc62de2019-05-17 22:00:50 -0600681 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass4f443042016-11-25 20:15:52 -0700682
683 def CheckNoGaps(self, entries):
684 """Check that all entries fit together without gaps
685
686 Args:
687 entries: List of entries to check
688 """
Simon Glass3ab95982018-08-01 15:22:37 -0600689 offset = 0
Simon Glass4f443042016-11-25 20:15:52 -0700690 for entry in entries.values():
Simon Glass3ab95982018-08-01 15:22:37 -0600691 self.assertEqual(offset, entry.offset)
692 offset += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700693
Simon Glasse0ff8552016-11-25 20:15:53 -0700694 def GetFdtLen(self, dtb):
Simon Glass7ae5f312018-06-01 09:38:19 -0600695 """Get the totalsize field from a device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700696
697 Args:
Simon Glass7ae5f312018-06-01 09:38:19 -0600698 dtb: Device-tree binary contents
Simon Glasse0ff8552016-11-25 20:15:53 -0700699
700 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600701 Total size of device-tree binary, from the header
Simon Glasse0ff8552016-11-25 20:15:53 -0700702 """
703 return struct.unpack('>L', dtb[4:8])[0]
704
Simon Glass086cec92019-07-08 14:25:27 -0600705 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glass16b8d6b2018-07-06 10:27:42 -0600706 def AddNode(node, path):
707 if node.name != '/':
708 path += '/' + node.name
Simon Glass086cec92019-07-08 14:25:27 -0600709 for prop in node.props.values():
710 if prop.name in prop_names:
711 prop_path = path + ':' + prop.name
712 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
713 prop.value)
Simon Glass16b8d6b2018-07-06 10:27:42 -0600714 for subnode in node.subnodes:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600715 AddNode(subnode, path)
716
717 tree = {}
Simon Glass16b8d6b2018-07-06 10:27:42 -0600718 AddNode(dtb.GetRoot(), '')
719 return tree
720
Ivan Mikhaylov5b34efe2023-03-08 01:13:40 +0000721 def _CheckSign(self, fit, key):
722 try:
723 tools.run('fit_check_sign', '-k', key, '-f', fit)
724 except:
725 self.fail('Expected signed FIT container')
726 return False
727 return True
728
Simon Glass4f443042016-11-25 20:15:52 -0700729 def testRun(self):
730 """Test a basic run with valid args"""
731 result = self._RunBinman('-h')
732
733 def testFullHelp(self):
734 """Test that the full help is displayed with -H"""
735 result = self._RunBinman('-H')
Simon Glass61adb2d2021-03-18 20:25:13 +1300736 help_file = os.path.join(self._binman_dir, 'README.rst')
Tom Rini3759df02018-01-16 15:29:50 -0500737 # Remove possible extraneous strings
738 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
739 gothelp = result.stdout.replace(extra, '')
740 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass4f443042016-11-25 20:15:52 -0700741 self.assertEqual(0, len(result.stderr))
742 self.assertEqual(0, result.return_code)
743
744 def testFullHelpInternal(self):
745 """Test that the full help is displayed with -H"""
746 try:
747 command.test_result = command.CommandResult()
748 result = self._DoBinman('-H')
Simon Glass61adb2d2021-03-18 20:25:13 +1300749 help_file = os.path.join(self._binman_dir, 'README.rst')
Simon Glass4f443042016-11-25 20:15:52 -0700750 finally:
751 command.test_result = None
752
753 def testHelp(self):
754 """Test that the basic help is displayed with -h"""
755 result = self._RunBinman('-h')
756 self.assertTrue(len(result.stdout) > 200)
757 self.assertEqual(0, len(result.stderr))
758 self.assertEqual(0, result.return_code)
759
Simon Glass4f443042016-11-25 20:15:52 -0700760 def testBoard(self):
761 """Test that we can run it with a specific board"""
Simon Glass741f2d62018-10-01 12:22:30 -0600762 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass4f443042016-11-25 20:15:52 -0700763 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glass63aeaeb2021-03-18 20:25:05 +1300764 result = self._DoBinman('build', '-n', '-b', 'sandbox')
Simon Glass4f443042016-11-25 20:15:52 -0700765 self.assertEqual(0, result)
766
767 def testNeedBoard(self):
768 """Test that we get an error when no board ius supplied"""
769 with self.assertRaises(ValueError) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600770 result = self._DoBinman('build')
Simon Glass4f443042016-11-25 20:15:52 -0700771 self.assertIn("Must provide a board to process (use -b <board>)",
772 str(e.exception))
773
774 def testMissingDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600775 """Test that an invalid device-tree file generates an error"""
Simon Glass4f443042016-11-25 20:15:52 -0700776 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600777 self._RunBinman('build', '-d', 'missing_file')
Simon Glass4f443042016-11-25 20:15:52 -0700778 # We get one error from libfdt, and a different one from fdtget.
779 self.AssertInList(["Couldn't open blob from 'missing_file'",
780 'No such file or directory'], str(e.exception))
781
782 def testBrokenDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600783 """Test that an invalid device-tree source file generates an error
Simon Glass4f443042016-11-25 20:15:52 -0700784
785 Since this is a source file it should be compiled and the error
786 will come from the device-tree compiler (dtc).
787 """
788 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600789 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700790 self.assertIn("FATAL ERROR: Unable to parse input tree",
791 str(e.exception))
792
793 def testMissingNode(self):
794 """Test that a device tree without a 'binman' node generates an error"""
795 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600796 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700797 self.assertIn("does not have a 'binman' node", str(e.exception))
798
799 def testEmpty(self):
800 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glass53cd5d92019-07-08 14:25:29 -0600801 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700802 self.assertEqual(0, len(result.stderr))
803 self.assertEqual(0, result.return_code)
804
805 def testInvalidEntry(self):
806 """Test that an invalid entry is flagged"""
807 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600808 result = self._RunBinman('build', '-d',
Simon Glass741f2d62018-10-01 12:22:30 -0600809 self.TestFile('004_invalid_entry.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700810 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
811 "'/binman/not-a-valid-type'", str(e.exception))
812
813 def testSimple(self):
814 """Test a simple binman with a single file"""
Simon Glass741f2d62018-10-01 12:22:30 -0600815 data = self._DoReadFile('005_simple.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700816 self.assertEqual(U_BOOT_DATA, data)
817
Simon Glass7fe91732017-11-13 18:55:00 -0700818 def testSimpleDebug(self):
819 """Test a simple binman run with debugging enabled"""
Simon Glasse2705fa2019-07-08 14:25:53 -0600820 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass7fe91732017-11-13 18:55:00 -0700821
Simon Glass4f443042016-11-25 20:15:52 -0700822 def testDual(self):
823 """Test that we can handle creating two images
824
825 This also tests image padding.
826 """
Simon Glass741f2d62018-10-01 12:22:30 -0600827 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700828 self.assertEqual(0, retcode)
829
830 image = control.images['image1']
Simon Glass8beb11e2019-07-08 14:25:47 -0600831 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glassc1aa66e2022-01-29 14:14:04 -0700832 fname = tools.get_output_filename('image1.bin')
Simon Glass4f443042016-11-25 20:15:52 -0700833 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600834 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700835 data = fd.read()
836 self.assertEqual(U_BOOT_DATA, data)
837
838 image = control.images['image2']
Simon Glass8beb11e2019-07-08 14:25:47 -0600839 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glassc1aa66e2022-01-29 14:14:04 -0700840 fname = tools.get_output_filename('image2.bin')
Simon Glass4f443042016-11-25 20:15:52 -0700841 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600842 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700843 data = fd.read()
844 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glassc1aa66e2022-01-29 14:14:04 -0700845 self.assertEqual(tools.get_bytes(0, 3), data[:3])
846 self.assertEqual(tools.get_bytes(0, 5), data[7:])
Simon Glass4f443042016-11-25 20:15:52 -0700847
848 def testBadAlign(self):
849 """Test that an invalid alignment value is detected"""
850 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600851 self._DoTestFile('007_bad_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700852 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
853 "of two", str(e.exception))
854
855 def testPackSimple(self):
856 """Test that packing works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600857 retcode = self._DoTestFile('008_pack.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700858 self.assertEqual(0, retcode)
859 self.assertIn('image', control.images)
860 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600861 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700862 self.assertEqual(5, len(entries))
863
864 # First u-boot
865 self.assertIn('u-boot', entries)
866 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600867 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700868 self.assertEqual(len(U_BOOT_DATA), entry.size)
869
870 # Second u-boot, aligned to 16-byte boundary
871 self.assertIn('u-boot-align', entries)
872 entry = entries['u-boot-align']
Simon Glass3ab95982018-08-01 15:22:37 -0600873 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700874 self.assertEqual(len(U_BOOT_DATA), entry.size)
875
876 # Third u-boot, size 23 bytes
877 self.assertIn('u-boot-size', entries)
878 entry = entries['u-boot-size']
Simon Glass3ab95982018-08-01 15:22:37 -0600879 self.assertEqual(20, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700880 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
881 self.assertEqual(23, entry.size)
882
883 # Fourth u-boot, placed immediate after the above
884 self.assertIn('u-boot-next', entries)
885 entry = entries['u-boot-next']
Simon Glass3ab95982018-08-01 15:22:37 -0600886 self.assertEqual(43, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700887 self.assertEqual(len(U_BOOT_DATA), entry.size)
888
Simon Glass3ab95982018-08-01 15:22:37 -0600889 # Fifth u-boot, placed at a fixed offset
Simon Glass4f443042016-11-25 20:15:52 -0700890 self.assertIn('u-boot-fixed', entries)
891 entry = entries['u-boot-fixed']
Simon Glass3ab95982018-08-01 15:22:37 -0600892 self.assertEqual(61, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700893 self.assertEqual(len(U_BOOT_DATA), entry.size)
894
Simon Glass8beb11e2019-07-08 14:25:47 -0600895 self.assertEqual(65, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700896
897 def testPackExtra(self):
898 """Test that extra packing feature works as expected"""
Simon Glass4eec34c2020-10-26 17:40:10 -0600899 data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
900 update_dtb=True)
Simon Glass4f443042016-11-25 20:15:52 -0700901
Simon Glass4f443042016-11-25 20:15:52 -0700902 self.assertIn('image', control.images)
903 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600904 entries = image.GetEntries()
Samuel Hollandb01ae032023-01-21 17:25:16 -0600905 self.assertEqual(6, len(entries))
Simon Glass4f443042016-11-25 20:15:52 -0700906
Samuel Hollandb01ae032023-01-21 17:25:16 -0600907 # First u-boot with padding before and after (included in minimum size)
Simon Glass4f443042016-11-25 20:15:52 -0700908 self.assertIn('u-boot', entries)
909 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600910 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700911 self.assertEqual(3, entry.pad_before)
912 self.assertEqual(3 + 5 + len(U_BOOT_DATA), 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(tools.get_bytes(0, 3) + U_BOOT_DATA +
915 tools.get_bytes(0, 5), data[:entry.size])
Simon Glassef439ed2020-10-26 17:40:08 -0600916 pos = entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700917
918 # Second u-boot has an aligned size, but it has no effect
919 self.assertIn('u-boot-align-size-nop', entries)
920 entry = entries['u-boot-align-size-nop']
Simon Glassef439ed2020-10-26 17:40:08 -0600921 self.assertEqual(pos, entry.offset)
922 self.assertEqual(len(U_BOOT_DATA), entry.size)
923 self.assertEqual(U_BOOT_DATA, entry.data)
924 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
925 pos += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700926
927 # Third u-boot has an aligned size too
928 self.assertIn('u-boot-align-size', entries)
929 entry = entries['u-boot-align-size']
Simon Glassef439ed2020-10-26 17:40:08 -0600930 self.assertEqual(pos, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700931 self.assertEqual(32, entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600932 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassc1aa66e2022-01-29 14:14:04 -0700933 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
Simon Glassef439ed2020-10-26 17:40:08 -0600934 data[pos:pos + entry.size])
935 pos += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700936
937 # Fourth u-boot has an aligned end
938 self.assertIn('u-boot-align-end', entries)
939 entry = entries['u-boot-align-end']
Simon Glass3ab95982018-08-01 15:22:37 -0600940 self.assertEqual(48, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700941 self.assertEqual(16, entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600942 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glassc1aa66e2022-01-29 14:14:04 -0700943 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 16 - len(U_BOOT_DATA)),
Simon Glassef439ed2020-10-26 17:40:08 -0600944 data[pos:pos + entry.size])
945 pos += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700946
947 # Fifth u-boot immediately afterwards
948 self.assertIn('u-boot-align-both', entries)
949 entry = entries['u-boot-align-both']
Simon Glass3ab95982018-08-01 15:22:37 -0600950 self.assertEqual(64, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700951 self.assertEqual(64, entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600952 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glassc1aa66e2022-01-29 14:14:04 -0700953 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 64 - len(U_BOOT_DATA)),
Simon Glassef439ed2020-10-26 17:40:08 -0600954 data[pos:pos + entry.size])
Simon Glass4f443042016-11-25 20:15:52 -0700955
Samuel Hollandb01ae032023-01-21 17:25:16 -0600956 # Sixth u-boot with both minimum size and aligned size
957 self.assertIn('u-boot-min-size', entries)
958 entry = entries['u-boot-min-size']
959 self.assertEqual(128, entry.offset)
960 self.assertEqual(32, entry.size)
961 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
962 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
963 data[pos:pos + entry.size])
964
Simon Glass4f443042016-11-25 20:15:52 -0700965 self.CheckNoGaps(entries)
Samuel Hollandb01ae032023-01-21 17:25:16 -0600966 self.assertEqual(160, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700967
Simon Glass4eec34c2020-10-26 17:40:10 -0600968 dtb = fdt.Fdt(out_dtb_fname)
969 dtb.Scan()
970 props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
971 expected = {
972 'image-pos': 0,
973 'offset': 0,
Samuel Hollandb01ae032023-01-21 17:25:16 -0600974 'size': 160,
Simon Glass4eec34c2020-10-26 17:40:10 -0600975
976 'u-boot:image-pos': 0,
977 'u-boot:offset': 0,
978 'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
979
980 'u-boot-align-size-nop:image-pos': 12,
981 'u-boot-align-size-nop:offset': 12,
982 'u-boot-align-size-nop:size': 4,
983
984 'u-boot-align-size:image-pos': 16,
985 'u-boot-align-size:offset': 16,
986 'u-boot-align-size:size': 32,
987
988 'u-boot-align-end:image-pos': 48,
989 'u-boot-align-end:offset': 48,
990 'u-boot-align-end:size': 16,
991
992 'u-boot-align-both:image-pos': 64,
993 'u-boot-align-both:offset': 64,
994 'u-boot-align-both:size': 64,
Samuel Hollandb01ae032023-01-21 17:25:16 -0600995
996 'u-boot-min-size:image-pos': 128,
997 'u-boot-min-size:offset': 128,
998 'u-boot-min-size:size': 32,
Simon Glass4eec34c2020-10-26 17:40:10 -0600999 }
1000 self.assertEqual(expected, props)
1001
Simon Glass4f443042016-11-25 20:15:52 -07001002 def testPackAlignPowerOf2(self):
1003 """Test that invalid entry alignment is detected"""
1004 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001005 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001006 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
1007 "of two", str(e.exception))
1008
1009 def testPackAlignSizePowerOf2(self):
1010 """Test that invalid entry size alignment is detected"""
1011 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001012 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001013 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
1014 "power of two", str(e.exception))
1015
1016 def testPackInvalidAlign(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001017 """Test detection of an offset that does not match its alignment"""
Simon Glass4f443042016-11-25 20:15:52 -07001018 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001019 self._DoTestFile('012_pack_inv_align.dts')
Simon Glass3ab95982018-08-01 15:22:37 -06001020 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass4f443042016-11-25 20:15:52 -07001021 "align 0x4 (4)", str(e.exception))
1022
1023 def testPackInvalidSizeAlign(self):
1024 """Test that invalid entry size alignment is detected"""
1025 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001026 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001027 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
1028 "align-size 0x4 (4)", str(e.exception))
1029
1030 def testPackOverlap(self):
1031 """Test that overlapping regions are detected"""
1032 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001033 self._DoTestFile('014_pack_overlap.dts')
Simon Glass3ab95982018-08-01 15:22:37 -06001034 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -07001035 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1036 str(e.exception))
1037
1038 def testPackEntryOverflow(self):
1039 """Test that entries that overflow their size are detected"""
1040 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001041 self._DoTestFile('015_pack_overflow.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001042 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
1043 "but entry size is 0x3 (3)", str(e.exception))
1044
1045 def testPackImageOverflow(self):
1046 """Test that entries which overflow the image size are detected"""
1047 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001048 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glass8f1da502018-06-01 09:38:12 -06001049 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass4f443042016-11-25 20:15:52 -07001050 "size 0x3 (3)", str(e.exception))
1051
1052 def testPackImageSize(self):
1053 """Test that the image size can be set"""
Simon Glass741f2d62018-10-01 12:22:30 -06001054 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001055 self.assertEqual(0, retcode)
1056 self.assertIn('image', control.images)
1057 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -06001058 self.assertEqual(7, image.size)
Simon Glass4f443042016-11-25 20:15:52 -07001059
1060 def testPackImageSizeAlign(self):
1061 """Test that image size alignemnt works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -06001062 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001063 self.assertEqual(0, retcode)
1064 self.assertIn('image', control.images)
1065 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -06001066 self.assertEqual(16, image.size)
Simon Glass4f443042016-11-25 20:15:52 -07001067
1068 def testPackInvalidImageAlign(self):
1069 """Test that invalid image alignment is detected"""
1070 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001071 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glass8f1da502018-06-01 09:38:12 -06001072 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass4f443042016-11-25 20:15:52 -07001073 "align-size 0x8 (8)", str(e.exception))
1074
Simon Glass8d2ef3e2022-02-11 13:23:21 -07001075 def testPackAlignPowerOf2Inv(self):
Simon Glass4f443042016-11-25 20:15:52 -07001076 """Test that invalid image alignment is detected"""
1077 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001078 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -06001079 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass4f443042016-11-25 20:15:52 -07001080 "two", str(e.exception))
1081
1082 def testImagePadByte(self):
1083 """Test that the image pad byte can be specified"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001084 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001085 data = self._DoReadFile('021_image_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001086 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0xff, 1) +
Simon Glasse6d85ff2019-05-14 15:53:47 -06001087 U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -07001088
1089 def testImageName(self):
1090 """Test that image files can be named"""
Simon Glass741f2d62018-10-01 12:22:30 -06001091 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001092 self.assertEqual(0, retcode)
1093 image = control.images['image1']
Simon Glassc1aa66e2022-01-29 14:14:04 -07001094 fname = tools.get_output_filename('test-name')
Simon Glass4f443042016-11-25 20:15:52 -07001095 self.assertTrue(os.path.exists(fname))
1096
1097 image = control.images['image2']
Simon Glassc1aa66e2022-01-29 14:14:04 -07001098 fname = tools.get_output_filename('test-name.xx')
Simon Glass4f443042016-11-25 20:15:52 -07001099 self.assertTrue(os.path.exists(fname))
1100
1101 def testBlobFilename(self):
1102 """Test that generic blobs can be provided by filename"""
Simon Glass741f2d62018-10-01 12:22:30 -06001103 data = self._DoReadFile('023_blob.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001104 self.assertEqual(BLOB_DATA, data)
1105
1106 def testPackSorted(self):
1107 """Test that entries can be sorted"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001108 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001109 data = self._DoReadFile('024_sorted.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001110 self.assertEqual(tools.get_bytes(0, 1) + U_BOOT_SPL_DATA +
1111 tools.get_bytes(0, 2) + U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -07001112
Simon Glass3ab95982018-08-01 15:22:37 -06001113 def testPackZeroOffset(self):
1114 """Test that an entry at offset 0 is not given a new offset"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06001115 self._SetupSplElf()
Simon Glass4f443042016-11-25 20:15:52 -07001116 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001117 self._DoTestFile('025_pack_zero_size.dts')
Simon Glass3ab95982018-08-01 15:22:37 -06001118 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -07001119 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1120 str(e.exception))
1121
1122 def testPackUbootDtb(self):
1123 """Test that a device tree can be added to U-Boot"""
Simon Glass741f2d62018-10-01 12:22:30 -06001124 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001125 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glasse0ff8552016-11-25 20:15:53 -07001126
1127 def testPackX86RomNoSize(self):
1128 """Test that the end-at-4gb property requires a size property"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06001129 self._SetupSplElf()
Simon Glasse0ff8552016-11-25 20:15:53 -07001130 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001131 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -06001132 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glasse0ff8552016-11-25 20:15:53 -07001133 "using end-at-4gb", str(e.exception))
1134
Jagdish Gediya94b57db2018-09-03 21:35:07 +05301135 def test4gbAndSkipAtStartTogether(self):
1136 """Test that the end-at-4gb and skip-at-size property can't be used
1137 together"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06001138 self._SetupSplElf()
Jagdish Gediya94b57db2018-09-03 21:35:07 +05301139 with self.assertRaises(ValueError) as e:
Simon Glassdfdd2b62019-08-24 07:23:02 -06001140 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -06001141 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya94b57db2018-09-03 21:35:07 +05301142 "'skip-at-start'", str(e.exception))
1143
Simon Glasse0ff8552016-11-25 20:15:53 -07001144 def testPackX86RomOutside(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001145 """Test that the end-at-4gb property checks for offset boundaries"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06001146 self._SetupSplElf()
Simon Glasse0ff8552016-11-25 20:15:53 -07001147 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001148 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glasse6bed4f2020-10-26 17:40:05 -06001149 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
1150 "is outside the section '/binman' starting at "
1151 '0xffffffe0 (4294967264) of size 0x20 (32)',
Simon Glasse0ff8552016-11-25 20:15:53 -07001152 str(e.exception))
1153
1154 def testPackX86Rom(self):
1155 """Test that a basic x86 ROM can be created"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001156 self._SetupSplElf()
Simon Glass9255f3c2019-08-24 07:23:01 -06001157 data = self._DoReadFile('029_x86_rom.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001158 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 3) + U_BOOT_SPL_DATA +
1159 tools.get_bytes(0, 2), data)
Simon Glasse0ff8552016-11-25 20:15:53 -07001160
1161 def testPackX86RomMeNoDesc(self):
1162 """Test that an invalid Intel descriptor entry is detected"""
Simon Glass0ba4b3d2020-07-09 18:39:41 -06001163 try:
Simon Glass52b10dd2020-07-25 15:11:19 -06001164 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
Simon Glass0ba4b3d2020-07-09 18:39:41 -06001165 with self.assertRaises(ValueError) as e:
Simon Glass52b10dd2020-07-25 15:11:19 -06001166 self._DoTestFile('163_x86_rom_me_empty.dts')
Simon Glass0ba4b3d2020-07-09 18:39:41 -06001167 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1168 str(e.exception))
1169 finally:
1170 self._SetupDescriptor()
Simon Glasse0ff8552016-11-25 20:15:53 -07001171
1172 def testPackX86RomBadDesc(self):
1173 """Test that the Intel requires a descriptor entry"""
1174 with self.assertRaises(ValueError) as e:
Simon Glass9255f3c2019-08-24 07:23:01 -06001175 self._DoTestFile('030_x86_rom_me_no_desc.dts')
Simon Glass3ab95982018-08-01 15:22:37 -06001176 self.assertIn("Node '/binman/intel-me': No offset set with "
1177 "offset-unset: should another entry provide this correct "
1178 "offset?", str(e.exception))
Simon Glasse0ff8552016-11-25 20:15:53 -07001179
1180 def testPackX86RomMe(self):
1181 """Test that an x86 ROM with an ME region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001182 data = self._DoReadFile('031_x86_rom_me.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001183 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glassc5ac1382019-07-08 13:18:54 -06001184 if data[:0x1000] != expected_desc:
1185 self.fail('Expected descriptor binary at start of image')
Simon Glasse0ff8552016-11-25 20:15:53 -07001186 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1187
1188 def testPackVga(self):
1189 """Test that an image with a VGA binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001190 data = self._DoReadFile('032_intel_vga.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -07001191 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1192
1193 def testPackStart16(self):
1194 """Test that an image with an x86 start16 region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001195 data = self._DoReadFile('033_x86_start16.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -07001196 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1197
Jagdish Gediya9d368f32018-09-03 21:35:08 +05301198 def testPackPowerpcMpc85xxBootpgResetvec(self):
1199 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1200 created"""
Simon Glassdfdd2b62019-08-24 07:23:02 -06001201 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
Jagdish Gediya9d368f32018-09-03 21:35:08 +05301202 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1203
Simon Glass736bb0a2018-07-06 10:27:17 -06001204 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glassadc57012018-07-06 10:27:16 -06001205 """Handle running a test for insertion of microcode
1206
1207 Args:
1208 dts_fname: Name of test .dts file
1209 nodtb_data: Data that we expect in the first section
Simon Glass736bb0a2018-07-06 10:27:17 -06001210 ucode_second: True if the microsecond entry is second instead of
1211 third
Simon Glassadc57012018-07-06 10:27:16 -06001212
1213 Returns:
1214 Tuple:
1215 Contents of first region (U-Boot or SPL)
Simon Glass3ab95982018-08-01 15:22:37 -06001216 Offset and size components of microcode pointer, as inserted
Simon Glassadc57012018-07-06 10:27:16 -06001217 in the above (two 4-byte words)
1218 """
Simon Glass6b187df2017-11-12 21:52:27 -07001219 data = self._DoReadFile(dts_fname, True)
Simon Glasse0ff8552016-11-25 20:15:53 -07001220
1221 # Now check the device tree has no microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001222 if ucode_second:
1223 ucode_content = data[len(nodtb_data):]
1224 ucode_pos = len(nodtb_data)
1225 dtb_with_ucode = ucode_content[16:]
1226 fdt_len = self.GetFdtLen(dtb_with_ucode)
1227 else:
1228 dtb_with_ucode = data[len(nodtb_data):]
1229 fdt_len = self.GetFdtLen(dtb_with_ucode)
1230 ucode_content = dtb_with_ucode[fdt_len:]
1231 ucode_pos = len(nodtb_data) + fdt_len
Simon Glassc1aa66e2022-01-29 14:14:04 -07001232 fname = tools.get_output_filename('test.dtb')
Simon Glasse0ff8552016-11-25 20:15:53 -07001233 with open(fname, 'wb') as fd:
Simon Glassadc57012018-07-06 10:27:16 -06001234 fd.write(dtb_with_ucode)
Simon Glassec3f3782017-05-27 07:38:29 -06001235 dtb = fdt.FdtScan(fname)
1236 ucode = dtb.GetNode('/microcode')
Simon Glasse0ff8552016-11-25 20:15:53 -07001237 self.assertTrue(ucode)
1238 for node in ucode.subnodes:
1239 self.assertFalse(node.props.get('data'))
1240
Simon Glasse0ff8552016-11-25 20:15:53 -07001241 # Check that the microcode appears immediately after the Fdt
1242 # This matches the concatenation of the data properties in
Simon Glass87722132017-11-12 21:52:26 -07001243 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glasse0ff8552016-11-25 20:15:53 -07001244 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1245 0x78235609)
Simon Glassadc57012018-07-06 10:27:16 -06001246 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glasse0ff8552016-11-25 20:15:53 -07001247
1248 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -06001249 # expected offset and size
Simon Glasse0ff8552016-11-25 20:15:53 -07001250 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1251 len(ucode_data))
Simon Glass736bb0a2018-07-06 10:27:17 -06001252 u_boot = data[:len(nodtb_data)]
1253 return u_boot, pos_and_size
Simon Glass6b187df2017-11-12 21:52:27 -07001254
1255 def testPackUbootMicrocode(self):
1256 """Test that x86 microcode can be handled correctly
1257
1258 We expect to see the following in the image, in order:
1259 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1260 place
1261 u-boot.dtb with the microcode removed
1262 the microcode
1263 """
Simon Glass741f2d62018-10-01 12:22:30 -06001264 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass6b187df2017-11-12 21:52:27 -07001265 U_BOOT_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001266 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1267 b' somewhere in here', first)
Simon Glasse0ff8552016-11-25 20:15:53 -07001268
Simon Glass160a7662017-05-27 07:38:26 -06001269 def _RunPackUbootSingleMicrocode(self):
Simon Glasse0ff8552016-11-25 20:15:53 -07001270 """Test that x86 microcode can be handled correctly
1271
1272 We expect to see the following in the image, in order:
1273 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1274 place
1275 u-boot.dtb with the microcode
1276 an empty microcode region
1277 """
1278 # We need the libfdt library to run this test since only that allows
1279 # finding the offset of a property. This is required by
1280 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass741f2d62018-10-01 12:22:30 -06001281 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glasse0ff8552016-11-25 20:15:53 -07001282
1283 second = data[len(U_BOOT_NODTB_DATA):]
1284
1285 fdt_len = self.GetFdtLen(second)
1286 third = second[fdt_len:]
1287 second = second[:fdt_len]
1288
Simon Glass160a7662017-05-27 07:38:26 -06001289 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1290 self.assertIn(ucode_data, second)
1291 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -07001292
Simon Glass160a7662017-05-27 07:38:26 -06001293 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -06001294 # expected offset and size
Simon Glass160a7662017-05-27 07:38:26 -06001295 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1296 len(ucode_data))
1297 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glassc6c10e72019-05-17 22:00:46 -06001298 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1299 b' somewhere in here', first)
Simon Glassc49deb82016-11-25 20:15:54 -07001300
Simon Glass75db0862016-11-25 20:15:55 -07001301 def testPackUbootSingleMicrocode(self):
1302 """Test that x86 microcode can be handled correctly with fdt_normal.
1303 """
Simon Glass160a7662017-05-27 07:38:26 -06001304 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001305
Simon Glassc49deb82016-11-25 20:15:54 -07001306 def testUBootImg(self):
1307 """Test that u-boot.img can be put in a file"""
Simon Glass741f2d62018-10-01 12:22:30 -06001308 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glassc49deb82016-11-25 20:15:54 -07001309 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glass75db0862016-11-25 20:15:55 -07001310
1311 def testNoMicrocode(self):
1312 """Test that a missing microcode region is detected"""
1313 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001314 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001315 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1316 "node found in ", str(e.exception))
1317
1318 def testMicrocodeWithoutNode(self):
1319 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1320 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001321 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001322 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1323 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1324
1325 def testMicrocodeWithoutNode2(self):
1326 """Test that a missing u-boot-ucode node is detected"""
1327 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001328 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001329 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1330 "microcode region u-boot-ucode", str(e.exception))
1331
1332 def testMicrocodeWithoutPtrInElf(self):
1333 """Test that a U-Boot binary without the microcode symbol is detected"""
1334 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glass75db0862016-11-25 20:15:55 -07001335 try:
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 Glass75db0862016-11-25 20:15:55 -07001338
1339 with self.assertRaises(ValueError) as e:
Simon Glass160a7662017-05-27 07:38:26 -06001340 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001341 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1342 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1343
1344 finally:
1345 # Put the original file back
Simon Glassf514d8f2019-08-24 07:22:54 -06001346 TestFunctional._MakeInputFile('u-boot',
Simon Glassc1aa66e2022-01-29 14:14:04 -07001347 tools.read_file(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glass75db0862016-11-25 20:15:55 -07001348
1349 def testMicrocodeNotInImage(self):
1350 """Test that microcode must be placed within the image"""
1351 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001352 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001353 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1354 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glass25ac0e62018-06-01 09:38:14 -06001355 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glass75db0862016-11-25 20:15:55 -07001356
1357 def testWithoutMicrocode(self):
1358 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glassbccd91d2019-08-24 07:22:55 -06001359 TestFunctional._MakeInputFile('u-boot',
Simon Glassc1aa66e2022-01-29 14:14:04 -07001360 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass741f2d62018-10-01 12:22:30 -06001361 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001362
1363 # Now check the device tree has no microcode
1364 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1365 second = data[len(U_BOOT_NODTB_DATA):]
1366
1367 fdt_len = self.GetFdtLen(second)
1368 self.assertEqual(dtb, second[:fdt_len])
1369
1370 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1371 third = data[used_len:]
Simon Glassc1aa66e2022-01-29 14:14:04 -07001372 self.assertEqual(tools.get_bytes(0, 0x200 - used_len), third)
Simon Glass75db0862016-11-25 20:15:55 -07001373
1374 def testUnknownPosSize(self):
1375 """Test that microcode must be placed within the image"""
1376 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001377 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glass3ab95982018-08-01 15:22:37 -06001378 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glass75db0862016-11-25 20:15:55 -07001379 "entry 'invalid-entry'", str(e.exception))
Simon Glassda229092016-11-25 20:15:56 -07001380
1381 def testPackFsp(self):
1382 """Test that an image with a FSP binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001383 data = self._DoReadFile('042_intel_fsp.dts')
Simon Glassda229092016-11-25 20:15:56 -07001384 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1385
1386 def testPackCmc(self):
Bin Meng59ea8c22017-08-15 22:41:54 -07001387 """Test that an image with a CMC binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001388 data = self._DoReadFile('043_intel_cmc.dts')
Simon Glassda229092016-11-25 20:15:56 -07001389 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Meng59ea8c22017-08-15 22:41:54 -07001390
1391 def testPackVbt(self):
1392 """Test that an image with a VBT binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001393 data = self._DoReadFile('046_intel_vbt.dts')
Bin Meng59ea8c22017-08-15 22:41:54 -07001394 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glass9fc60b42017-11-12 21:52:22 -07001395
Simon Glass56509842017-11-12 21:52:25 -07001396 def testSplBssPad(self):
1397 """Test that we can pad SPL's BSS with zeros"""
Simon Glass6b187df2017-11-12 21:52:27 -07001398 # ELF file with a '__bss_size' symbol
Simon Glass11ae93e2018-10-01 21:12:47 -06001399 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001400 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001401 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glasse6d85ff2019-05-14 15:53:47 -06001402 data)
Simon Glass56509842017-11-12 21:52:25 -07001403
Simon Glass86af5112018-10-01 21:12:42 -06001404 def testSplBssPadMissing(self):
1405 """Test that a missing symbol is detected"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001406 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glassb50e5612017-11-13 18:54:54 -07001407 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001408 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassb50e5612017-11-13 18:54:54 -07001409 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1410 str(e.exception))
1411
Simon Glass87722132017-11-12 21:52:26 -07001412 def testPackStart16Spl(self):
Simon Glass35b384c2018-09-14 04:57:10 -06001413 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001414 data = self._DoReadFile('048_x86_start16_spl.dts')
Simon Glass87722132017-11-12 21:52:26 -07001415 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1416
Simon Glass736bb0a2018-07-06 10:27:17 -06001417 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1418 """Helper function for microcode tests
Simon Glass6b187df2017-11-12 21:52:27 -07001419
1420 We expect to see the following in the image, in order:
1421 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1422 correct place
1423 u-boot.dtb with the microcode removed
1424 the microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001425
1426 Args:
1427 dts: Device tree file to use for test
1428 ucode_second: True if the microsecond entry is second instead of
1429 third
Simon Glass6b187df2017-11-12 21:52:27 -07001430 """
Simon Glass11ae93e2018-10-01 21:12:47 -06001431 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass736bb0a2018-07-06 10:27:17 -06001432 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1433 ucode_second=ucode_second)
Simon Glassc6c10e72019-05-17 22:00:46 -06001434 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1435 b'ter somewhere in here', first)
Simon Glass6b187df2017-11-12 21:52:27 -07001436
Simon Glass736bb0a2018-07-06 10:27:17 -06001437 def testPackUbootSplMicrocode(self):
1438 """Test that x86 microcode can be handled correctly in SPL"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06001439 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001440 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass736bb0a2018-07-06 10:27:17 -06001441
1442 def testPackUbootSplMicrocodeReorder(self):
1443 """Test that order doesn't matter for microcode entries
1444
1445 This is the same as testPackUbootSplMicrocode but when we process the
1446 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1447 entry, so we reply on binman to try later.
1448 """
Simon Glass741f2d62018-10-01 12:22:30 -06001449 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass736bb0a2018-07-06 10:27:17 -06001450 ucode_second=True)
1451
Simon Glassca4f4ff2017-11-12 21:52:28 -07001452 def testPackMrc(self):
1453 """Test that an image with an MRC binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001454 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassca4f4ff2017-11-12 21:52:28 -07001455 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1456
Simon Glass47419ea2017-11-13 18:54:55 -07001457 def testSplDtb(self):
1458 """Test that an image with spl/u-boot-spl.dtb can be created"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06001459 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001460 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass47419ea2017-11-13 18:54:55 -07001461 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1462
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001463 def testSplNoDtb(self):
1464 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass0fe44dc2021-04-25 08:39:32 +12001465 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001466 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001467 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1468
Simon Glass3d433382021-03-21 18:24:30 +13001469 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
Simon Glass4649bea2023-07-18 07:23:54 -06001470 use_expanded=False, no_write_symbols=False):
Simon Glassf5898822021-03-18 20:24:56 +13001471 """Check the image contains the expected symbol values
1472
1473 Args:
1474 dts: Device tree file to use for test
1475 base_data: Data before and after 'u-boot' section
1476 u_boot_offset: Offset of 'u-boot' section in image
Simon Glass3d433382021-03-21 18:24:30 +13001477 entry_args: Dict of entry args to supply to binman
1478 key: arg name
1479 value: value of that arg
1480 use_expanded: True to use expanded entries where available, e.g.
1481 'u-boot-expanded' instead of 'u-boot'
Simon Glassf5898822021-03-18 20:24:56 +13001482 """
Simon Glass1542c8b2019-08-24 07:22:56 -06001483 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass19790632017-11-13 18:55:01 -07001484 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1485 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03001486 self.assertEqual(syms['_binman_sym_magic'].address, addr)
Simon Glassf5898822021-03-18 20:24:56 +13001487 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03001488 addr + 4)
Simon Glass19790632017-11-13 18:55:01 -07001489
Simon Glass11ae93e2018-10-01 21:12:47 -06001490 self._SetupSplElf('u_boot_binman_syms')
Simon Glass3d433382021-03-21 18:24:30 +13001491 data = self._DoReadFileDtb(dts, entry_args=entry_args,
1492 use_expanded=use_expanded)[0]
Simon Glassf5898822021-03-18 20:24:56 +13001493 # The image should contain the symbols from u_boot_binman_syms.c
1494 # Note that image_pos is adjusted by the base address of the image,
1495 # which is 0x10 in our test image
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03001496 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE,
1497 0x00, u_boot_offset + len(U_BOOT_DATA),
Simon Glassf5898822021-03-18 20:24:56 +13001498 0x10 + u_boot_offset, 0x04)
Simon Glass4649bea2023-07-18 07:23:54 -06001499 if no_write_symbols:
1500 expected = (base_data +
1501 tools.get_bytes(0xff, 0x38 - len(base_data)) +
1502 U_BOOT_DATA + base_data)
1503 else:
1504 expected = (sym_values + base_data[24:] +
1505 tools.get_bytes(0xff, 1) + U_BOOT_DATA + sym_values +
1506 base_data[24:])
Simon Glass19790632017-11-13 18:55:01 -07001507 self.assertEqual(expected, data)
1508
Simon Glassf5898822021-03-18 20:24:56 +13001509 def testSymbols(self):
1510 """Test binman can assign symbols embedded in U-Boot"""
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03001511 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glassf5898822021-03-18 20:24:56 +13001512
1513 def testSymbolsNoDtb(self):
1514 """Test binman can assign symbols embedded in U-Boot SPL"""
Simon Glasse9e0db82021-03-21 18:24:29 +13001515 self.checkSymbols('196_symbols_nodtb.dts',
Simon Glassf5898822021-03-18 20:24:56 +13001516 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1517 0x38)
1518
Simon Glassdd57c132018-06-01 09:38:11 -06001519 def testPackUnitAddress(self):
1520 """Test that we support multiple binaries with the same name"""
Simon Glass741f2d62018-10-01 12:22:30 -06001521 data = self._DoReadFile('054_unit_address.dts')
Simon Glassdd57c132018-06-01 09:38:11 -06001522 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1523
Simon Glass18546952018-06-01 09:38:16 -06001524 def testSections(self):
1525 """Basic test of sections"""
Simon Glass741f2d62018-10-01 12:22:30 -06001526 data = self._DoReadFile('055_sections.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001527 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1528 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
1529 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glass18546952018-06-01 09:38:16 -06001530 self.assertEqual(expected, data)
Simon Glass9fc60b42017-11-12 21:52:22 -07001531
Simon Glass3b0c3822018-06-01 09:38:20 -06001532 def testMap(self):
1533 """Tests outputting a map of the images"""
Simon Glass741f2d62018-10-01 12:22:30 -06001534 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001535 self.assertEqual('''ImagePos Offset Size Name
Simon Glass193d3db2023-02-07 14:34:18 -0700153600000000 00000000 00000028 image
Simon Glass1be70d22018-07-17 13:25:49 -0600153700000000 00000000 00000010 section@0
153800000000 00000000 00000004 u-boot
153900000010 00000010 00000010 section@1
154000000010 00000000 00000004 u-boot
154100000020 00000020 00000004 section@2
154200000020 00000000 00000004 u-boot
Simon Glass3b0c3822018-06-01 09:38:20 -06001543''', map_data)
1544
Simon Glassc8d48ef2018-06-01 09:38:21 -06001545 def testNamePrefix(self):
1546 """Tests that name prefixes are used"""
Simon Glass741f2d62018-10-01 12:22:30 -06001547 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001548 self.assertEqual('''ImagePos Offset Size Name
Simon Glass193d3db2023-02-07 14:34:18 -0700154900000000 00000000 00000028 image
Simon Glass1be70d22018-07-17 13:25:49 -0600155000000000 00000000 00000010 section@0
155100000000 00000000 00000004 ro-u-boot
155200000010 00000010 00000010 section@1
155300000010 00000000 00000004 rw-u-boot
Simon Glassc8d48ef2018-06-01 09:38:21 -06001554''', map_data)
1555
Simon Glass736bb0a2018-07-06 10:27:17 -06001556 def testUnknownContents(self):
1557 """Test that obtaining the contents works as expected"""
1558 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001559 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass8beb11e2019-07-08 14:25:47 -06001560 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glass16287932020-04-17 18:09:03 -06001561 "processing of contents: remaining ["
1562 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass736bb0a2018-07-06 10:27:17 -06001563
Simon Glass5c890232018-07-06 10:27:19 -06001564 def testBadChangeSize(self):
1565 """Test that trying to change the size of an entry fails"""
Simon Glassc52c9e72019-07-08 14:25:37 -06001566 try:
1567 state.SetAllowEntryExpansion(False)
1568 with self.assertRaises(ValueError) as e:
1569 self._DoReadFile('059_change_size.dts', True)
Simon Glass79d3c582019-07-20 12:23:57 -06001570 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glassc52c9e72019-07-08 14:25:37 -06001571 str(e.exception))
1572 finally:
1573 state.SetAllowEntryExpansion(True)
Simon Glass5c890232018-07-06 10:27:19 -06001574
Simon Glass16b8d6b2018-07-06 10:27:42 -06001575 def testUpdateFdt(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001576 """Test that we can update the device tree with offset/size info"""
Simon Glass741f2d62018-10-01 12:22:30 -06001577 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glass16b8d6b2018-07-06 10:27:42 -06001578 update_dtb=True)
Simon Glasscee02e62018-07-17 13:25:52 -06001579 dtb = fdt.Fdt(out_dtb_fname)
1580 dtb.Scan()
Simon Glass12bb1a92019-07-20 12:23:51 -06001581 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001582 self.assertEqual({
Simon Glassdbf6be92018-08-01 15:22:42 -06001583 'image-pos': 0,
Simon Glass8122f392018-07-17 13:25:28 -06001584 'offset': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001585 '_testing:offset': 32,
Simon Glass79d3c582019-07-20 12:23:57 -06001586 '_testing:size': 2,
Simon Glassdbf6be92018-08-01 15:22:42 -06001587 '_testing:image-pos': 32,
Simon Glass3ab95982018-08-01 15:22:37 -06001588 'section@0/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001589 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001590 'section@0/u-boot:image-pos': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001591 'section@0:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001592 'section@0:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001593 'section@0:image-pos': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001594
Simon Glass3ab95982018-08-01 15:22:37 -06001595 'section@1/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001596 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001597 'section@1/u-boot:image-pos': 16,
Simon Glass3ab95982018-08-01 15:22:37 -06001598 'section@1:offset': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001599 'section@1:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001600 'section@1:image-pos': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001601 'size': 40
1602 }, props)
1603
1604 def testUpdateFdtBad(self):
1605 """Test that we detect when ProcessFdt never completes"""
1606 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001607 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001608 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glass16287932020-04-17 18:09:03 -06001609 '[<binman.etype._testing.Entry__testing',
1610 str(e.exception))
Simon Glass5c890232018-07-06 10:27:19 -06001611
Simon Glass53af22a2018-07-17 13:25:32 -06001612 def testEntryArgs(self):
1613 """Test passing arguments to entries from the command line"""
1614 entry_args = {
1615 'test-str-arg': 'test1',
1616 'test-int-arg': '456',
1617 }
Simon Glass741f2d62018-10-01 12:22:30 -06001618 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001619 self.assertIn('image', control.images)
1620 entry = control.images['image'].GetEntries()['_testing']
1621 self.assertEqual('test0', entry.test_str_fdt)
1622 self.assertEqual('test1', entry.test_str_arg)
1623 self.assertEqual(123, entry.test_int_fdt)
1624 self.assertEqual(456, entry.test_int_arg)
1625
1626 def testEntryArgsMissing(self):
1627 """Test missing arguments and properties"""
1628 entry_args = {
1629 'test-int-arg': '456',
1630 }
Simon Glass741f2d62018-10-01 12:22:30 -06001631 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001632 entry = control.images['image'].GetEntries()['_testing']
1633 self.assertEqual('test0', entry.test_str_fdt)
1634 self.assertEqual(None, entry.test_str_arg)
1635 self.assertEqual(None, entry.test_int_fdt)
1636 self.assertEqual(456, entry.test_int_arg)
1637
1638 def testEntryArgsRequired(self):
1639 """Test missing arguments and properties"""
1640 entry_args = {
1641 'test-int-arg': '456',
1642 }
1643 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001644 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass3decfa32020-09-01 05:13:54 -06001645 self.assertIn("Node '/binman/_testing': "
1646 'Missing required properties/entry args: test-str-arg, '
1647 'test-int-fdt, test-int-arg',
Simon Glass53af22a2018-07-17 13:25:32 -06001648 str(e.exception))
1649
1650 def testEntryArgsInvalidFormat(self):
1651 """Test that an invalid entry-argument format is detected"""
Simon Glass53cd5d92019-07-08 14:25:29 -06001652 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1653 '-ano-value']
Simon Glass53af22a2018-07-17 13:25:32 -06001654 with self.assertRaises(ValueError) as e:
1655 self._DoBinman(*args)
1656 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1657
1658 def testEntryArgsInvalidInteger(self):
1659 """Test that an invalid entry-argument integer is detected"""
1660 entry_args = {
1661 'test-int-arg': 'abc',
1662 }
1663 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001664 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001665 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1666 "'test-int-arg' (value 'abc') to integer",
1667 str(e.exception))
1668
1669 def testEntryArgsInvalidDatatype(self):
1670 """Test that an invalid entry-argument datatype is detected
1671
1672 This test could be written in entry_test.py except that it needs
1673 access to control.entry_args, which seems more than that module should
1674 be able to see.
1675 """
1676 entry_args = {
1677 'test-bad-datatype-arg': '12',
1678 }
1679 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001680 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass53af22a2018-07-17 13:25:32 -06001681 entry_args=entry_args)
1682 self.assertIn('GetArg() internal error: Unknown data type ',
1683 str(e.exception))
1684
Simon Glassbb748372018-07-17 13:25:33 -06001685 def testText(self):
1686 """Test for a text entry type"""
1687 entry_args = {
1688 'test-id': TEXT_DATA,
1689 'test-id2': TEXT_DATA2,
1690 'test-id3': TEXT_DATA3,
1691 }
Simon Glass741f2d62018-10-01 12:22:30 -06001692 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glassbb748372018-07-17 13:25:33 -06001693 entry_args=entry_args)
Simon Glassc1aa66e2022-01-29 14:14:04 -07001694 expected = (tools.to_bytes(TEXT_DATA) +
1695 tools.get_bytes(0, 8 - len(TEXT_DATA)) +
1696 tools.to_bytes(TEXT_DATA2) + tools.to_bytes(TEXT_DATA3) +
Simon Glassaa88b502019-07-08 13:18:40 -06001697 b'some text' + b'more text')
Simon Glassbb748372018-07-17 13:25:33 -06001698 self.assertEqual(expected, data)
1699
Simon Glassfd8d1f72018-07-17 13:25:36 -06001700 def testEntryDocs(self):
1701 """Test for creation of entry documentation"""
1702 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass87d43322020-08-05 13:27:46 -06001703 control.WriteEntryDocs(control.GetEntryModules())
Simon Glassfd8d1f72018-07-17 13:25:36 -06001704 self.assertTrue(len(stdout.getvalue()) > 0)
1705
1706 def testEntryDocsMissing(self):
1707 """Test handling of missing entry documentation"""
1708 with self.assertRaises(ValueError) as e:
1709 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass87d43322020-08-05 13:27:46 -06001710 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glassfd8d1f72018-07-17 13:25:36 -06001711 self.assertIn('Documentation is missing for modules: u_boot',
1712 str(e.exception))
1713
Simon Glass11e36cc2018-07-17 13:25:38 -06001714 def testFmap(self):
1715 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001716 data = self._DoReadFile('067_fmap.dts')
Simon Glass11e36cc2018-07-17 13:25:38 -06001717 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc1aa66e2022-01-29 14:14:04 -07001718 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1719 U_BOOT_DATA + tools.get_bytes(ord('a'), 12))
Simon Glass11e36cc2018-07-17 13:25:38 -06001720 self.assertEqual(expected, data[:32])
Simon Glassc6c10e72019-05-17 22:00:46 -06001721 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass11e36cc2018-07-17 13:25:38 -06001722 self.assertEqual(1, fhdr.ver_major)
1723 self.assertEqual(0, fhdr.ver_minor)
1724 self.assertEqual(0, fhdr.base)
Simon Glass17365752021-04-03 11:05:10 +13001725 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 5
Simon Glassc7722e82021-04-03 11:05:09 +13001726 self.assertEqual(16 + 16 + expect_size, fhdr.image_size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001727 self.assertEqual(b'FMAP', fhdr.name)
Simon Glass17365752021-04-03 11:05:10 +13001728 self.assertEqual(5, fhdr.nareas)
Simon Glassc7722e82021-04-03 11:05:09 +13001729 fiter = iter(fentries)
Simon Glass11e36cc2018-07-17 13:25:38 -06001730
Simon Glassc7722e82021-04-03 11:05:09 +13001731 fentry = next(fiter)
Simon Glass17365752021-04-03 11:05:10 +13001732 self.assertEqual(b'SECTION0', fentry.name)
1733 self.assertEqual(0, fentry.offset)
1734 self.assertEqual(16, fentry.size)
Simon Glass9dbb02b2023-02-12 17:11:15 -07001735 self.assertEqual(fmap_util.FMAP_AREA_PRESERVE, fentry.flags)
Simon Glass17365752021-04-03 11:05:10 +13001736
1737 fentry = next(fiter)
Simon Glassc7722e82021-04-03 11:05:09 +13001738 self.assertEqual(b'RO_U_BOOT', fentry.name)
1739 self.assertEqual(0, fentry.offset)
1740 self.assertEqual(4, fentry.size)
1741 self.assertEqual(0, fentry.flags)
Simon Glass11e36cc2018-07-17 13:25:38 -06001742
Simon Glassc7722e82021-04-03 11:05:09 +13001743 fentry = next(fiter)
Simon Glass17365752021-04-03 11:05:10 +13001744 self.assertEqual(b'SECTION1', fentry.name)
1745 self.assertEqual(16, fentry.offset)
1746 self.assertEqual(16, fentry.size)
1747 self.assertEqual(0, fentry.flags)
1748
1749 fentry = next(fiter)
Simon Glassc7722e82021-04-03 11:05:09 +13001750 self.assertEqual(b'RW_U_BOOT', fentry.name)
1751 self.assertEqual(16, fentry.offset)
1752 self.assertEqual(4, fentry.size)
1753 self.assertEqual(0, fentry.flags)
Simon Glass11e36cc2018-07-17 13:25:38 -06001754
Simon Glassc7722e82021-04-03 11:05:09 +13001755 fentry = next(fiter)
1756 self.assertEqual(b'FMAP', fentry.name)
1757 self.assertEqual(32, fentry.offset)
1758 self.assertEqual(expect_size, fentry.size)
1759 self.assertEqual(0, fentry.flags)
Simon Glass11e36cc2018-07-17 13:25:38 -06001760
Simon Glassec127af2018-07-17 13:25:39 -06001761 def testBlobNamedByArg(self):
1762 """Test we can add a blob with the filename coming from an entry arg"""
1763 entry_args = {
1764 'cros-ec-rw-path': 'ecrw.bin',
1765 }
Simon Glass3decfa32020-09-01 05:13:54 -06001766 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassec127af2018-07-17 13:25:39 -06001767
Simon Glass3af8e492018-07-17 13:25:40 -06001768 def testFill(self):
1769 """Test for an fill entry type"""
Simon Glass741f2d62018-10-01 12:22:30 -06001770 data = self._DoReadFile('069_fill.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001771 expected = tools.get_bytes(0xff, 8) + tools.get_bytes(0, 8)
Simon Glass3af8e492018-07-17 13:25:40 -06001772 self.assertEqual(expected, data)
1773
1774 def testFillNoSize(self):
1775 """Test for an fill entry type with no size"""
1776 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001777 self._DoReadFile('070_fill_no_size.dts')
Simon Glasscdadada2022-08-13 11:40:44 -06001778 self.assertIn("'fill' entry is missing properties: size",
Simon Glass3af8e492018-07-17 13:25:40 -06001779 str(e.exception))
1780
Simon Glass0ef87aa2018-07-17 13:25:44 -06001781 def _HandleGbbCommand(self, pipe_list):
1782 """Fake calls to the futility utility"""
Simon Glassfe7e9242023-02-22 12:14:49 -07001783 if 'futility' in pipe_list[0][0]:
Simon Glass0ef87aa2018-07-17 13:25:44 -06001784 fname = pipe_list[0][-1]
1785 # Append our GBB data to the file, which will happen every time the
1786 # futility command is called.
Simon Glass1d0ebf72019-05-14 15:53:42 -06001787 with open(fname, 'ab') as fd:
Simon Glass0ef87aa2018-07-17 13:25:44 -06001788 fd.write(GBB_DATA)
1789 return command.CommandResult()
1790
1791 def testGbb(self):
1792 """Test for the Chromium OS Google Binary Block"""
1793 command.test_result = self._HandleGbbCommand
1794 entry_args = {
1795 'keydir': 'devkeys',
1796 'bmpblk': 'bmpblk.bin',
1797 }
Simon Glass741f2d62018-10-01 12:22:30 -06001798 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glass0ef87aa2018-07-17 13:25:44 -06001799
1800 # Since futility
Simon Glassc1aa66e2022-01-29 14:14:04 -07001801 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
1802 tools.get_bytes(0, 0x2180 - 16))
Simon Glass0ef87aa2018-07-17 13:25:44 -06001803 self.assertEqual(expected, data)
1804
1805 def testGbbTooSmall(self):
1806 """Test for the Chromium OS Google Binary Block being large enough"""
1807 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001808 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001809 self.assertIn("Node '/binman/gbb': GBB is too small",
1810 str(e.exception))
1811
1812 def testGbbNoSize(self):
1813 """Test for the Chromium OS Google Binary Block having a size"""
1814 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001815 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001816 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1817 str(e.exception))
1818
Simon Glass4f9ee832022-01-09 20:14:09 -07001819 def testGbbMissing(self):
1820 """Test that binman still produces an image if futility is missing"""
1821 entry_args = {
1822 'keydir': 'devkeys',
1823 }
1824 with test_util.capture_sys_output() as (_, stderr):
1825 self._DoTestFile('071_gbb.dts', force_missing_bintools='futility',
1826 entry_args=entry_args)
1827 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07001828 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass4f9ee832022-01-09 20:14:09 -07001829
Simon Glass24d0d3c2018-07-17 13:25:47 -06001830 def _HandleVblockCommand(self, pipe_list):
Simon Glass5af9ebc2021-01-06 21:35:17 -07001831 """Fake calls to the futility utility
1832
1833 The expected pipe is:
1834
1835 [('futility', 'vbutil_firmware', '--vblock',
1836 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1837 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1838 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1839 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1840
1841 This writes to the output file (here, 'vblock.vblock'). If
1842 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1843 of the input data (here, 'input.vblock').
1844 """
Simon Glassfe7e9242023-02-22 12:14:49 -07001845 if 'futility' in pipe_list[0][0]:
Simon Glass24d0d3c2018-07-17 13:25:47 -06001846 fname = pipe_list[0][3]
Simon Glassa326b492018-09-14 04:57:11 -06001847 with open(fname, 'wb') as fd:
Simon Glass5af9ebc2021-01-06 21:35:17 -07001848 if self._hash_data:
1849 infile = pipe_list[0][11]
1850 m = hashlib.sha256()
Simon Glassc1aa66e2022-01-29 14:14:04 -07001851 data = tools.read_file(infile)
Simon Glass5af9ebc2021-01-06 21:35:17 -07001852 m.update(data)
1853 fd.write(m.digest())
1854 else:
1855 fd.write(VBLOCK_DATA)
1856
Simon Glass24d0d3c2018-07-17 13:25:47 -06001857 return command.CommandResult()
1858
1859 def testVblock(self):
1860 """Test for the Chromium OS Verified Boot Block"""
Simon Glass5af9ebc2021-01-06 21:35:17 -07001861 self._hash_data = False
Simon Glass24d0d3c2018-07-17 13:25:47 -06001862 command.test_result = self._HandleVblockCommand
1863 entry_args = {
1864 'keydir': 'devkeys',
1865 }
Simon Glass741f2d62018-10-01 12:22:30 -06001866 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass24d0d3c2018-07-17 13:25:47 -06001867 entry_args=entry_args)
1868 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1869 self.assertEqual(expected, data)
1870
1871 def testVblockNoContent(self):
1872 """Test we detect a vblock which has no content to sign"""
1873 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001874 self._DoReadFile('075_vblock_no_content.dts')
Simon Glass189f2912021-03-21 18:24:31 +13001875 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
Simon Glass24d0d3c2018-07-17 13:25:47 -06001876 'property', str(e.exception))
1877
1878 def testVblockBadPhandle(self):
1879 """Test that we detect a vblock with an invalid phandle in contents"""
1880 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001881 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001882 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1883 '1000', str(e.exception))
1884
1885 def testVblockBadEntry(self):
1886 """Test that we detect an entry that points to a non-entry"""
1887 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001888 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001889 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1890 "'other'", str(e.exception))
1891
Simon Glass5af9ebc2021-01-06 21:35:17 -07001892 def testVblockContent(self):
1893 """Test that the vblock signs the right data"""
1894 self._hash_data = True
1895 command.test_result = self._HandleVblockCommand
1896 entry_args = {
1897 'keydir': 'devkeys',
1898 }
1899 data = self._DoReadFileDtb(
1900 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1901 entry_args=entry_args)[0]
1902 hashlen = 32 # SHA256 hash is 32 bytes
1903 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1904 hashval = data[-hashlen:]
1905 dtb = data[len(U_BOOT_DATA):-hashlen]
1906
1907 expected_data = U_BOOT_DATA + dtb
1908
1909 # The hashval should be a hash of the dtb
1910 m = hashlib.sha256()
1911 m.update(expected_data)
1912 expected_hashval = m.digest()
1913 self.assertEqual(expected_hashval, hashval)
1914
Simon Glass4f9ee832022-01-09 20:14:09 -07001915 def testVblockMissing(self):
1916 """Test that binman still produces an image if futility is missing"""
1917 entry_args = {
1918 'keydir': 'devkeys',
1919 }
1920 with test_util.capture_sys_output() as (_, stderr):
1921 self._DoTestFile('074_vblock.dts',
1922 force_missing_bintools='futility',
1923 entry_args=entry_args)
1924 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07001925 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass4f9ee832022-01-09 20:14:09 -07001926
Simon Glassb8ef5b62018-07-17 13:25:48 -06001927 def testTpl(self):
Simon Glass2090f1e2019-08-24 07:23:00 -06001928 """Test that an image with TPL and its device tree can be created"""
Simon Glassb8ef5b62018-07-17 13:25:48 -06001929 # ELF file with a '__bss_size' symbol
Simon Glass2090f1e2019-08-24 07:23:00 -06001930 self._SetupTplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001931 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glassb8ef5b62018-07-17 13:25:48 -06001932 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1933
Simon Glass15a587c2018-07-17 13:25:51 -06001934 def testUsesPos(self):
1935 """Test that the 'pos' property cannot be used anymore"""
1936 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001937 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass15a587c2018-07-17 13:25:51 -06001938 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1939 "'pos'", str(e.exception))
1940
Simon Glassd178eab2018-09-14 04:57:08 -06001941 def testFillZero(self):
1942 """Test for an fill entry type with a size of 0"""
Simon Glass741f2d62018-10-01 12:22:30 -06001943 data = self._DoReadFile('080_fill_empty.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001944 self.assertEqual(tools.get_bytes(0, 16), data)
Simon Glassd178eab2018-09-14 04:57:08 -06001945
Simon Glass0b489362018-09-14 04:57:09 -06001946 def testTextMissing(self):
1947 """Test for a text entry type where there is no text"""
1948 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001949 self._DoReadFileDtb('066_text.dts',)
Simon Glass0b489362018-09-14 04:57:09 -06001950 self.assertIn("Node '/binman/text': No value provided for text label "
1951 "'test-id'", str(e.exception))
1952
Simon Glass35b384c2018-09-14 04:57:10 -06001953 def testPackStart16Tpl(self):
1954 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001955 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glass35b384c2018-09-14 04:57:10 -06001956 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1957
Simon Glass0bfa7b02018-09-14 04:57:12 -06001958 def testSelectImage(self):
1959 """Test that we can select which images to build"""
Simon Glasseb833d82019-04-25 21:58:34 -06001960 expected = 'Skipping images: image1'
Simon Glass0bfa7b02018-09-14 04:57:12 -06001961
Simon Glasseb833d82019-04-25 21:58:34 -06001962 # We should only get the expected message in verbose mode
Simon Glassee0c9a72019-07-08 13:18:48 -06001963 for verbosity in (0, 2):
Simon Glasseb833d82019-04-25 21:58:34 -06001964 with test_util.capture_sys_output() as (stdout, stderr):
1965 retcode = self._DoTestFile('006_dual_image.dts',
1966 verbosity=verbosity,
1967 images=['image2'])
1968 self.assertEqual(0, retcode)
1969 if verbosity:
1970 self.assertIn(expected, stdout.getvalue())
1971 else:
1972 self.assertNotIn(expected, stdout.getvalue())
1973
Simon Glassc1aa66e2022-01-29 14:14:04 -07001974 self.assertFalse(os.path.exists(tools.get_output_filename('image1.bin')))
1975 self.assertTrue(os.path.exists(tools.get_output_filename('image2.bin')))
Simon Glassf86a7362019-07-20 12:24:10 -06001976 self._CleanupOutputDir()
Simon Glass0bfa7b02018-09-14 04:57:12 -06001977
Simon Glass6ed45ba2018-09-14 04:57:24 -06001978 def testUpdateFdtAll(self):
1979 """Test that all device trees are updated with offset/size info"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06001980 self._SetupSplElf()
1981 self._SetupTplElf()
Simon Glass3c081312019-07-08 14:25:26 -06001982 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glass6ed45ba2018-09-14 04:57:24 -06001983
1984 base_expected = {
Simon Glass6ed45ba2018-09-14 04:57:24 -06001985 'offset': 0,
Simon Glass6ad24522022-02-28 07:16:54 -07001986 'image-pos': 0,
1987 'size': 2320,
Simon Glass6ed45ba2018-09-14 04:57:24 -06001988 'section:offset': 0,
Simon Glass6ad24522022-02-28 07:16:54 -07001989 'section:image-pos': 0,
1990 'section:size': 565,
1991 'section/u-boot-dtb:offset': 0,
1992 'section/u-boot-dtb:image-pos': 0,
1993 'section/u-boot-dtb:size': 565,
1994 'u-boot-spl-dtb:offset': 565,
1995 'u-boot-spl-dtb:image-pos': 565,
1996 'u-boot-spl-dtb:size': 585,
1997 'u-boot-tpl-dtb:offset': 1150,
1998 'u-boot-tpl-dtb:image-pos': 1150,
1999 'u-boot-tpl-dtb:size': 585,
2000 'u-boot-vpl-dtb:image-pos': 1735,
2001 'u-boot-vpl-dtb:offset': 1735,
2002 'u-boot-vpl-dtb:size': 585,
Simon Glass6ed45ba2018-09-14 04:57:24 -06002003 }
2004
2005 # We expect three device-tree files in the output, one after the other.
2006 # Read them in sequence. We look for an 'spl' property in the SPL tree,
2007 # and 'tpl' in the TPL tree, to make sure they are distinct from the
2008 # main U-Boot tree. All three should have the same postions and offset.
2009 start = 0
Simon Glass6ad24522022-02-28 07:16:54 -07002010 self.maxDiff = None
2011 for item in ['', 'spl', 'tpl', 'vpl']:
Simon Glass6ed45ba2018-09-14 04:57:24 -06002012 dtb = fdt.Fdt.FromData(data[start:])
2013 dtb.Scan()
Simon Glass12bb1a92019-07-20 12:23:51 -06002014 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
Simon Glass6ad24522022-02-28 07:16:54 -07002015 ['spl', 'tpl', 'vpl'])
Simon Glass6ed45ba2018-09-14 04:57:24 -06002016 expected = dict(base_expected)
2017 if item:
2018 expected[item] = 0
2019 self.assertEqual(expected, props)
2020 start += dtb._fdt_obj.totalsize()
2021
2022 def testUpdateFdtOutput(self):
2023 """Test that output DTB files are updated"""
2024 try:
Simon Glass741f2d62018-10-01 12:22:30 -06002025 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glass6ed45ba2018-09-14 04:57:24 -06002026 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
2027
2028 # Unfortunately, compiling a source file always results in a file
2029 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass741f2d62018-10-01 12:22:30 -06002030 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glass6ed45ba2018-09-14 04:57:24 -06002031 # binman as a file called u-boot.dtb. To fix this, copy the file
2032 # over to the expected place.
Simon Glass6ed45ba2018-09-14 04:57:24 -06002033 start = 0
2034 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
Simon Glass6ad24522022-02-28 07:16:54 -07002035 'tpl/u-boot-tpl.dtb.out', 'vpl/u-boot-vpl.dtb.out']:
Simon Glass6ed45ba2018-09-14 04:57:24 -06002036 dtb = fdt.Fdt.FromData(data[start:])
2037 size = dtb._fdt_obj.totalsize()
Simon Glassc1aa66e2022-01-29 14:14:04 -07002038 pathname = tools.get_output_filename(os.path.split(fname)[1])
2039 outdata = tools.read_file(pathname)
Simon Glass6ed45ba2018-09-14 04:57:24 -06002040 name = os.path.split(fname)[0]
2041
2042 if name:
Simon Glass6ad24522022-02-28 07:16:54 -07002043 orig_indata = self._GetDtbContentsForSpls(dtb_data, name)
Simon Glass6ed45ba2018-09-14 04:57:24 -06002044 else:
2045 orig_indata = dtb_data
2046 self.assertNotEqual(outdata, orig_indata,
2047 "Expected output file '%s' be updated" % pathname)
2048 self.assertEqual(outdata, data[start:start + size],
2049 "Expected output file '%s' to match output image" %
2050 pathname)
2051 start += size
2052 finally:
2053 self._ResetDtbs()
2054
Simon Glass83d73c22018-09-14 04:57:26 -06002055 def _decompress(self, data):
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +02002056 bintool = self.comp_bintools['lz4']
2057 return bintool.decompress(data)
Simon Glass83d73c22018-09-14 04:57:26 -06002058
2059 def testCompress(self):
2060 """Test compression of blobs"""
Simon Glassac62fba2019-07-08 13:18:53 -06002061 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06002062 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass83d73c22018-09-14 04:57:26 -06002063 use_real_dtb=True, update_dtb=True)
2064 dtb = fdt.Fdt(out_dtb_fname)
2065 dtb.Scan()
2066 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2067 orig = self._decompress(data)
2068 self.assertEquals(COMPRESS_DATA, orig)
Simon Glass97c3e9a2020-10-26 17:40:15 -06002069
2070 # Do a sanity check on various fields
2071 image = control.images['image']
2072 entries = image.GetEntries()
2073 self.assertEqual(1, len(entries))
2074
2075 entry = entries['blob']
2076 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
2077 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
2078 orig = self._decompress(entry.data)
2079 self.assertEqual(orig, entry.uncomp_data)
2080
Simon Glass63e7ba62020-10-26 17:40:16 -06002081 self.assertEqual(image.data, entry.data)
2082
Simon Glass83d73c22018-09-14 04:57:26 -06002083 expected = {
2084 'blob:uncomp-size': len(COMPRESS_DATA),
2085 'blob:size': len(data),
2086 'size': len(data),
2087 }
2088 self.assertEqual(expected, props)
2089
Simon Glass0a98b282018-09-14 04:57:28 -06002090 def testFiles(self):
2091 """Test bringing in multiple files"""
Simon Glass741f2d62018-10-01 12:22:30 -06002092 data = self._DoReadFile('084_files.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06002093 self.assertEqual(FILES_DATA, data)
2094
2095 def testFilesCompress(self):
2096 """Test bringing in multiple files and compressing them"""
Simon Glassac62fba2019-07-08 13:18:53 -06002097 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06002098 data = self._DoReadFile('085_files_compress.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06002099
2100 image = control.images['image']
2101 entries = image.GetEntries()
2102 files = entries['files']
Simon Glass8beb11e2019-07-08 14:25:47 -06002103 entries = files._entries
Simon Glass0a98b282018-09-14 04:57:28 -06002104
Simon Glassc6c10e72019-05-17 22:00:46 -06002105 orig = b''
Simon Glass0a98b282018-09-14 04:57:28 -06002106 for i in range(1, 3):
2107 key = '%d.dat' % i
2108 start = entries[key].image_pos
2109 len = entries[key].size
2110 chunk = data[start:start + len]
2111 orig += self._decompress(chunk)
2112
2113 self.assertEqual(FILES_DATA, orig)
2114
2115 def testFilesMissing(self):
2116 """Test missing files"""
2117 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002118 data = self._DoReadFile('086_files_none.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06002119 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
2120 'no files', str(e.exception))
2121
2122 def testFilesNoPattern(self):
2123 """Test missing files"""
2124 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002125 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06002126 self.assertIn("Node '/binman/files': Missing 'pattern' property",
2127 str(e.exception))
2128
Simon Glass80a66ae2022-03-05 20:18:59 -07002129 def testExtendSize(self):
2130 """Test an extending entry"""
2131 data, _, map_data, _ = self._DoReadFileDtb('088_extend_size.dts',
Simon Glassba64a0b2018-09-14 04:57:29 -06002132 map=True)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002133 expect = (tools.get_bytes(ord('a'), 8) + U_BOOT_DATA +
2134 MRC_DATA + tools.get_bytes(ord('b'), 1) + U_BOOT_DATA +
2135 tools.get_bytes(ord('c'), 8) + U_BOOT_DATA +
2136 tools.get_bytes(ord('d'), 8))
Simon Glassba64a0b2018-09-14 04:57:29 -06002137 self.assertEqual(expect, data)
2138 self.assertEqual('''ImagePos Offset Size Name
Simon Glass193d3db2023-02-07 14:34:18 -0700213900000000 00000000 00000028 image
Simon Glassba64a0b2018-09-14 04:57:29 -0600214000000000 00000000 00000008 fill
214100000008 00000008 00000004 u-boot
21420000000c 0000000c 00000004 section
21430000000c 00000000 00000003 intel-mrc
214400000010 00000010 00000004 u-boot2
214500000014 00000014 0000000c section2
214600000014 00000000 00000008 fill
21470000001c 00000008 00000004 u-boot
214800000020 00000020 00000008 fill2
2149''', map_data)
2150
Simon Glass80a66ae2022-03-05 20:18:59 -07002151 def testExtendSizeBad(self):
2152 """Test an extending entry which fails to provide contents"""
Simon Glass163ed6c2018-09-14 04:57:36 -06002153 with test_util.capture_sys_output() as (stdout, stderr):
2154 with self.assertRaises(ValueError) as e:
Simon Glass80a66ae2022-03-05 20:18:59 -07002155 self._DoReadFileDtb('089_extend_size_bad.dts', map=True)
Simon Glassba64a0b2018-09-14 04:57:29 -06002156 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
2157 'expanding entry', str(e.exception))
2158
Simon Glasse0e5df92018-09-14 04:57:31 -06002159 def testHash(self):
2160 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06002161 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06002162 use_real_dtb=True, update_dtb=True)
2163 dtb = fdt.Fdt(out_dtb_fname)
2164 dtb.Scan()
2165 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
2166 m = hashlib.sha256()
2167 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06002168 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06002169
2170 def testHashNoAlgo(self):
2171 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002172 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06002173 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2174 'hash node', str(e.exception))
2175
2176 def testHashBadAlgo(self):
2177 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002178 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glass8db1f992022-02-08 10:59:44 -07002179 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm 'invalid'",
Simon Glasse0e5df92018-09-14 04:57:31 -06002180 str(e.exception))
2181
2182 def testHashSection(self):
2183 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06002184 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06002185 use_real_dtb=True, update_dtb=True)
2186 dtb = fdt.Fdt(out_dtb_fname)
2187 dtb.Scan()
2188 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2189 m = hashlib.sha256()
2190 m.update(U_BOOT_DATA)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002191 m.update(tools.get_bytes(ord('a'), 16))
Simon Glassc6c10e72019-05-17 22:00:46 -06002192 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06002193
Simon Glassf0253632018-09-14 04:57:32 -06002194 def testPackUBootTplMicrocode(self):
2195 """Test that x86 microcode can be handled correctly in TPL
2196
2197 We expect to see the following in the image, in order:
2198 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2199 place
2200 u-boot-tpl.dtb with the microcode removed
2201 the microcode
2202 """
Simon Glass2090f1e2019-08-24 07:23:00 -06002203 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass741f2d62018-10-01 12:22:30 -06002204 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glassf0253632018-09-14 04:57:32 -06002205 U_BOOT_TPL_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06002206 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2207 b'ter somewhere in here', first)
Simon Glassf0253632018-09-14 04:57:32 -06002208
Simon Glassf8f8df62018-09-14 04:57:34 -06002209 def testFmapX86(self):
2210 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06002211 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassf8f8df62018-09-14 04:57:34 -06002212 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc1aa66e2022-01-29 14:14:04 -07002213 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('a'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06002214 self.assertEqual(expected, data[:32])
2215 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2216
2217 self.assertEqual(0x100, fhdr.image_size)
2218
2219 self.assertEqual(0, fentries[0].offset)
2220 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06002221 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06002222
2223 self.assertEqual(4, fentries[1].offset)
2224 self.assertEqual(3, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06002225 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06002226
2227 self.assertEqual(32, fentries[2].offset)
2228 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2229 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06002230 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06002231
2232 def testFmapX86Section(self):
2233 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06002234 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002235 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('b'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06002236 self.assertEqual(expected, data[:32])
2237 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2238
Simon Glass17365752021-04-03 11:05:10 +13002239 self.assertEqual(0x180, fhdr.image_size)
2240 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
Simon Glassc7722e82021-04-03 11:05:09 +13002241 fiter = iter(fentries)
Simon Glassf8f8df62018-09-14 04:57:34 -06002242
Simon Glassc7722e82021-04-03 11:05:09 +13002243 fentry = next(fiter)
2244 self.assertEqual(b'U_BOOT', fentry.name)
2245 self.assertEqual(0, fentry.offset)
2246 self.assertEqual(4, fentry.size)
Simon Glassf8f8df62018-09-14 04:57:34 -06002247
Simon Glassc7722e82021-04-03 11:05:09 +13002248 fentry = next(fiter)
Simon Glass17365752021-04-03 11:05:10 +13002249 self.assertEqual(b'SECTION', fentry.name)
2250 self.assertEqual(4, fentry.offset)
2251 self.assertEqual(0x20 + expect_size, fentry.size)
2252
2253 fentry = next(fiter)
Simon Glassc7722e82021-04-03 11:05:09 +13002254 self.assertEqual(b'INTEL_MRC', fentry.name)
2255 self.assertEqual(4, fentry.offset)
2256 self.assertEqual(3, fentry.size)
Simon Glassf8f8df62018-09-14 04:57:34 -06002257
Simon Glassc7722e82021-04-03 11:05:09 +13002258 fentry = next(fiter)
2259 self.assertEqual(b'FMAP', fentry.name)
2260 self.assertEqual(36, fentry.offset)
2261 self.assertEqual(expect_size, fentry.size)
Simon Glassf8f8df62018-09-14 04:57:34 -06002262
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002263 def testElf(self):
2264 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06002265 self._SetupSplElf()
Simon Glass2090f1e2019-08-24 07:23:00 -06002266 self._SetupTplElf()
Simon Glass53e22bf2019-08-24 07:22:53 -06002267 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002268 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06002269 data = self._DoReadFile('096_elf.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002270
Simon Glass093d1682019-07-08 13:18:25 -06002271 def testElfStrip(self):
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002272 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06002273 self._SetupSplElf()
Simon Glass53e22bf2019-08-24 07:22:53 -06002274 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002275 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06002276 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002277
Simon Glass163ed6c2018-09-14 04:57:36 -06002278 def testPackOverlapMap(self):
2279 """Test that overlapping regions are detected"""
2280 with test_util.capture_sys_output() as (stdout, stderr):
2281 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002282 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002283 map_fname = tools.get_output_filename('image.map')
Simon Glass163ed6c2018-09-14 04:57:36 -06002284 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2285 stdout.getvalue())
2286
2287 # We should not get an inmage, but there should be a map file
Simon Glassc1aa66e2022-01-29 14:14:04 -07002288 self.assertFalse(os.path.exists(tools.get_output_filename('image.bin')))
Simon Glass163ed6c2018-09-14 04:57:36 -06002289 self.assertTrue(os.path.exists(map_fname))
Simon Glassc1aa66e2022-01-29 14:14:04 -07002290 map_data = tools.read_file(map_fname, binary=False)
Simon Glass163ed6c2018-09-14 04:57:36 -06002291 self.assertEqual('''ImagePos Offset Size Name
Simon Glass193d3db2023-02-07 14:34:18 -07002292<none> 00000000 00000008 image
Simon Glass163ed6c2018-09-14 04:57:36 -06002293<none> 00000000 00000004 u-boot
2294<none> 00000003 00000004 u-boot-align
2295''', map_data)
2296
Simon Glass093d1682019-07-08 13:18:25 -06002297 def testPackRefCode(self):
Simon Glass3ae192c2018-10-01 12:22:31 -06002298 """Test that an image with an Intel Reference code binary works"""
2299 data = self._DoReadFile('100_intel_refcode.dts')
2300 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2301
Simon Glass9481c802019-04-25 21:58:39 -06002302 def testSectionOffset(self):
2303 """Tests use of a section with an offset"""
2304 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2305 map=True)
2306 self.assertEqual('''ImagePos Offset Size Name
Simon Glass193d3db2023-02-07 14:34:18 -0700230700000000 00000000 00000038 image
Simon Glass9481c802019-04-25 21:58:39 -0600230800000004 00000004 00000010 section@0
230900000004 00000000 00000004 u-boot
231000000018 00000018 00000010 section@1
231100000018 00000000 00000004 u-boot
23120000002c 0000002c 00000004 section@2
23130000002c 00000000 00000004 u-boot
2314''', map_data)
2315 self.assertEqual(data,
Simon Glassc1aa66e2022-01-29 14:14:04 -07002316 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2317 tools.get_bytes(0x21, 12) +
2318 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2319 tools.get_bytes(0x61, 12) +
2320 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2321 tools.get_bytes(0x26, 8))
Simon Glass9481c802019-04-25 21:58:39 -06002322
Simon Glassac62fba2019-07-08 13:18:53 -06002323 def testCbfsRaw(self):
2324 """Test base handling of a Coreboot Filesystem (CBFS)
2325
2326 The exact contents of the CBFS is verified by similar tests in
2327 cbfs_util_test.py. The tests here merely check that the files added to
2328 the CBFS can be found in the final image.
2329 """
2330 data = self._DoReadFile('102_cbfs_raw.dts')
2331 size = 0xb0
2332
2333 cbfs = cbfs_util.CbfsReader(data)
2334 self.assertEqual(size, cbfs.rom_size)
2335
2336 self.assertIn('u-boot-dtb', cbfs.files)
2337 cfile = cbfs.files['u-boot-dtb']
2338 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2339
2340 def testCbfsArch(self):
2341 """Test on non-x86 architecture"""
2342 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2343 size = 0x100
2344
2345 cbfs = cbfs_util.CbfsReader(data)
2346 self.assertEqual(size, cbfs.rom_size)
2347
2348 self.assertIn('u-boot-dtb', cbfs.files)
2349 cfile = cbfs.files['u-boot-dtb']
2350 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2351
2352 def testCbfsStage(self):
2353 """Tests handling of a Coreboot Filesystem (CBFS)"""
2354 if not elf.ELF_TOOLS:
2355 self.skipTest('Python elftools not available')
2356 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2357 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2358 size = 0xb0
2359
2360 data = self._DoReadFile('104_cbfs_stage.dts')
2361 cbfs = cbfs_util.CbfsReader(data)
2362 self.assertEqual(size, cbfs.rom_size)
2363
2364 self.assertIn('u-boot', cbfs.files)
2365 cfile = cbfs.files['u-boot']
2366 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2367
2368 def testCbfsRawCompress(self):
2369 """Test handling of compressing raw files"""
2370 self._CheckLz4()
2371 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2372 size = 0x140
2373
2374 cbfs = cbfs_util.CbfsReader(data)
2375 self.assertIn('u-boot', cbfs.files)
2376 cfile = cbfs.files['u-boot']
2377 self.assertEqual(COMPRESS_DATA, cfile.data)
2378
2379 def testCbfsBadArch(self):
2380 """Test handling of a bad architecture"""
2381 with self.assertRaises(ValueError) as e:
2382 self._DoReadFile('106_cbfs_bad_arch.dts')
2383 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2384
2385 def testCbfsNoSize(self):
2386 """Test handling of a missing size property"""
2387 with self.assertRaises(ValueError) as e:
2388 self._DoReadFile('107_cbfs_no_size.dts')
2389 self.assertIn('entry must have a size property', str(e.exception))
2390
Simon Glasse2f04742021-11-23 11:03:54 -07002391 def testCbfsNoContents(self):
Simon Glassac62fba2019-07-08 13:18:53 -06002392 """Test handling of a CBFS entry which does not provide contentsy"""
2393 with self.assertRaises(ValueError) as e:
2394 self._DoReadFile('108_cbfs_no_contents.dts')
2395 self.assertIn('Could not complete processing of contents',
2396 str(e.exception))
2397
2398 def testCbfsBadCompress(self):
2399 """Test handling of a bad architecture"""
2400 with self.assertRaises(ValueError) as e:
2401 self._DoReadFile('109_cbfs_bad_compress.dts')
2402 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2403 str(e.exception))
2404
2405 def testCbfsNamedEntries(self):
2406 """Test handling of named entries"""
2407 data = self._DoReadFile('110_cbfs_name.dts')
2408
2409 cbfs = cbfs_util.CbfsReader(data)
2410 self.assertIn('FRED', cbfs.files)
2411 cfile1 = cbfs.files['FRED']
2412 self.assertEqual(U_BOOT_DATA, cfile1.data)
2413
2414 self.assertIn('hello', cbfs.files)
2415 cfile2 = cbfs.files['hello']
2416 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2417
Simon Glassc5ac1382019-07-08 13:18:54 -06002418 def _SetupIfwi(self, fname):
2419 """Set up to run an IFWI test
2420
2421 Args:
2422 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2423 """
2424 self._SetupSplElf()
Simon Glass2090f1e2019-08-24 07:23:00 -06002425 self._SetupTplElf()
Simon Glassc5ac1382019-07-08 13:18:54 -06002426
2427 # Intel Integrated Firmware Image (IFWI) file
2428 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2429 data = fd.read()
2430 TestFunctional._MakeInputFile(fname,data)
2431
2432 def _CheckIfwi(self, data):
2433 """Check that an image with an IFWI contains the correct output
2434
2435 Args:
2436 data: Conents of output file
2437 """
Simon Glassc1aa66e2022-01-29 14:14:04 -07002438 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glassc5ac1382019-07-08 13:18:54 -06002439 if data[:0x1000] != expected_desc:
2440 self.fail('Expected descriptor binary at start of image')
2441
2442 # We expect to find the TPL wil in subpart IBBP entry IBBL
Simon Glassc1aa66e2022-01-29 14:14:04 -07002443 image_fname = tools.get_output_filename('image.bin')
2444 tpl_fname = tools.get_output_filename('tpl.out')
Simon Glass532ae702022-01-09 20:14:01 -07002445 ifwitool = bintool.Bintool.create('ifwitool')
2446 ifwitool.extract(image_fname, 'IBBP', 'IBBL', tpl_fname)
Simon Glassc5ac1382019-07-08 13:18:54 -06002447
Simon Glassc1aa66e2022-01-29 14:14:04 -07002448 tpl_data = tools.read_file(tpl_fname)
Simon Glasse95be632019-08-24 07:22:51 -06002449 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glassc5ac1382019-07-08 13:18:54 -06002450
2451 def testPackX86RomIfwi(self):
2452 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2453 self._SetupIfwi('fitimage.bin')
Simon Glass9255f3c2019-08-24 07:23:01 -06002454 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002455 self._CheckIfwi(data)
2456
2457 def testPackX86RomIfwiNoDesc(self):
2458 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2459 self._SetupIfwi('ifwi.bin')
Simon Glass9255f3c2019-08-24 07:23:01 -06002460 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002461 self._CheckIfwi(data)
2462
2463 def testPackX86RomIfwiNoData(self):
2464 """Test that an x86 ROM with IFWI handles missing data"""
2465 self._SetupIfwi('ifwi.bin')
2466 with self.assertRaises(ValueError) as e:
Simon Glass9255f3c2019-08-24 07:23:01 -06002467 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002468 self.assertIn('Could not complete processing of contents',
2469 str(e.exception))
Simon Glass53af22a2018-07-17 13:25:32 -06002470
Simon Glass4f9ee832022-01-09 20:14:09 -07002471 def testIfwiMissing(self):
2472 """Test that binman still produces an image if ifwitool is missing"""
2473 self._SetupIfwi('fitimage.bin')
2474 with test_util.capture_sys_output() as (_, stderr):
2475 self._DoTestFile('111_x86_rom_ifwi.dts',
2476 force_missing_bintools='ifwitool')
2477 err = stderr.getvalue()
2478 self.assertRegex(err,
Simon Glass193d3db2023-02-07 14:34:18 -07002479 "Image 'image'.*missing bintools.*: ifwitool")
Simon Glass4f9ee832022-01-09 20:14:09 -07002480
Simon Glasse073d4e2019-07-08 13:18:56 -06002481 def testCbfsOffset(self):
2482 """Test a CBFS with files at particular offsets
2483
2484 Like all CFBS tests, this is just checking the logic that calls
2485 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2486 """
2487 data = self._DoReadFile('114_cbfs_offset.dts')
2488 size = 0x200
2489
2490 cbfs = cbfs_util.CbfsReader(data)
2491 self.assertEqual(size, cbfs.rom_size)
2492
2493 self.assertIn('u-boot', cbfs.files)
2494 cfile = cbfs.files['u-boot']
2495 self.assertEqual(U_BOOT_DATA, cfile.data)
2496 self.assertEqual(0x40, cfile.cbfs_offset)
2497
2498 self.assertIn('u-boot-dtb', cbfs.files)
2499 cfile2 = cbfs.files['u-boot-dtb']
2500 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2501 self.assertEqual(0x140, cfile2.cbfs_offset)
2502
Simon Glass086cec92019-07-08 14:25:27 -06002503 def testFdtmap(self):
2504 """Test an FDT map can be inserted in the image"""
2505 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2506 fdtmap_data = data[len(U_BOOT_DATA):]
2507 magic = fdtmap_data[:8]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002508 self.assertEqual(b'_FDTMAP_', magic)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002509 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass086cec92019-07-08 14:25:27 -06002510
2511 fdt_data = fdtmap_data[16:]
2512 dtb = fdt.Fdt.FromData(fdt_data)
2513 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002514 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass086cec92019-07-08 14:25:27 -06002515 self.assertEqual({
2516 'image-pos': 0,
2517 'offset': 0,
2518 'u-boot:offset': 0,
2519 'u-boot:size': len(U_BOOT_DATA),
2520 'u-boot:image-pos': 0,
2521 'fdtmap:image-pos': 4,
2522 'fdtmap:offset': 4,
2523 'fdtmap:size': len(fdtmap_data),
2524 'size': len(data),
2525 }, props)
2526
2527 def testFdtmapNoMatch(self):
2528 """Check handling of an FDT map when the section cannot be found"""
2529 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2530
2531 # Mangle the section name, which should cause a mismatch between the
2532 # correct FDT path and the one expected by the section
2533 image = control.images['image']
Simon Glasscf228942019-07-08 14:25:28 -06002534 image._node.path += '-suffix'
Simon Glass086cec92019-07-08 14:25:27 -06002535 entries = image.GetEntries()
2536 fdtmap = entries['fdtmap']
2537 with self.assertRaises(ValueError) as e:
2538 fdtmap._GetFdtmap()
2539 self.assertIn("Cannot locate node for path '/binman-suffix'",
2540 str(e.exception))
2541
Simon Glasscf228942019-07-08 14:25:28 -06002542 def testFdtmapHeader(self):
2543 """Test an FDT map and image header can be inserted in the image"""
2544 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2545 fdtmap_pos = len(U_BOOT_DATA)
2546 fdtmap_data = data[fdtmap_pos:]
2547 fdt_data = fdtmap_data[16:]
2548 dtb = fdt.Fdt.FromData(fdt_data)
2549 fdt_size = dtb.GetFdtObj().totalsize()
2550 hdr_data = data[-8:]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002551 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002552 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2553 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2554
2555 def testFdtmapHeaderStart(self):
2556 """Test an image header can be inserted at the image start"""
2557 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2558 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2559 hdr_data = data[:8]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002560 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002561 offset = struct.unpack('<I', hdr_data[4:])[0]
2562 self.assertEqual(fdtmap_pos, offset)
2563
2564 def testFdtmapHeaderPos(self):
2565 """Test an image header can be inserted at a chosen position"""
2566 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2567 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2568 hdr_data = data[0x80:0x88]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002569 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002570 offset = struct.unpack('<I', hdr_data[4:])[0]
2571 self.assertEqual(fdtmap_pos, offset)
2572
2573 def testHeaderMissingFdtmap(self):
2574 """Test an image header requires an fdtmap"""
2575 with self.assertRaises(ValueError) as e:
2576 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2577 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2578 str(e.exception))
2579
2580 def testHeaderNoLocation(self):
2581 """Test an image header with a no specified location is detected"""
2582 with self.assertRaises(ValueError) as e:
2583 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2584 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2585 str(e.exception))
2586
Simon Glassc52c9e72019-07-08 14:25:37 -06002587 def testEntryExpand(self):
Simon Glass80a66ae2022-03-05 20:18:59 -07002588 """Test extending an entry after it is packed"""
2589 data = self._DoReadFile('121_entry_extend.dts')
Simon Glass79d3c582019-07-20 12:23:57 -06002590 self.assertEqual(b'aaa', data[:3])
2591 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2592 self.assertEqual(b'aaa', data[-3:])
Simon Glassc52c9e72019-07-08 14:25:37 -06002593
Simon Glass80a66ae2022-03-05 20:18:59 -07002594 def testEntryExtendBad(self):
2595 """Test extending an entry after it is packed, twice"""
Simon Glassc52c9e72019-07-08 14:25:37 -06002596 with self.assertRaises(ValueError) as e:
Simon Glass80a66ae2022-03-05 20:18:59 -07002597 self._DoReadFile('122_entry_extend_twice.dts')
Simon Glass61ec04f2019-07-20 12:23:58 -06002598 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glassc52c9e72019-07-08 14:25:37 -06002599 str(e.exception))
2600
Simon Glass80a66ae2022-03-05 20:18:59 -07002601 def testEntryExtendSection(self):
2602 """Test extending an entry within a section after it is packed"""
2603 data = self._DoReadFile('123_entry_extend_section.dts')
Simon Glass79d3c582019-07-20 12:23:57 -06002604 self.assertEqual(b'aaa', data[:3])
2605 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2606 self.assertEqual(b'aaa', data[-3:])
Simon Glassc52c9e72019-07-08 14:25:37 -06002607
Simon Glass6c223fd2019-07-08 14:25:38 -06002608 def testCompressDtb(self):
2609 """Test that compress of device-tree files is supported"""
2610 self._CheckLz4()
2611 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2612 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2613 comp_data = data[len(U_BOOT_DATA):]
2614 orig = self._decompress(comp_data)
2615 dtb = fdt.Fdt.FromData(orig)
2616 dtb.Scan()
2617 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2618 expected = {
2619 'u-boot:size': len(U_BOOT_DATA),
2620 'u-boot-dtb:uncomp-size': len(orig),
2621 'u-boot-dtb:size': len(comp_data),
2622 'size': len(data),
2623 }
2624 self.assertEqual(expected, props)
2625
Simon Glass69f7cb32019-07-08 14:25:41 -06002626 def testCbfsUpdateFdt(self):
2627 """Test that we can update the device tree with CBFS offset/size info"""
2628 self._CheckLz4()
2629 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2630 update_dtb=True)
2631 dtb = fdt.Fdt(out_dtb_fname)
2632 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002633 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass69f7cb32019-07-08 14:25:41 -06002634 del props['cbfs/u-boot:size']
2635 self.assertEqual({
2636 'offset': 0,
2637 'size': len(data),
2638 'image-pos': 0,
2639 'cbfs:offset': 0,
2640 'cbfs:size': len(data),
2641 'cbfs:image-pos': 0,
2642 'cbfs/u-boot:offset': 0x38,
2643 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2644 'cbfs/u-boot:image-pos': 0x38,
2645 'cbfs/u-boot-dtb:offset': 0xb8,
2646 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2647 'cbfs/u-boot-dtb:image-pos': 0xb8,
2648 }, props)
2649
Simon Glass8a1ad062019-07-08 14:25:42 -06002650 def testCbfsBadType(self):
2651 """Test an image header with a no specified location is detected"""
2652 with self.assertRaises(ValueError) as e:
2653 self._DoReadFile('126_cbfs_bad_type.dts')
2654 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2655
Simon Glass41b8ba02019-07-08 14:25:43 -06002656 def testList(self):
2657 """Test listing the files in an image"""
2658 self._CheckLz4()
2659 data = self._DoReadFile('127_list.dts')
2660 image = control.images['image']
2661 entries = image.BuildEntryList()
2662 self.assertEqual(7, len(entries))
2663
2664 ent = entries[0]
2665 self.assertEqual(0, ent.indent)
Simon Glass193d3db2023-02-07 14:34:18 -07002666 self.assertEqual('image', ent.name)
Simon Glass41b8ba02019-07-08 14:25:43 -06002667 self.assertEqual('section', ent.etype)
2668 self.assertEqual(len(data), ent.size)
2669 self.assertEqual(0, ent.image_pos)
2670 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002671 self.assertEqual(0, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002672
2673 ent = entries[1]
2674 self.assertEqual(1, ent.indent)
2675 self.assertEqual('u-boot', ent.name)
2676 self.assertEqual('u-boot', ent.etype)
2677 self.assertEqual(len(U_BOOT_DATA), ent.size)
2678 self.assertEqual(0, ent.image_pos)
2679 self.assertEqual(None, ent.uncomp_size)
2680 self.assertEqual(0, ent.offset)
2681
2682 ent = entries[2]
2683 self.assertEqual(1, ent.indent)
2684 self.assertEqual('section', ent.name)
2685 self.assertEqual('section', ent.etype)
2686 section_size = ent.size
2687 self.assertEqual(0x100, ent.image_pos)
2688 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002689 self.assertEqual(0x100, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002690
2691 ent = entries[3]
2692 self.assertEqual(2, ent.indent)
2693 self.assertEqual('cbfs', ent.name)
2694 self.assertEqual('cbfs', ent.etype)
2695 self.assertEqual(0x400, ent.size)
2696 self.assertEqual(0x100, ent.image_pos)
2697 self.assertEqual(None, ent.uncomp_size)
2698 self.assertEqual(0, ent.offset)
2699
2700 ent = entries[4]
2701 self.assertEqual(3, ent.indent)
2702 self.assertEqual('u-boot', ent.name)
2703 self.assertEqual('u-boot', ent.etype)
2704 self.assertEqual(len(U_BOOT_DATA), ent.size)
2705 self.assertEqual(0x138, ent.image_pos)
2706 self.assertEqual(None, ent.uncomp_size)
2707 self.assertEqual(0x38, ent.offset)
2708
2709 ent = entries[5]
2710 self.assertEqual(3, ent.indent)
2711 self.assertEqual('u-boot-dtb', ent.name)
2712 self.assertEqual('text', ent.etype)
2713 self.assertGreater(len(COMPRESS_DATA), ent.size)
2714 self.assertEqual(0x178, ent.image_pos)
2715 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2716 self.assertEqual(0x78, ent.offset)
2717
2718 ent = entries[6]
2719 self.assertEqual(2, ent.indent)
2720 self.assertEqual('u-boot-dtb', ent.name)
2721 self.assertEqual('u-boot-dtb', ent.etype)
2722 self.assertEqual(0x500, ent.image_pos)
2723 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2724 dtb_size = ent.size
2725 # Compressing this data expands it since headers are added
2726 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2727 self.assertEqual(0x400, ent.offset)
2728
2729 self.assertEqual(len(data), 0x100 + section_size)
2730 self.assertEqual(section_size, 0x400 + dtb_size)
2731
Simon Glasse1925fa2019-07-08 14:25:44 -06002732 def testFindFdtmap(self):
2733 """Test locating an FDT map in an image"""
2734 self._CheckLz4()
2735 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2736 image = control.images['image']
2737 entries = image.GetEntries()
2738 entry = entries['fdtmap']
2739 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2740
2741 def testFindFdtmapMissing(self):
2742 """Test failing to locate an FDP map"""
2743 data = self._DoReadFile('005_simple.dts')
2744 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2745
Simon Glass2d260032019-07-08 14:25:45 -06002746 def testFindImageHeader(self):
2747 """Test locating a image header"""
2748 self._CheckLz4()
Simon Glassffded752019-07-08 14:25:46 -06002749 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002750 image = control.images['image']
2751 entries = image.GetEntries()
2752 entry = entries['fdtmap']
2753 # The header should point to the FDT map
2754 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2755
2756 def testFindImageHeaderStart(self):
2757 """Test locating a image header located at the start of an image"""
Simon Glassffded752019-07-08 14:25:46 -06002758 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002759 image = control.images['image']
2760 entries = image.GetEntries()
2761 entry = entries['fdtmap']
2762 # The header should point to the FDT map
2763 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2764
2765 def testFindImageHeaderMissing(self):
2766 """Test failing to locate an image header"""
2767 data = self._DoReadFile('005_simple.dts')
2768 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2769
Simon Glassffded752019-07-08 14:25:46 -06002770 def testReadImage(self):
2771 """Test reading an image and accessing its FDT map"""
2772 self._CheckLz4()
2773 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002774 image_fname = tools.get_output_filename('image.bin')
Simon Glassffded752019-07-08 14:25:46 -06002775 orig_image = control.images['image']
2776 image = Image.FromFile(image_fname)
2777 self.assertEqual(orig_image.GetEntries().keys(),
2778 image.GetEntries().keys())
2779
2780 orig_entry = orig_image.GetEntries()['fdtmap']
2781 entry = image.GetEntries()['fdtmap']
2782 self.assertEquals(orig_entry.offset, entry.offset)
2783 self.assertEquals(orig_entry.size, entry.size)
2784 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2785
2786 def testReadImageNoHeader(self):
2787 """Test accessing an image's FDT map without an image header"""
2788 self._CheckLz4()
2789 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002790 image_fname = tools.get_output_filename('image.bin')
Simon Glassffded752019-07-08 14:25:46 -06002791 image = Image.FromFile(image_fname)
2792 self.assertTrue(isinstance(image, Image))
Simon Glass10f9d002019-07-20 12:23:50 -06002793 self.assertEqual('image', image.image_name[-5:])
Simon Glassffded752019-07-08 14:25:46 -06002794
2795 def testReadImageFail(self):
2796 """Test failing to read an image image's FDT map"""
2797 self._DoReadFile('005_simple.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002798 image_fname = tools.get_output_filename('image.bin')
Simon Glassffded752019-07-08 14:25:46 -06002799 with self.assertRaises(ValueError) as e:
2800 image = Image.FromFile(image_fname)
2801 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glasse073d4e2019-07-08 13:18:56 -06002802
Simon Glass61f564d2019-07-08 14:25:48 -06002803 def testListCmd(self):
2804 """Test listing the files in an image using an Fdtmap"""
2805 self._CheckLz4()
2806 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2807
2808 # lz4 compression size differs depending on the version
2809 image = control.images['image']
2810 entries = image.GetEntries()
2811 section_size = entries['section'].size
2812 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2813 fdtmap_offset = entries['fdtmap'].offset
2814
Simon Glassf86a7362019-07-20 12:24:10 -06002815 try:
2816 tmpdir, updated_fname = self._SetupImageInTmpdir()
2817 with test_util.capture_sys_output() as (stdout, stderr):
2818 self._DoBinman('ls', '-i', updated_fname)
2819 finally:
2820 shutil.rmtree(tmpdir)
Simon Glass61f564d2019-07-08 14:25:48 -06002821 lines = stdout.getvalue().splitlines()
2822 expected = [
2823'Name Image-pos Size Entry-type Offset Uncomp-size',
2824'----------------------------------------------------------------------',
Simon Glass193d3db2023-02-07 14:34:18 -07002825'image 0 c00 section 0',
Simon Glass61f564d2019-07-08 14:25:48 -06002826' u-boot 0 4 u-boot 0',
2827' section 100 %x section 100' % section_size,
2828' cbfs 100 400 cbfs 0',
2829' u-boot 138 4 u-boot 38',
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002830' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glass61f564d2019-07-08 14:25:48 -06002831' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002832' fdtmap %x 3bd fdtmap %x' %
Simon Glass61f564d2019-07-08 14:25:48 -06002833 (fdtmap_offset, fdtmap_offset),
2834' image-header bf8 8 image-header bf8',
2835 ]
2836 self.assertEqual(expected, lines)
2837
2838 def testListCmdFail(self):
2839 """Test failing to list an image"""
2840 self._DoReadFile('005_simple.dts')
Simon Glassf86a7362019-07-20 12:24:10 -06002841 try:
2842 tmpdir, updated_fname = self._SetupImageInTmpdir()
2843 with self.assertRaises(ValueError) as e:
2844 self._DoBinman('ls', '-i', updated_fname)
2845 finally:
2846 shutil.rmtree(tmpdir)
Simon Glass61f564d2019-07-08 14:25:48 -06002847 self.assertIn("Cannot find FDT map in image", str(e.exception))
2848
2849 def _RunListCmd(self, paths, expected):
2850 """List out entries and check the result
2851
2852 Args:
2853 paths: List of paths to pass to the list command
2854 expected: Expected list of filenames to be returned, in order
2855 """
2856 self._CheckLz4()
2857 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002858 image_fname = tools.get_output_filename('image.bin')
Simon Glass61f564d2019-07-08 14:25:48 -06002859 image = Image.FromFile(image_fname)
2860 lines = image.GetListEntries(paths)[1]
2861 files = [line[0].strip() for line in lines[1:]]
2862 self.assertEqual(expected, files)
2863
2864 def testListCmdSection(self):
2865 """Test listing the files in a section"""
2866 self._RunListCmd(['section'],
2867 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2868
2869 def testListCmdFile(self):
2870 """Test listing a particular file"""
2871 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2872
2873 def testListCmdWildcard(self):
2874 """Test listing a wildcarded file"""
2875 self._RunListCmd(['*boot*'],
2876 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2877
2878 def testListCmdWildcardMulti(self):
2879 """Test listing a wildcarded file"""
2880 self._RunListCmd(['*cb*', '*head*'],
2881 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2882
2883 def testListCmdEmpty(self):
2884 """Test listing a wildcarded file"""
2885 self._RunListCmd(['nothing'], [])
2886
2887 def testListCmdPath(self):
2888 """Test listing the files in a sub-entry of a section"""
2889 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2890
Simon Glassf667e452019-07-08 14:25:50 -06002891 def _RunExtractCmd(self, entry_name, decomp=True):
2892 """Extract an entry from an image
2893
2894 Args:
2895 entry_name: Entry name to extract
2896 decomp: True to decompress the data if compressed, False to leave
2897 it in its raw uncompressed format
2898
2899 Returns:
2900 data from entry
2901 """
2902 self._CheckLz4()
2903 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002904 image_fname = tools.get_output_filename('image.bin')
Simon Glassf667e452019-07-08 14:25:50 -06002905 return control.ReadEntry(image_fname, entry_name, decomp)
2906
2907 def testExtractSimple(self):
2908 """Test extracting a single file"""
2909 data = self._RunExtractCmd('u-boot')
2910 self.assertEqual(U_BOOT_DATA, data)
2911
Simon Glass71ce0ba2019-07-08 14:25:52 -06002912 def testExtractSection(self):
2913 """Test extracting the files in a section"""
2914 data = self._RunExtractCmd('section')
2915 cbfs_data = data[:0x400]
2916 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002917 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass71ce0ba2019-07-08 14:25:52 -06002918 dtb_data = data[0x400:]
2919 dtb = self._decompress(dtb_data)
2920 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2921
2922 def testExtractCompressed(self):
2923 """Test extracting compressed data"""
2924 data = self._RunExtractCmd('section/u-boot-dtb')
2925 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2926
2927 def testExtractRaw(self):
2928 """Test extracting compressed data without decompressing it"""
2929 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2930 dtb = self._decompress(data)
2931 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2932
2933 def testExtractCbfs(self):
2934 """Test extracting CBFS data"""
2935 data = self._RunExtractCmd('section/cbfs/u-boot')
2936 self.assertEqual(U_BOOT_DATA, data)
2937
2938 def testExtractCbfsCompressed(self):
2939 """Test extracting CBFS compressed data"""
2940 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2941 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2942
2943 def testExtractCbfsRaw(self):
2944 """Test extracting CBFS compressed data without decompressing it"""
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +02002945 bintool = self.comp_bintools['lzma_alone']
2946 self._CheckBintool(bintool)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002947 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +02002948 dtb = bintool.decompress(data)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002949 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2950
Simon Glassf667e452019-07-08 14:25:50 -06002951 def testExtractBadEntry(self):
2952 """Test extracting a bad section path"""
2953 with self.assertRaises(ValueError) as e:
2954 self._RunExtractCmd('section/does-not-exist')
2955 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2956 str(e.exception))
2957
2958 def testExtractMissingFile(self):
2959 """Test extracting file that does not exist"""
2960 with self.assertRaises(IOError) as e:
2961 control.ReadEntry('missing-file', 'name')
2962
2963 def testExtractBadFile(self):
2964 """Test extracting an invalid file"""
2965 fname = os.path.join(self._indir, 'badfile')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002966 tools.write_file(fname, b'')
Simon Glassf667e452019-07-08 14:25:50 -06002967 with self.assertRaises(ValueError) as e:
2968 control.ReadEntry(fname, 'name')
2969
Simon Glass71ce0ba2019-07-08 14:25:52 -06002970 def testExtractCmd(self):
2971 """Test extracting a file fron an image on the command line"""
2972 self._CheckLz4()
2973 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass71ce0ba2019-07-08 14:25:52 -06002974 fname = os.path.join(self._indir, 'output.extact')
Simon Glassf86a7362019-07-20 12:24:10 -06002975 try:
2976 tmpdir, updated_fname = self._SetupImageInTmpdir()
2977 with test_util.capture_sys_output() as (stdout, stderr):
2978 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2979 '-f', fname)
2980 finally:
2981 shutil.rmtree(tmpdir)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002982 data = tools.read_file(fname)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002983 self.assertEqual(U_BOOT_DATA, data)
2984
2985 def testExtractOneEntry(self):
2986 """Test extracting a single entry fron an image """
2987 self._CheckLz4()
2988 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002989 image_fname = tools.get_output_filename('image.bin')
Simon Glass71ce0ba2019-07-08 14:25:52 -06002990 fname = os.path.join(self._indir, 'output.extact')
2991 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
Simon Glassc1aa66e2022-01-29 14:14:04 -07002992 data = tools.read_file(fname)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002993 self.assertEqual(U_BOOT_DATA, data)
2994
2995 def _CheckExtractOutput(self, decomp):
2996 """Helper to test file output with and without decompression
2997
2998 Args:
2999 decomp: True to decompress entry data, False to output it raw
3000 """
3001 def _CheckPresent(entry_path, expect_data, expect_size=None):
3002 """Check and remove expected file
3003
3004 This checks the data/size of a file and removes the file both from
3005 the outfiles set and from the output directory. Once all files are
3006 processed, both the set and directory should be empty.
3007
3008 Args:
3009 entry_path: Entry path
3010 expect_data: Data to expect in file, or None to skip check
3011 expect_size: Size of data to expect in file, or None to skip
3012 """
3013 path = os.path.join(outdir, entry_path)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003014 data = tools.read_file(path)
Simon Glass71ce0ba2019-07-08 14:25:52 -06003015 os.remove(path)
3016 if expect_data:
3017 self.assertEqual(expect_data, data)
3018 elif expect_size:
3019 self.assertEqual(expect_size, len(data))
3020 outfiles.remove(path)
3021
3022 def _CheckDirPresent(name):
3023 """Remove expected directory
3024
3025 This gives an error if the directory does not exist as expected
3026
3027 Args:
3028 name: Name of directory to remove
3029 """
3030 path = os.path.join(outdir, name)
3031 os.rmdir(path)
3032
3033 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003034 image_fname = tools.get_output_filename('image.bin')
Simon Glass71ce0ba2019-07-08 14:25:52 -06003035 outdir = os.path.join(self._indir, 'extract')
3036 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
3037
3038 # Create a set of all file that were output (should be 9)
3039 outfiles = set()
3040 for root, dirs, files in os.walk(outdir):
3041 outfiles |= set([os.path.join(root, fname) for fname in files])
3042 self.assertEqual(9, len(outfiles))
3043 self.assertEqual(9, len(einfos))
3044
3045 image = control.images['image']
3046 entries = image.GetEntries()
3047
3048 # Check the 9 files in various ways
3049 section = entries['section']
3050 section_entries = section.GetEntries()
3051 cbfs_entries = section_entries['cbfs'].GetEntries()
3052 _CheckPresent('u-boot', U_BOOT_DATA)
3053 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
3054 dtb_len = EXTRACT_DTB_SIZE
3055 if not decomp:
3056 dtb_len = cbfs_entries['u-boot-dtb'].size
3057 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
3058 if not decomp:
3059 dtb_len = section_entries['u-boot-dtb'].size
3060 _CheckPresent('section/u-boot-dtb', None, dtb_len)
3061
3062 fdtmap = entries['fdtmap']
3063 _CheckPresent('fdtmap', fdtmap.data)
3064 hdr = entries['image-header']
3065 _CheckPresent('image-header', hdr.data)
3066
3067 _CheckPresent('section/root', section.data)
3068 cbfs = section_entries['cbfs']
3069 _CheckPresent('section/cbfs/root', cbfs.data)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003070 data = tools.read_file(image_fname)
Simon Glass71ce0ba2019-07-08 14:25:52 -06003071 _CheckPresent('root', data)
3072
3073 # There should be no files left. Remove all the directories to check.
3074 # If there are any files/dirs remaining, one of these checks will fail.
3075 self.assertEqual(0, len(outfiles))
3076 _CheckDirPresent('section/cbfs')
3077 _CheckDirPresent('section')
3078 _CheckDirPresent('')
3079 self.assertFalse(os.path.exists(outdir))
3080
3081 def testExtractAllEntries(self):
3082 """Test extracting all entries"""
3083 self._CheckLz4()
3084 self._CheckExtractOutput(decomp=True)
3085
3086 def testExtractAllEntriesRaw(self):
3087 """Test extracting all entries without decompressing them"""
3088 self._CheckLz4()
3089 self._CheckExtractOutput(decomp=False)
3090
3091 def testExtractSelectedEntries(self):
3092 """Test extracting some entries"""
3093 self._CheckLz4()
3094 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003095 image_fname = tools.get_output_filename('image.bin')
Simon Glass71ce0ba2019-07-08 14:25:52 -06003096 outdir = os.path.join(self._indir, 'extract')
3097 einfos = control.ExtractEntries(image_fname, None, outdir,
3098 ['*cb*', '*head*'])
3099
3100 # File output is tested by testExtractAllEntries(), so just check that
3101 # the expected entries are selected
3102 names = [einfo.name for einfo in einfos]
3103 self.assertEqual(names,
3104 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
3105
3106 def testExtractNoEntryPaths(self):
3107 """Test extracting some entries"""
3108 self._CheckLz4()
3109 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003110 image_fname = tools.get_output_filename('image.bin')
Simon Glass71ce0ba2019-07-08 14:25:52 -06003111 with self.assertRaises(ValueError) as e:
3112 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassbb5edc12019-07-20 12:24:14 -06003113 self.assertIn('Must specify an entry path to write with -f',
Simon Glass71ce0ba2019-07-08 14:25:52 -06003114 str(e.exception))
3115
3116 def testExtractTooManyEntryPaths(self):
3117 """Test extracting some entries"""
3118 self._CheckLz4()
3119 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003120 image_fname = tools.get_output_filename('image.bin')
Simon Glass71ce0ba2019-07-08 14:25:52 -06003121 with self.assertRaises(ValueError) as e:
3122 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassbb5edc12019-07-20 12:24:14 -06003123 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass71ce0ba2019-07-08 14:25:52 -06003124 str(e.exception))
3125
Simon Glasse2705fa2019-07-08 14:25:53 -06003126 def testPackAlignSection(self):
3127 """Test that sections can have alignment"""
3128 self._DoReadFile('131_pack_align_section.dts')
3129
3130 self.assertIn('image', control.images)
3131 image = control.images['image']
3132 entries = image.GetEntries()
3133 self.assertEqual(3, len(entries))
3134
3135 # First u-boot
3136 self.assertIn('u-boot', entries)
3137 entry = entries['u-boot']
3138 self.assertEqual(0, entry.offset)
3139 self.assertEqual(0, entry.image_pos)
3140 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3141 self.assertEqual(len(U_BOOT_DATA), entry.size)
3142
3143 # Section0
3144 self.assertIn('section0', entries)
3145 section0 = entries['section0']
3146 self.assertEqual(0x10, section0.offset)
3147 self.assertEqual(0x10, section0.image_pos)
3148 self.assertEqual(len(U_BOOT_DATA), section0.size)
3149
3150 # Second u-boot
3151 section_entries = section0.GetEntries()
3152 self.assertIn('u-boot', section_entries)
3153 entry = section_entries['u-boot']
3154 self.assertEqual(0, entry.offset)
3155 self.assertEqual(0x10, entry.image_pos)
3156 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3157 self.assertEqual(len(U_BOOT_DATA), entry.size)
3158
3159 # Section1
3160 self.assertIn('section1', entries)
3161 section1 = entries['section1']
3162 self.assertEqual(0x14, section1.offset)
3163 self.assertEqual(0x14, section1.image_pos)
3164 self.assertEqual(0x20, section1.size)
3165
3166 # Second u-boot
3167 section_entries = section1.GetEntries()
3168 self.assertIn('u-boot', section_entries)
3169 entry = section_entries['u-boot']
3170 self.assertEqual(0, entry.offset)
3171 self.assertEqual(0x14, entry.image_pos)
3172 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3173 self.assertEqual(len(U_BOOT_DATA), entry.size)
3174
3175 # Section2
3176 self.assertIn('section2', section_entries)
3177 section2 = section_entries['section2']
3178 self.assertEqual(0x4, section2.offset)
3179 self.assertEqual(0x18, section2.image_pos)
3180 self.assertEqual(4, section2.size)
3181
3182 # Third u-boot
3183 section_entries = section2.GetEntries()
3184 self.assertIn('u-boot', section_entries)
3185 entry = section_entries['u-boot']
3186 self.assertEqual(0, entry.offset)
3187 self.assertEqual(0x18, entry.image_pos)
3188 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3189 self.assertEqual(len(U_BOOT_DATA), entry.size)
3190
Simon Glass51014aa2019-07-20 12:23:56 -06003191 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3192 dts='132_replace.dts'):
Simon Glass10f9d002019-07-20 12:23:50 -06003193 """Replace an entry in an image
3194
3195 This writes the entry data to update it, then opens the updated file and
3196 returns the value that it now finds there.
3197
3198 Args:
3199 entry_name: Entry name to replace
3200 data: Data to replace it with
3201 decomp: True to compress the data if needed, False if data is
3202 already compressed so should be used as is
Simon Glass51014aa2019-07-20 12:23:56 -06003203 allow_resize: True to allow entries to change size, False to raise
3204 an exception
Simon Glass10f9d002019-07-20 12:23:50 -06003205
3206 Returns:
3207 Tuple:
3208 data from entry
3209 data from fdtmap (excluding header)
Simon Glass51014aa2019-07-20 12:23:56 -06003210 Image object that was modified
Simon Glass10f9d002019-07-20 12:23:50 -06003211 """
Simon Glass51014aa2019-07-20 12:23:56 -06003212 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass10f9d002019-07-20 12:23:50 -06003213 update_dtb=True)[1]
3214
3215 self.assertIn('image', control.images)
3216 image = control.images['image']
3217 entries = image.GetEntries()
3218 orig_dtb_data = entries['u-boot-dtb'].data
3219 orig_fdtmap_data = entries['fdtmap'].data
3220
Simon Glassc1aa66e2022-01-29 14:14:04 -07003221 image_fname = tools.get_output_filename('image.bin')
3222 updated_fname = tools.get_output_filename('image-updated.bin')
3223 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glass51014aa2019-07-20 12:23:56 -06003224 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3225 allow_resize)
Simon Glass10f9d002019-07-20 12:23:50 -06003226 data = control.ReadEntry(updated_fname, entry_name, decomp)
3227
Simon Glass51014aa2019-07-20 12:23:56 -06003228 # The DT data should not change unless resized:
3229 if not allow_resize:
3230 new_dtb_data = entries['u-boot-dtb'].data
3231 self.assertEqual(new_dtb_data, orig_dtb_data)
3232 new_fdtmap_data = entries['fdtmap'].data
3233 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass10f9d002019-07-20 12:23:50 -06003234
Simon Glass51014aa2019-07-20 12:23:56 -06003235 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass10f9d002019-07-20 12:23:50 -06003236
3237 def testReplaceSimple(self):
3238 """Test replacing a single file"""
3239 expected = b'x' * len(U_BOOT_DATA)
Simon Glass51014aa2019-07-20 12:23:56 -06003240 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3241 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06003242 self.assertEqual(expected, data)
3243
3244 # Test that the state looks right. There should be an FDT for the fdtmap
3245 # that we jsut read back in, and it should match what we find in the
3246 # 'control' tables. Checking for an FDT that does not exist should
3247 # return None.
3248 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glass51014aa2019-07-20 12:23:56 -06003249 self.assertIsNotNone(path)
Simon Glass10f9d002019-07-20 12:23:50 -06003250 self.assertEqual(expected_fdtmap, fdtmap)
3251
3252 dtb = state.GetFdtForEtype('fdtmap')
3253 self.assertEqual(dtb.GetContents(), fdtmap)
3254
3255 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3256 self.assertIsNone(missing_path)
3257 self.assertIsNone(missing_fdtmap)
3258
3259 missing_dtb = state.GetFdtForEtype('missing')
3260 self.assertIsNone(missing_dtb)
3261
3262 self.assertEqual('/binman', state.fdt_path_prefix)
3263
3264 def testReplaceResizeFail(self):
3265 """Test replacing a file by something larger"""
3266 expected = U_BOOT_DATA + b'x'
3267 with self.assertRaises(ValueError) as e:
Simon Glass51014aa2019-07-20 12:23:56 -06003268 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3269 dts='139_replace_repack.dts')
Simon Glass10f9d002019-07-20 12:23:50 -06003270 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3271 str(e.exception))
3272
3273 def testReplaceMulti(self):
3274 """Test replacing entry data where multiple images are generated"""
3275 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3276 update_dtb=True)[0]
3277 expected = b'x' * len(U_BOOT_DATA)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003278 updated_fname = tools.get_output_filename('image-updated.bin')
3279 tools.write_file(updated_fname, data)
Simon Glass10f9d002019-07-20 12:23:50 -06003280 entry_name = 'u-boot'
Simon Glass51014aa2019-07-20 12:23:56 -06003281 control.WriteEntry(updated_fname, entry_name, expected,
3282 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06003283 data = control.ReadEntry(updated_fname, entry_name)
3284 self.assertEqual(expected, data)
3285
3286 # Check the state looks right.
3287 self.assertEqual('/binman/image', state.fdt_path_prefix)
3288
3289 # Now check we can write the first image
Simon Glassc1aa66e2022-01-29 14:14:04 -07003290 image_fname = tools.get_output_filename('first-image.bin')
3291 updated_fname = tools.get_output_filename('first-updated.bin')
3292 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glass10f9d002019-07-20 12:23:50 -06003293 entry_name = 'u-boot'
Simon Glass51014aa2019-07-20 12:23:56 -06003294 control.WriteEntry(updated_fname, entry_name, expected,
3295 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06003296 data = control.ReadEntry(updated_fname, entry_name)
3297 self.assertEqual(expected, data)
3298
3299 # Check the state looks right.
3300 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass8beb11e2019-07-08 14:25:47 -06003301
Simon Glass12bb1a92019-07-20 12:23:51 -06003302 def testUpdateFdtAllRepack(self):
3303 """Test that all device trees are updated with offset/size info"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06003304 self._SetupSplElf()
3305 self._SetupTplElf()
Simon Glass12bb1a92019-07-20 12:23:51 -06003306 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3307 SECTION_SIZE = 0x300
3308 DTB_SIZE = 602
3309 FDTMAP_SIZE = 608
3310 base_expected = {
3311 'offset': 0,
3312 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3313 'image-pos': 0,
3314 'section:offset': 0,
3315 'section:size': SECTION_SIZE,
3316 'section:image-pos': 0,
3317 'section/u-boot-dtb:offset': 4,
3318 'section/u-boot-dtb:size': 636,
3319 'section/u-boot-dtb:image-pos': 4,
3320 'u-boot-spl-dtb:offset': SECTION_SIZE,
3321 'u-boot-spl-dtb:size': DTB_SIZE,
3322 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3323 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3324 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3325 'u-boot-tpl-dtb:size': DTB_SIZE,
3326 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3327 'fdtmap:size': FDTMAP_SIZE,
3328 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3329 }
3330 main_expected = {
3331 'section:orig-size': SECTION_SIZE,
3332 'section/u-boot-dtb:orig-offset': 4,
3333 }
3334
3335 # We expect three device-tree files in the output, with the first one
3336 # within a fixed-size section.
3337 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3338 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3339 # main U-Boot tree. All three should have the same positions and offset
3340 # except that the main tree should include the main_expected properties
3341 start = 4
3342 for item in ['', 'spl', 'tpl', None]:
3343 if item is None:
3344 start += 16 # Move past fdtmap header
3345 dtb = fdt.Fdt.FromData(data[start:])
3346 dtb.Scan()
3347 props = self._GetPropTree(dtb,
3348 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3349 prefix='/' if item is None else '/binman/')
3350 expected = dict(base_expected)
3351 if item:
3352 expected[item] = 0
3353 else:
3354 # Main DTB and fdtdec should include the 'orig-' properties
3355 expected.update(main_expected)
3356 # Helpful for debugging:
3357 #for prop in sorted(props):
3358 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3359 self.assertEqual(expected, props)
3360 if item == '':
3361 start = SECTION_SIZE
3362 else:
3363 start += dtb._fdt_obj.totalsize()
3364
Simon Glasseba1f0c2019-07-20 12:23:55 -06003365 def testFdtmapHeaderMiddle(self):
3366 """Test an FDT map in the middle of an image when it should be at end"""
3367 with self.assertRaises(ValueError) as e:
3368 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3369 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3370 str(e.exception))
3371
3372 def testFdtmapHeaderStartBad(self):
3373 """Test an FDT map in middle of an image when it should be at start"""
3374 with self.assertRaises(ValueError) as e:
3375 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3376 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3377 str(e.exception))
3378
3379 def testFdtmapHeaderEndBad(self):
3380 """Test an FDT map at the start of an image when it should be at end"""
3381 with self.assertRaises(ValueError) as e:
3382 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3383 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3384 str(e.exception))
3385
3386 def testFdtmapHeaderNoSize(self):
3387 """Test an image header at the end of an image with undefined size"""
3388 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3389
Simon Glass51014aa2019-07-20 12:23:56 -06003390 def testReplaceResize(self):
3391 """Test replacing a single file in an entry with a larger file"""
3392 expected = U_BOOT_DATA + b'x'
3393 data, _, image = self._RunReplaceCmd('u-boot', expected,
3394 dts='139_replace_repack.dts')
3395 self.assertEqual(expected, data)
3396
3397 entries = image.GetEntries()
3398 dtb_data = entries['u-boot-dtb'].data
3399 dtb = fdt.Fdt.FromData(dtb_data)
3400 dtb.Scan()
3401
3402 # The u-boot section should now be larger in the dtb
3403 node = dtb.GetNode('/binman/u-boot')
3404 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3405
3406 # Same for the fdtmap
3407 fdata = entries['fdtmap'].data
3408 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3409 fdtb.Scan()
3410 fnode = fdtb.GetNode('/u-boot')
3411 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3412
3413 def testReplaceResizeNoRepack(self):
3414 """Test replacing an entry with a larger file when not allowed"""
3415 expected = U_BOOT_DATA + b'x'
3416 with self.assertRaises(ValueError) as e:
3417 self._RunReplaceCmd('u-boot', expected)
3418 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3419 str(e.exception))
3420
Simon Glass61ec04f2019-07-20 12:23:58 -06003421 def testEntryShrink(self):
3422 """Test contracting an entry after it is packed"""
3423 try:
3424 state.SetAllowEntryContraction(True)
3425 data = self._DoReadFileDtb('140_entry_shrink.dts',
3426 update_dtb=True)[0]
3427 finally:
3428 state.SetAllowEntryContraction(False)
3429 self.assertEqual(b'a', data[:1])
3430 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3431 self.assertEqual(b'a', data[-1:])
3432
3433 def testEntryShrinkFail(self):
3434 """Test not being allowed to contract an entry after it is packed"""
3435 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3436
3437 # In this case there is a spare byte at the end of the data. The size of
3438 # the contents is only 1 byte but we still have the size before it
3439 # shrunk.
3440 self.assertEqual(b'a\0', data[:2])
3441 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3442 self.assertEqual(b'a\0', data[-2:])
3443
Simon Glass27145fd2019-07-20 12:24:01 -06003444 def testDescriptorOffset(self):
3445 """Test that the Intel descriptor is always placed at at the start"""
3446 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3447 image = control.images['image']
3448 entries = image.GetEntries()
3449 desc = entries['intel-descriptor']
3450 self.assertEqual(0xff800000, desc.offset);
3451 self.assertEqual(0xff800000, desc.image_pos);
3452
Simon Glasseb0f4a42019-07-20 12:24:06 -06003453 def testReplaceCbfs(self):
3454 """Test replacing a single file in CBFS without changing the size"""
3455 self._CheckLz4()
3456 expected = b'x' * len(U_BOOT_DATA)
3457 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003458 updated_fname = tools.get_output_filename('image-updated.bin')
3459 tools.write_file(updated_fname, data)
Simon Glasseb0f4a42019-07-20 12:24:06 -06003460 entry_name = 'section/cbfs/u-boot'
3461 control.WriteEntry(updated_fname, entry_name, expected,
3462 allow_resize=True)
3463 data = control.ReadEntry(updated_fname, entry_name)
3464 self.assertEqual(expected, data)
3465
3466 def testReplaceResizeCbfs(self):
3467 """Test replacing a single file in CBFS with one of a different size"""
3468 self._CheckLz4()
3469 expected = U_BOOT_DATA + b'x'
3470 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003471 updated_fname = tools.get_output_filename('image-updated.bin')
3472 tools.write_file(updated_fname, data)
Simon Glasseb0f4a42019-07-20 12:24:06 -06003473 entry_name = 'section/cbfs/u-boot'
3474 control.WriteEntry(updated_fname, entry_name, expected,
3475 allow_resize=True)
3476 data = control.ReadEntry(updated_fname, entry_name)
3477 self.assertEqual(expected, data)
3478
Simon Glassa6cb9952019-07-20 12:24:15 -06003479 def _SetupForReplace(self):
3480 """Set up some files to use to replace entries
3481
3482 This generates an image, copies it to a new file, extracts all the files
3483 in it and updates some of them
3484
3485 Returns:
3486 List
3487 Image filename
3488 Output directory
3489 Expected values for updated entries, each a string
3490 """
3491 data = self._DoReadFileRealDtb('143_replace_all.dts')
3492
Simon Glassc1aa66e2022-01-29 14:14:04 -07003493 updated_fname = tools.get_output_filename('image-updated.bin')
3494 tools.write_file(updated_fname, data)
Simon Glassa6cb9952019-07-20 12:24:15 -06003495
3496 outdir = os.path.join(self._indir, 'extract')
3497 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3498
3499 expected1 = b'x' + U_BOOT_DATA + b'y'
3500 u_boot_fname1 = os.path.join(outdir, 'u-boot')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003501 tools.write_file(u_boot_fname1, expected1)
Simon Glassa6cb9952019-07-20 12:24:15 -06003502
3503 expected2 = b'a' + U_BOOT_DATA + b'b'
3504 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003505 tools.write_file(u_boot_fname2, expected2)
Simon Glassa6cb9952019-07-20 12:24:15 -06003506
3507 expected_text = b'not the same text'
3508 text_fname = os.path.join(outdir, 'text')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003509 tools.write_file(text_fname, expected_text)
Simon Glassa6cb9952019-07-20 12:24:15 -06003510
3511 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3512 dtb = fdt.FdtScan(dtb_fname)
3513 node = dtb.GetNode('/binman/text')
3514 node.AddString('my-property', 'the value')
3515 dtb.Sync(auto_resize=True)
3516 dtb.Flush()
3517
3518 return updated_fname, outdir, expected1, expected2, expected_text
3519
3520 def _CheckReplaceMultiple(self, entry_paths):
3521 """Handle replacing the contents of multiple entries
3522
3523 Args:
3524 entry_paths: List of entry paths to replace
3525
3526 Returns:
3527 List
3528 Dict of entries in the image:
3529 key: Entry name
3530 Value: Entry object
3531 Expected values for updated entries, each a string
3532 """
3533 updated_fname, outdir, expected1, expected2, expected_text = (
3534 self._SetupForReplace())
3535 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3536
3537 image = Image.FromFile(updated_fname)
3538 image.LoadData()
3539 return image.GetEntries(), expected1, expected2, expected_text
3540
3541 def testReplaceAll(self):
3542 """Test replacing the contents of all entries"""
3543 entries, expected1, expected2, expected_text = (
3544 self._CheckReplaceMultiple([]))
3545 data = entries['u-boot'].data
3546 self.assertEqual(expected1, data)
3547
3548 data = entries['u-boot2'].data
3549 self.assertEqual(expected2, data)
3550
3551 data = entries['text'].data
3552 self.assertEqual(expected_text, data)
3553
3554 # Check that the device tree is updated
3555 data = entries['u-boot-dtb'].data
3556 dtb = fdt.Fdt.FromData(data)
3557 dtb.Scan()
3558 node = dtb.GetNode('/binman/text')
3559 self.assertEqual('the value', node.props['my-property'].value)
3560
3561 def testReplaceSome(self):
3562 """Test replacing the contents of a few entries"""
3563 entries, expected1, expected2, expected_text = (
3564 self._CheckReplaceMultiple(['u-boot2', 'text']))
3565
3566 # This one should not change
3567 data = entries['u-boot'].data
3568 self.assertEqual(U_BOOT_DATA, data)
3569
3570 data = entries['u-boot2'].data
3571 self.assertEqual(expected2, data)
3572
3573 data = entries['text'].data
3574 self.assertEqual(expected_text, data)
3575
3576 def testReplaceCmd(self):
3577 """Test replacing a file fron an image on the command line"""
3578 self._DoReadFileRealDtb('143_replace_all.dts')
3579
3580 try:
3581 tmpdir, updated_fname = self._SetupImageInTmpdir()
3582
3583 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3584 expected = b'x' * len(U_BOOT_DATA)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003585 tools.write_file(fname, expected)
Simon Glassa6cb9952019-07-20 12:24:15 -06003586
3587 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003588 data = tools.read_file(updated_fname)
Simon Glassa6cb9952019-07-20 12:24:15 -06003589 self.assertEqual(expected, data[:len(expected)])
3590 map_fname = os.path.join(tmpdir, 'image-updated.map')
3591 self.assertFalse(os.path.exists(map_fname))
3592 finally:
3593 shutil.rmtree(tmpdir)
3594
3595 def testReplaceCmdSome(self):
3596 """Test replacing some files fron an image on the command line"""
3597 updated_fname, outdir, expected1, expected2, expected_text = (
3598 self._SetupForReplace())
3599
3600 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3601 'u-boot2', 'text')
3602
Simon Glassc1aa66e2022-01-29 14:14:04 -07003603 tools.prepare_output_dir(None)
Simon Glassa6cb9952019-07-20 12:24:15 -06003604 image = Image.FromFile(updated_fname)
3605 image.LoadData()
3606 entries = image.GetEntries()
3607
3608 # This one should not change
3609 data = entries['u-boot'].data
3610 self.assertEqual(U_BOOT_DATA, data)
3611
3612 data = entries['u-boot2'].data
3613 self.assertEqual(expected2, data)
3614
3615 data = entries['text'].data
3616 self.assertEqual(expected_text, data)
3617
3618 def testReplaceMissing(self):
3619 """Test replacing entries where the file is missing"""
3620 updated_fname, outdir, expected1, expected2, expected_text = (
3621 self._SetupForReplace())
3622
3623 # Remove one of the files, to generate a warning
3624 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3625 os.remove(u_boot_fname1)
3626
3627 with test_util.capture_sys_output() as (stdout, stderr):
3628 control.ReplaceEntries(updated_fname, None, outdir, [])
3629 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass38fdb4c2020-07-09 18:39:39 -06003630 stderr.getvalue())
Simon Glassa6cb9952019-07-20 12:24:15 -06003631
3632 def testReplaceCmdMap(self):
3633 """Test replacing a file fron an image on the command line"""
3634 self._DoReadFileRealDtb('143_replace_all.dts')
3635
3636 try:
3637 tmpdir, updated_fname = self._SetupImageInTmpdir()
3638
3639 fname = os.path.join(self._indir, 'update-u-boot.bin')
3640 expected = b'x' * len(U_BOOT_DATA)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003641 tools.write_file(fname, expected)
Simon Glassa6cb9952019-07-20 12:24:15 -06003642
3643 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3644 '-f', fname, '-m')
3645 map_fname = os.path.join(tmpdir, 'image-updated.map')
3646 self.assertTrue(os.path.exists(map_fname))
3647 finally:
3648 shutil.rmtree(tmpdir)
3649
3650 def testReplaceNoEntryPaths(self):
3651 """Test replacing an entry without an entry path"""
3652 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003653 image_fname = tools.get_output_filename('image.bin')
Simon Glassa6cb9952019-07-20 12:24:15 -06003654 with self.assertRaises(ValueError) as e:
3655 control.ReplaceEntries(image_fname, 'fname', None, [])
3656 self.assertIn('Must specify an entry path to read with -f',
3657 str(e.exception))
3658
3659 def testReplaceTooManyEntryPaths(self):
3660 """Test extracting some entries"""
3661 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003662 image_fname = tools.get_output_filename('image.bin')
Simon Glassa6cb9952019-07-20 12:24:15 -06003663 with self.assertRaises(ValueError) as e:
3664 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3665 self.assertIn('Must specify exactly one entry path to write with -f',
3666 str(e.exception))
3667
Simon Glass2250ee62019-08-24 07:22:48 -06003668 def testPackReset16(self):
3669 """Test that an image with an x86 reset16 region can be created"""
3670 data = self._DoReadFile('144_x86_reset16.dts')
3671 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3672
3673 def testPackReset16Spl(self):
3674 """Test that an image with an x86 reset16-spl region can be created"""
3675 data = self._DoReadFile('145_x86_reset16_spl.dts')
3676 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3677
3678 def testPackReset16Tpl(self):
3679 """Test that an image with an x86 reset16-tpl region can be created"""
3680 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3681 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3682
Simon Glass5af12072019-08-24 07:22:50 -06003683 def testPackIntelFit(self):
3684 """Test that an image with an Intel FIT and pointer can be created"""
3685 data = self._DoReadFile('147_intel_fit.dts')
3686 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3687 fit = data[16:32];
3688 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3689 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3690
3691 image = control.images['image']
3692 entries = image.GetEntries()
3693 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3694 self.assertEqual(expected_ptr, ptr)
3695
3696 def testPackIntelFitMissing(self):
3697 """Test detection of a FIT pointer with not FIT region"""
3698 with self.assertRaises(ValueError) as e:
3699 self._DoReadFile('148_intel_fit_missing.dts')
3700 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3701 str(e.exception))
3702
Simon Glass7c150132019-11-06 17:22:44 -07003703 def _CheckSymbolsTplSection(self, dts, expected_vals):
3704 data = self._DoReadFile(dts)
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003705 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE, *expected_vals)
Simon Glass2090f1e2019-08-24 07:23:00 -06003706 upto1 = 4 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003707 expected1 = tools.get_bytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass2090f1e2019-08-24 07:23:00 -06003708 self.assertEqual(expected1, data[:upto1])
3709
3710 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003711 expected2 = tools.get_bytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass2090f1e2019-08-24 07:23:00 -06003712 self.assertEqual(expected2, data[upto1:upto2])
3713
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003714 upto3 = 0x3c + len(U_BOOT_DATA)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003715 expected3 = tools.get_bytes(0xff, 1) + U_BOOT_DATA
Simon Glass2090f1e2019-08-24 07:23:00 -06003716 self.assertEqual(expected3, data[upto2:upto3])
3717
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003718 expected4 = sym_values + U_BOOT_TPL_DATA[24:]
Simon Glass7c150132019-11-06 17:22:44 -07003719 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3720
3721 def testSymbolsTplSection(self):
3722 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3723 self._SetupSplElf('u_boot_binman_syms')
3724 self._SetupTplElf('u_boot_binman_syms')
3725 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003726 [0x04, 0x20, 0x10 + 0x3c, 0x04])
Simon Glass7c150132019-11-06 17:22:44 -07003727
3728 def testSymbolsTplSectionX86(self):
3729 """Test binman can assign symbols in a section with end-at-4gb"""
3730 self._SetupSplElf('u_boot_binman_syms_x86')
3731 self._SetupTplElf('u_boot_binman_syms_x86')
3732 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003733 [0xffffff04, 0xffffff20, 0xffffff3c,
Simon Glass7c150132019-11-06 17:22:44 -07003734 0x04])
Simon Glass2090f1e2019-08-24 07:23:00 -06003735
Simon Glassbf4d0e22019-08-24 07:23:03 -06003736 def testPackX86RomIfwiSectiom(self):
3737 """Test that a section can be placed in an IFWI region"""
3738 self._SetupIfwi('fitimage.bin')
3739 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3740 self._CheckIfwi(data)
3741
Simon Glassea0fff92019-08-24 07:23:07 -06003742 def testPackFspM(self):
3743 """Test that an image with a FSP memory-init binary can be created"""
3744 data = self._DoReadFile('152_intel_fsp_m.dts')
3745 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3746
Simon Glassbc6a88f2019-10-20 21:31:35 -06003747 def testPackFspS(self):
3748 """Test that an image with a FSP silicon-init binary can be created"""
3749 data = self._DoReadFile('153_intel_fsp_s.dts')
3750 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassea0fff92019-08-24 07:23:07 -06003751
Simon Glass998d1482019-10-20 21:31:36 -06003752 def testPackFspT(self):
3753 """Test that an image with a FSP temp-ram-init binary can be created"""
3754 data = self._DoReadFile('154_intel_fsp_t.dts')
3755 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3756
Simon Glass0dc706f2020-07-09 18:39:31 -06003757 def testMkimage(self):
3758 """Test using mkimage to build an image"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06003759 self._SetupSplElf()
Simon Glass0dc706f2020-07-09 18:39:31 -06003760 data = self._DoReadFile('156_mkimage.dts')
3761
3762 # Just check that the data appears in the file somewhere
3763 self.assertIn(U_BOOT_SPL_DATA, data)
3764
Simon Glass4f9ee832022-01-09 20:14:09 -07003765 def testMkimageMissing(self):
3766 """Test that binman still produces an image if mkimage is missing"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06003767 self._SetupSplElf()
Simon Glass4f9ee832022-01-09 20:14:09 -07003768 with test_util.capture_sys_output() as (_, stderr):
3769 self._DoTestFile('156_mkimage.dts',
3770 force_missing_bintools='mkimage')
3771 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07003772 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass4f9ee832022-01-09 20:14:09 -07003773
Simon Glassce867ad2020-07-09 18:39:36 -06003774 def testExtblob(self):
3775 """Test an image with an external blob"""
3776 data = self._DoReadFile('157_blob_ext.dts')
3777 self.assertEqual(REFCODE_DATA, data)
3778
3779 def testExtblobMissing(self):
3780 """Test an image with a missing external blob"""
3781 with self.assertRaises(ValueError) as e:
3782 self._DoReadFile('158_blob_ext_missing.dts')
3783 self.assertIn("Filename 'missing-file' not found in input path",
3784 str(e.exception))
3785
Simon Glass4f9f1052020-07-09 18:39:38 -06003786 def testExtblobMissingOk(self):
3787 """Test an image with an missing external blob that is allowed"""
Simon Glassb1cca952020-07-09 18:39:40 -06003788 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glassb38da152022-11-09 19:14:42 -07003789 ret = self._DoTestFile('158_blob_ext_missing.dts',
3790 allow_missing=True)
3791 self.assertEqual(103, ret)
Simon Glassb1cca952020-07-09 18:39:40 -06003792 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07003793 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glassb38da152022-11-09 19:14:42 -07003794 self.assertIn('Some images are invalid', err)
3795
3796 def testExtblobMissingOkFlag(self):
3797 """Test an image with an missing external blob allowed with -W"""
3798 with test_util.capture_sys_output() as (stdout, stderr):
3799 ret = self._DoTestFile('158_blob_ext_missing.dts',
3800 allow_missing=True, ignore_missing=True)
3801 self.assertEqual(0, ret)
3802 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07003803 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glassb38da152022-11-09 19:14:42 -07003804 self.assertIn('Some images are invalid', err)
Simon Glassb1cca952020-07-09 18:39:40 -06003805
3806 def testExtblobMissingOkSect(self):
3807 """Test an image with an missing external blob that is allowed"""
3808 with test_util.capture_sys_output() as (stdout, stderr):
3809 self._DoTestFile('159_blob_ext_missing_sect.dts',
3810 allow_missing=True)
3811 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07003812 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext blob-ext2")
Simon Glass4f9f1052020-07-09 18:39:38 -06003813
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003814 def testPackX86RomMeMissingDesc(self):
3815 """Test that an missing Intel descriptor entry is allowed"""
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003816 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass52b10dd2020-07-25 15:11:19 -06003817 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003818 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07003819 self.assertRegex(err, "Image 'image'.*missing.*: intel-descriptor")
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003820
3821 def testPackX86RomMissingIfwi(self):
3822 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3823 self._SetupIfwi('fitimage.bin')
3824 pathname = os.path.join(self._indir, 'fitimage.bin')
3825 os.remove(pathname)
3826 with test_util.capture_sys_output() as (stdout, stderr):
3827 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3828 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07003829 self.assertRegex(err, "Image 'image'.*missing.*: intel-ifwi")
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003830
Simon Glass8d2ef3e2022-02-11 13:23:21 -07003831 def testPackOverlapZero(self):
Simon Glassb3295fd2020-07-09 18:39:42 -06003832 """Test that zero-size overlapping regions are ignored"""
3833 self._DoTestFile('160_pack_overlap_zero.dts')
3834
Alper Nebi Yasak21353312022-02-08 01:08:04 +03003835 def _CheckSimpleFitData(self, fit_data, kernel_data, fdt1_data):
Simon Glassfdc34362020-07-09 18:39:45 -06003836 # The data should be inside the FIT
3837 dtb = fdt.Fdt.FromData(fit_data)
3838 dtb.Scan()
3839 fnode = dtb.GetNode('/images/kernel')
3840 self.assertIn('data', fnode.props)
3841
3842 fname = os.path.join(self._indir, 'fit_data.fit')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003843 tools.write_file(fname, fit_data)
3844 out = tools.run('dumpimage', '-l', fname)
Simon Glassfdc34362020-07-09 18:39:45 -06003845
3846 # Check a few features to make sure the plumbing works. We don't need
3847 # to test the operation of mkimage or dumpimage here. First convert the
3848 # output into a dict where the keys are the fields printed by dumpimage
3849 # and the values are a list of values for each field
3850 lines = out.splitlines()
3851
3852 # Converts "Compression: gzip compressed" into two groups:
3853 # 'Compression' and 'gzip compressed'
3854 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3855 vals = collections.defaultdict(list)
3856 for line in lines:
3857 mat = re_line.match(line)
3858 vals[mat.group(1)].append(mat.group(2))
3859
3860 self.assertEquals('FIT description: test-desc', lines[0])
3861 self.assertIn('Created:', lines[1])
3862 self.assertIn('Image 0 (kernel)', vals)
3863 self.assertIn('Hash value', vals)
3864 data_sizes = vals.get('Data Size')
3865 self.assertIsNotNone(data_sizes)
3866 self.assertEqual(2, len(data_sizes))
3867 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
Alper Nebi Yasak21353312022-02-08 01:08:04 +03003868 self.assertEqual(len(kernel_data), int(data_sizes[0].split()[0]))
3869 self.assertEqual(len(fdt1_data), int(data_sizes[1].split()[0]))
3870
Alper Nebi Yasake7368782022-03-27 18:31:47 +03003871 # Check if entry listing correctly omits /images/
3872 image = control.images['image']
3873 fit_entry = image.GetEntries()['fit']
3874 subentries = list(fit_entry.GetEntries().keys())
3875 expected = ['kernel', 'fdt-1']
3876 self.assertEqual(expected, subentries)
3877
Alper Nebi Yasak21353312022-02-08 01:08:04 +03003878 def testSimpleFit(self):
3879 """Test an image with a FIT inside"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06003880 self._SetupSplElf()
Alper Nebi Yasak21353312022-02-08 01:08:04 +03003881 data = self._DoReadFile('161_fit.dts')
3882 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3883 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3884 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3885
3886 self._CheckSimpleFitData(fit_data, U_BOOT_DATA, U_BOOT_SPL_DTB_DATA)
3887
3888 def testSimpleFitExpandsSubentries(self):
3889 """Test that FIT images expand their subentries"""
3890 data = self._DoReadFileDtb('161_fit.dts', use_expanded=True)[0]
3891 self.assertEqual(U_BOOT_EXP_DATA, data[:len(U_BOOT_EXP_DATA)])
3892 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3893 fit_data = data[len(U_BOOT_EXP_DATA):-len(U_BOOT_NODTB_DATA)]
3894
3895 self._CheckSimpleFitData(fit_data, U_BOOT_EXP_DATA, U_BOOT_SPL_DTB_DATA)
Simon Glassfdc34362020-07-09 18:39:45 -06003896
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003897 def testSimpleFitImagePos(self):
3898 """Test that we have correct image-pos for FIT subentries"""
3899 data, _, _, out_dtb_fname = self._DoReadFileDtb('161_fit.dts',
3900 update_dtb=True)
3901 dtb = fdt.Fdt(out_dtb_fname)
3902 dtb.Scan()
3903 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3904
Simon Glass38397d02022-03-05 20:19:01 -07003905 self.maxDiff = None
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003906 self.assertEqual({
3907 'image-pos': 0,
3908 'offset': 0,
3909 'size': 1890,
3910
3911 'u-boot:image-pos': 0,
3912 'u-boot:offset': 0,
3913 'u-boot:size': 4,
3914
3915 'fit:image-pos': 4,
3916 'fit:offset': 4,
3917 'fit:size': 1840,
3918
Simon Glass38397d02022-03-05 20:19:01 -07003919 'fit/images/kernel:image-pos': 304,
3920 'fit/images/kernel:offset': 300,
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003921 'fit/images/kernel:size': 4,
3922
Simon Glass38397d02022-03-05 20:19:01 -07003923 'fit/images/kernel/u-boot:image-pos': 304,
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003924 'fit/images/kernel/u-boot:offset': 0,
3925 'fit/images/kernel/u-boot:size': 4,
3926
Simon Glass38397d02022-03-05 20:19:01 -07003927 'fit/images/fdt-1:image-pos': 552,
3928 'fit/images/fdt-1:offset': 548,
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003929 'fit/images/fdt-1:size': 6,
3930
Simon Glass38397d02022-03-05 20:19:01 -07003931 'fit/images/fdt-1/u-boot-spl-dtb:image-pos': 552,
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003932 'fit/images/fdt-1/u-boot-spl-dtb:offset': 0,
3933 'fit/images/fdt-1/u-boot-spl-dtb:size': 6,
3934
3935 'u-boot-nodtb:image-pos': 1844,
3936 'u-boot-nodtb:offset': 1844,
3937 'u-boot-nodtb:size': 46,
3938 }, props)
3939
3940 # Actually check the data is where we think it is
3941 for node, expected in [
3942 ("u-boot", U_BOOT_DATA),
3943 ("fit/images/kernel", U_BOOT_DATA),
3944 ("fit/images/kernel/u-boot", U_BOOT_DATA),
3945 ("fit/images/fdt-1", U_BOOT_SPL_DTB_DATA),
3946 ("fit/images/fdt-1/u-boot-spl-dtb", U_BOOT_SPL_DTB_DATA),
3947 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
3948 ]:
3949 image_pos = props[f"{node}:image-pos"]
3950 size = props[f"{node}:size"]
3951 self.assertEqual(len(expected), size)
3952 self.assertEqual(expected, data[image_pos:image_pos+size])
3953
Simon Glassfdc34362020-07-09 18:39:45 -06003954 def testFitExternal(self):
Simon Glasse9d336d2020-09-01 05:13:55 -06003955 """Test an image with an FIT with external images"""
Simon Glassfdc34362020-07-09 18:39:45 -06003956 data = self._DoReadFile('162_fit_external.dts')
3957 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3958
Simon Glass8bc78b72022-01-09 20:13:39 -07003959 # Size of the external-data region as set up by mkimage
3960 external_data_size = len(U_BOOT_DATA) + 2
3961 expected_size = (len(U_BOOT_DATA) + 0x400 +
Simon Glassc1aa66e2022-01-29 14:14:04 -07003962 tools.align(external_data_size, 4) +
Simon Glass8bc78b72022-01-09 20:13:39 -07003963 len(U_BOOT_NODTB_DATA))
3964
Simon Glassfdc34362020-07-09 18:39:45 -06003965 # The data should be outside the FIT
3966 dtb = fdt.Fdt.FromData(fit_data)
3967 dtb.Scan()
3968 fnode = dtb.GetNode('/images/kernel')
3969 self.assertNotIn('data', fnode.props)
Simon Glass8bc78b72022-01-09 20:13:39 -07003970 self.assertEqual(len(U_BOOT_DATA),
3971 fdt_util.fdt32_to_cpu(fnode.props['data-size'].value))
3972 fit_pos = 0x400;
3973 self.assertEqual(
3974 fit_pos,
3975 fdt_util.fdt32_to_cpu(fnode.props['data-position'].value))
3976
3977 self.assertEquals(expected_size, len(data))
3978 actual_pos = len(U_BOOT_DATA) + fit_pos
3979 self.assertEqual(U_BOOT_DATA + b'aa',
3980 data[actual_pos:actual_pos + external_data_size])
Simon Glass12bb1a92019-07-20 12:23:51 -06003981
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003982 def testFitExternalImagePos(self):
3983 """Test that we have correct image-pos for external FIT subentries"""
3984 data, _, _, out_dtb_fname = self._DoReadFileDtb('162_fit_external.dts',
3985 update_dtb=True)
3986 dtb = fdt.Fdt(out_dtb_fname)
3987 dtb.Scan()
3988 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3989
3990 self.assertEqual({
3991 'image-pos': 0,
3992 'offset': 0,
3993 'size': 1082,
3994
3995 'u-boot:image-pos': 0,
3996 'u-boot:offset': 0,
3997 'u-boot:size': 4,
3998
3999 'fit:size': 1032,
4000 'fit:offset': 4,
4001 'fit:image-pos': 4,
4002
4003 'fit/images/kernel:size': 4,
4004 'fit/images/kernel:offset': 1024,
4005 'fit/images/kernel:image-pos': 1028,
4006
4007 'fit/images/kernel/u-boot:size': 4,
4008 'fit/images/kernel/u-boot:offset': 0,
4009 'fit/images/kernel/u-boot:image-pos': 1028,
4010
4011 'fit/images/fdt-1:size': 2,
4012 'fit/images/fdt-1:offset': 1028,
4013 'fit/images/fdt-1:image-pos': 1032,
4014
4015 'fit/images/fdt-1/_testing:size': 2,
4016 'fit/images/fdt-1/_testing:offset': 0,
4017 'fit/images/fdt-1/_testing:image-pos': 1032,
4018
4019 'u-boot-nodtb:image-pos': 1036,
4020 'u-boot-nodtb:offset': 1036,
4021 'u-boot-nodtb:size': 46,
4022 }, props)
4023
4024 # Actually check the data is where we think it is
4025 for node, expected in [
4026 ("u-boot", U_BOOT_DATA),
4027 ("fit/images/kernel", U_BOOT_DATA),
4028 ("fit/images/kernel/u-boot", U_BOOT_DATA),
4029 ("fit/images/fdt-1", b'aa'),
4030 ("fit/images/fdt-1/_testing", b'aa'),
4031 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
4032 ]:
4033 image_pos = props[f"{node}:image-pos"]
4034 size = props[f"{node}:size"]
4035 self.assertEqual(len(expected), size)
4036 self.assertEqual(expected, data[image_pos:image_pos+size])
4037
Simon Glass4f9ee832022-01-09 20:14:09 -07004038 def testFitMissing(self):
Simon Glass033828c2023-03-02 17:02:43 -07004039 """Test that binman complains if mkimage is missing"""
4040 with self.assertRaises(ValueError) as e:
4041 self._DoTestFile('162_fit_external.dts',
4042 force_missing_bintools='mkimage')
4043 self.assertIn("Node '/binman/fit': Missing tool: 'mkimage'",
4044 str(e.exception))
4045
4046 def testFitMissingOK(self):
Simon Glass4f9ee832022-01-09 20:14:09 -07004047 """Test that binman still produces a FIT image if mkimage is missing"""
4048 with test_util.capture_sys_output() as (_, stderr):
Simon Glass033828c2023-03-02 17:02:43 -07004049 self._DoTestFile('162_fit_external.dts', allow_missing=True,
Simon Glass4f9ee832022-01-09 20:14:09 -07004050 force_missing_bintools='mkimage')
4051 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07004052 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass4f9ee832022-01-09 20:14:09 -07004053
Alper Nebi Yasak8001d0b2020-08-31 12:58:18 +03004054 def testSectionIgnoreHashSignature(self):
4055 """Test that sections ignore hash, signature nodes for its data"""
4056 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
4057 expected = (U_BOOT_DATA + U_BOOT_DATA)
4058 self.assertEqual(expected, data)
4059
Alper Nebi Yasak3fdeb142020-08-31 12:58:19 +03004060 def testPadInSections(self):
4061 """Test pad-before, pad-after for entries in sections"""
Simon Glassf90d9062020-10-26 17:40:09 -06004062 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4063 '166_pad_in_sections.dts', update_dtb=True)
Simon Glassc1aa66e2022-01-29 14:14:04 -07004064 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4065 U_BOOT_DATA + tools.get_bytes(ord('!'), 6) +
Alper Nebi Yasak3fdeb142020-08-31 12:58:19 +03004066 U_BOOT_DATA)
4067 self.assertEqual(expected, data)
4068
Simon Glassf90d9062020-10-26 17:40:09 -06004069 dtb = fdt.Fdt(out_dtb_fname)
4070 dtb.Scan()
4071 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
4072 expected = {
4073 'image-pos': 0,
4074 'offset': 0,
4075 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
4076
4077 'section:image-pos': 0,
4078 'section:offset': 0,
4079 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
4080
4081 'section/before:image-pos': 0,
4082 'section/before:offset': 0,
4083 'section/before:size': len(U_BOOT_DATA),
4084
4085 'section/u-boot:image-pos': 4,
4086 'section/u-boot:offset': 4,
4087 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
4088
4089 'section/after:image-pos': 26,
4090 'section/after:offset': 26,
4091 'section/after:size': len(U_BOOT_DATA),
4092 }
4093 self.assertEqual(expected, props)
4094
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03004095 def testFitImageSubentryAlignment(self):
4096 """Test relative alignability of FIT image subentries"""
Alper Nebi Yasakf3078d42022-02-08 01:08:07 +03004097 self._SetupSplElf()
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03004098 entry_args = {
4099 'test-id': TEXT_DATA,
4100 }
4101 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
4102 entry_args=entry_args)
4103 dtb = fdt.Fdt.FromData(data)
4104 dtb.Scan()
4105
4106 node = dtb.GetNode('/images/kernel')
4107 data = dtb.GetProps(node)["data"].bytes
4108 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
Simon Glassc1aa66e2022-01-29 14:14:04 -07004109 expected = (tools.get_bytes(0, 0x20) + U_BOOT_SPL_DATA +
4110 tools.get_bytes(0, align_pad) + U_BOOT_DATA)
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03004111 self.assertEqual(expected, data)
4112
4113 node = dtb.GetNode('/images/fdt-1')
4114 data = dtb.GetProps(node)["data"].bytes
Simon Glassc1aa66e2022-01-29 14:14:04 -07004115 expected = (U_BOOT_SPL_DTB_DATA + tools.get_bytes(0, 20) +
4116 tools.to_bytes(TEXT_DATA) + tools.get_bytes(0, 30) +
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03004117 U_BOOT_DTB_DATA)
4118 self.assertEqual(expected, data)
4119
4120 def testFitExtblobMissingOk(self):
4121 """Test a FIT with a missing external blob that is allowed"""
4122 with test_util.capture_sys_output() as (stdout, stderr):
4123 self._DoTestFile('168_fit_missing_blob.dts',
4124 allow_missing=True)
4125 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07004126 self.assertRegex(err, "Image 'image'.*missing.*: atf-bl31")
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03004127
Simon Glass3decfa32020-09-01 05:13:54 -06004128 def testBlobNamedByArgMissing(self):
4129 """Test handling of a missing entry arg"""
4130 with self.assertRaises(ValueError) as e:
4131 self._DoReadFile('068_blob_named_by_arg.dts')
4132 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
4133 str(e.exception))
4134
Simon Glassdc2f81a2020-09-01 05:13:58 -06004135 def testPackBl31(self):
4136 """Test that an image with an ATF BL31 binary can be created"""
4137 data = self._DoReadFile('169_atf_bl31.dts')
4138 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
4139
Samuel Holland18bd4552020-10-21 21:12:15 -05004140 def testPackScp(self):
4141 """Test that an image with an SCP binary can be created"""
4142 data = self._DoReadFile('172_scp.dts')
4143 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
4144
Simon Glass6cf99532020-09-01 05:13:59 -06004145 def testFitFdt(self):
4146 """Test an image with an FIT with multiple FDT images"""
4147 def _CheckFdt(seq, expected_data):
4148 """Check the FDT nodes
4149
4150 Args:
4151 seq: Sequence number to check (0 or 1)
4152 expected_data: Expected contents of 'data' property
4153 """
4154 name = 'fdt-%d' % seq
4155 fnode = dtb.GetNode('/images/%s' % name)
4156 self.assertIsNotNone(fnode)
4157 self.assertEqual({'description','type', 'compression', 'data'},
4158 set(fnode.props.keys()))
4159 self.assertEqual(expected_data, fnode.props['data'].bytes)
4160 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
4161 fnode.props['description'].value)
Jan Kiszkab2106612022-02-28 17:06:20 +01004162 self.assertEqual(fnode.subnodes[0].name, 'hash')
Simon Glass6cf99532020-09-01 05:13:59 -06004163
4164 def _CheckConfig(seq, expected_data):
4165 """Check the configuration nodes
4166
4167 Args:
4168 seq: Sequence number to check (0 or 1)
4169 expected_data: Expected contents of 'data' property
4170 """
4171 cnode = dtb.GetNode('/configurations')
4172 self.assertIn('default', cnode.props)
Simon Glassc0f1ebe2020-09-06 10:39:08 -06004173 self.assertEqual('config-2', cnode.props['default'].value)
Simon Glass6cf99532020-09-01 05:13:59 -06004174
4175 name = 'config-%d' % seq
4176 fnode = dtb.GetNode('/configurations/%s' % name)
4177 self.assertIsNotNone(fnode)
4178 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
4179 set(fnode.props.keys()))
4180 self.assertEqual('conf-test-fdt%d.dtb' % seq,
4181 fnode.props['description'].value)
4182 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
4183
4184 entry_args = {
4185 'of-list': 'test-fdt1 test-fdt2',
Simon Glassc0f1ebe2020-09-06 10:39:08 -06004186 'default-dt': 'test-fdt2',
Simon Glass6cf99532020-09-01 05:13:59 -06004187 }
4188 data = self._DoReadFileDtb(
Bin Mengaa75ce92021-05-10 20:23:32 +08004189 '170_fit_fdt.dts',
Simon Glass6cf99532020-09-01 05:13:59 -06004190 entry_args=entry_args,
4191 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4192 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4193 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4194
4195 dtb = fdt.Fdt.FromData(fit_data)
4196 dtb.Scan()
4197 fnode = dtb.GetNode('/images/kernel')
4198 self.assertIn('data', fnode.props)
4199
4200 # Check all the properties in fdt-1 and fdt-2
4201 _CheckFdt(1, TEST_FDT1_DATA)
4202 _CheckFdt(2, TEST_FDT2_DATA)
4203
4204 # Check configurations
4205 _CheckConfig(1, TEST_FDT1_DATA)
4206 _CheckConfig(2, TEST_FDT2_DATA)
4207
4208 def testFitFdtMissingList(self):
4209 """Test handling of a missing 'of-list' entry arg"""
4210 with self.assertRaises(ValueError) as e:
Bin Mengaa75ce92021-05-10 20:23:32 +08004211 self._DoReadFile('170_fit_fdt.dts')
Simon Glass6cf99532020-09-01 05:13:59 -06004212 self.assertIn("Generator node requires 'of-list' entry argument",
4213 str(e.exception))
4214
4215 def testFitFdtEmptyList(self):
4216 """Test handling of an empty 'of-list' entry arg"""
4217 entry_args = {
4218 'of-list': '',
4219 }
4220 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
4221
4222 def testFitFdtMissingProp(self):
4223 """Test handling of a missing 'fit,fdt-list' property"""
4224 with self.assertRaises(ValueError) as e:
4225 self._DoReadFile('171_fit_fdt_missing_prop.dts')
4226 self.assertIn("Generator node requires 'fit,fdt-list' property",
4227 str(e.exception))
Simon Glassdc2f81a2020-09-01 05:13:58 -06004228
Simon Glassc0f1ebe2020-09-06 10:39:08 -06004229 def testFitFdtMissing(self):
4230 """Test handling of a missing 'default-dt' entry arg"""
4231 entry_args = {
4232 'of-list': 'test-fdt1 test-fdt2',
4233 }
4234 with self.assertRaises(ValueError) as e:
4235 self._DoReadFileDtb(
Bin Mengaa75ce92021-05-10 20:23:32 +08004236 '170_fit_fdt.dts',
Simon Glassc0f1ebe2020-09-06 10:39:08 -06004237 entry_args=entry_args,
4238 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4239 self.assertIn("Generated 'default' node requires default-dt entry argument",
4240 str(e.exception))
4241
4242 def testFitFdtNotInList(self):
4243 """Test handling of a default-dt that is not in the of-list"""
4244 entry_args = {
4245 'of-list': 'test-fdt1 test-fdt2',
4246 'default-dt': 'test-fdt3',
4247 }
4248 with self.assertRaises(ValueError) as e:
4249 self._DoReadFileDtb(
Bin Mengaa75ce92021-05-10 20:23:32 +08004250 '170_fit_fdt.dts',
Simon Glassc0f1ebe2020-09-06 10:39:08 -06004251 entry_args=entry_args,
4252 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4253 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
4254 str(e.exception))
4255
Simon Glassb2381432020-09-06 10:39:09 -06004256 def testFitExtblobMissingHelp(self):
4257 """Test display of help messages when an external blob is missing"""
4258 control.missing_blob_help = control._ReadMissingBlobHelp()
4259 control.missing_blob_help['wibble'] = 'Wibble test'
4260 control.missing_blob_help['another'] = 'Another test'
4261 with test_util.capture_sys_output() as (stdout, stderr):
4262 self._DoTestFile('168_fit_missing_blob.dts',
4263 allow_missing=True)
4264 err = stderr.getvalue()
4265
4266 # We can get the tag from the name, the type or the missing-msg
4267 # property. Check all three.
4268 self.assertIn('You may need to build ARM Trusted', err)
4269 self.assertIn('Wibble test', err)
4270 self.assertIn('Another test', err)
4271
Simon Glass204aa782020-09-06 10:35:32 -06004272 def testMissingBlob(self):
4273 """Test handling of a blob containing a missing file"""
4274 with self.assertRaises(ValueError) as e:
4275 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
4276 self.assertIn("Filename 'missing' not found in input path",
4277 str(e.exception))
4278
Simon Glassfb91d562020-09-06 10:35:33 -06004279 def testEnvironment(self):
4280 """Test adding a U-Boot environment"""
4281 data = self._DoReadFile('174_env.dts')
4282 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
4283 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4284 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4285 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
4286 env)
4287
4288 def testEnvironmentNoSize(self):
4289 """Test that a missing 'size' property is detected"""
4290 with self.assertRaises(ValueError) as e:
Simon Glassa4dfe3e2020-10-26 17:40:00 -06004291 self._DoTestFile('175_env_no_size.dts')
Simon Glassfb91d562020-09-06 10:35:33 -06004292 self.assertIn("'u-boot-env' entry must have a size property",
4293 str(e.exception))
4294
4295 def testEnvironmentTooSmall(self):
4296 """Test handling of an environment that does not fit"""
4297 with self.assertRaises(ValueError) as e:
Simon Glassa4dfe3e2020-10-26 17:40:00 -06004298 self._DoTestFile('176_env_too_small.dts')
Simon Glassfb91d562020-09-06 10:35:33 -06004299
4300 # checksum, start byte, environment with \0 terminator, final \0
4301 need = 4 + 1 + len(ENV_DATA) + 1 + 1
4302 short = need - 0x8
4303 self.assertIn("too small to hold data (need %#x more bytes)" % short,
4304 str(e.exception))
4305
Simon Glassf2c0dd82020-10-26 17:40:01 -06004306 def testSkipAtStart(self):
4307 """Test handling of skip-at-start section"""
4308 data = self._DoReadFile('177_skip_at_start.dts')
4309 self.assertEqual(U_BOOT_DATA, data)
4310
4311 image = control.images['image']
4312 entries = image.GetEntries()
4313 section = entries['section']
4314 self.assertEqual(0, section.offset)
4315 self.assertEqual(len(U_BOOT_DATA), section.size)
4316 self.assertEqual(U_BOOT_DATA, section.GetData())
4317
4318 entry = section.GetEntries()['u-boot']
4319 self.assertEqual(16, entry.offset)
4320 self.assertEqual(len(U_BOOT_DATA), entry.size)
4321 self.assertEqual(U_BOOT_DATA, entry.data)
4322
4323 def testSkipAtStartPad(self):
4324 """Test handling of skip-at-start section with padded entry"""
4325 data = self._DoReadFile('178_skip_at_start_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004326 before = tools.get_bytes(0, 8)
4327 after = tools.get_bytes(0, 4)
Simon Glassf2c0dd82020-10-26 17:40:01 -06004328 all = before + U_BOOT_DATA + after
4329 self.assertEqual(all, data)
4330
4331 image = control.images['image']
4332 entries = image.GetEntries()
4333 section = entries['section']
4334 self.assertEqual(0, section.offset)
4335 self.assertEqual(len(all), section.size)
4336 self.assertEqual(all, section.GetData())
4337
4338 entry = section.GetEntries()['u-boot']
4339 self.assertEqual(16, entry.offset)
4340 self.assertEqual(len(all), entry.size)
4341 self.assertEqual(U_BOOT_DATA, entry.data)
4342
4343 def testSkipAtStartSectionPad(self):
4344 """Test handling of skip-at-start section with padding"""
4345 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004346 before = tools.get_bytes(0, 8)
4347 after = tools.get_bytes(0, 4)
Simon Glassf2c0dd82020-10-26 17:40:01 -06004348 all = before + U_BOOT_DATA + after
Simon Glassd1d3ad72020-10-26 17:40:13 -06004349 self.assertEqual(all, data)
Simon Glassf2c0dd82020-10-26 17:40:01 -06004350
4351 image = control.images['image']
4352 entries = image.GetEntries()
4353 section = entries['section']
4354 self.assertEqual(0, section.offset)
4355 self.assertEqual(len(all), section.size)
Simon Glass63e7ba62020-10-26 17:40:16 -06004356 self.assertEqual(U_BOOT_DATA, section.data)
Simon Glassd1d3ad72020-10-26 17:40:13 -06004357 self.assertEqual(all, section.GetPaddedData())
Simon Glassf2c0dd82020-10-26 17:40:01 -06004358
4359 entry = section.GetEntries()['u-boot']
4360 self.assertEqual(16, entry.offset)
4361 self.assertEqual(len(U_BOOT_DATA), entry.size)
4362 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassfb91d562020-09-06 10:35:33 -06004363
Simon Glass7d398bb2020-10-26 17:40:14 -06004364 def testSectionPad(self):
4365 """Testing padding with sections"""
4366 data = self._DoReadFile('180_section_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004367 expected = (tools.get_bytes(ord('&'), 3) +
4368 tools.get_bytes(ord('!'), 5) +
Simon Glass7d398bb2020-10-26 17:40:14 -06004369 U_BOOT_DATA +
Simon Glassc1aa66e2022-01-29 14:14:04 -07004370 tools.get_bytes(ord('!'), 1) +
4371 tools.get_bytes(ord('&'), 2))
Simon Glass7d398bb2020-10-26 17:40:14 -06004372 self.assertEqual(expected, data)
4373
4374 def testSectionAlign(self):
4375 """Testing alignment with sections"""
4376 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4377 expected = (b'\0' + # fill section
Simon Glassc1aa66e2022-01-29 14:14:04 -07004378 tools.get_bytes(ord('&'), 1) + # padding to section align
Simon Glass7d398bb2020-10-26 17:40:14 -06004379 b'\0' + # fill section
Simon Glassc1aa66e2022-01-29 14:14:04 -07004380 tools.get_bytes(ord('!'), 3) + # padding to u-boot align
Simon Glass7d398bb2020-10-26 17:40:14 -06004381 U_BOOT_DATA +
Simon Glassc1aa66e2022-01-29 14:14:04 -07004382 tools.get_bytes(ord('!'), 4) + # padding to u-boot size
4383 tools.get_bytes(ord('!'), 4)) # padding to section size
Simon Glass7d398bb2020-10-26 17:40:14 -06004384 self.assertEqual(expected, data)
4385
Simon Glass8f5ef892020-10-26 17:40:25 -06004386 def testCompressImage(self):
4387 """Test compression of the entire image"""
4388 self._CheckLz4()
4389 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4390 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4391 dtb = fdt.Fdt(out_dtb_fname)
4392 dtb.Scan()
4393 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4394 'uncomp-size'])
4395 orig = self._decompress(data)
4396 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4397
4398 # Do a sanity check on various fields
4399 image = control.images['image']
4400 entries = image.GetEntries()
4401 self.assertEqual(2, len(entries))
4402
4403 entry = entries['blob']
4404 self.assertEqual(COMPRESS_DATA, entry.data)
4405 self.assertEqual(len(COMPRESS_DATA), entry.size)
4406
4407 entry = entries['u-boot']
4408 self.assertEqual(U_BOOT_DATA, entry.data)
4409 self.assertEqual(len(U_BOOT_DATA), entry.size)
4410
4411 self.assertEqual(len(data), image.size)
4412 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4413 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4414 orig = self._decompress(image.data)
4415 self.assertEqual(orig, image.uncomp_data)
4416
4417 expected = {
4418 'blob:offset': 0,
4419 'blob:size': len(COMPRESS_DATA),
4420 'u-boot:offset': len(COMPRESS_DATA),
4421 'u-boot:size': len(U_BOOT_DATA),
4422 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4423 'offset': 0,
4424 'image-pos': 0,
4425 'size': len(data),
4426 }
4427 self.assertEqual(expected, props)
4428
4429 def testCompressImageLess(self):
4430 """Test compression where compression reduces the image size"""
4431 self._CheckLz4()
4432 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4433 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4434 dtb = fdt.Fdt(out_dtb_fname)
4435 dtb.Scan()
4436 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4437 'uncomp-size'])
4438 orig = self._decompress(data)
4439
4440 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
4441
4442 # Do a sanity check on various fields
4443 image = control.images['image']
4444 entries = image.GetEntries()
4445 self.assertEqual(2, len(entries))
4446
4447 entry = entries['blob']
4448 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4449 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4450
4451 entry = entries['u-boot']
4452 self.assertEqual(U_BOOT_DATA, entry.data)
4453 self.assertEqual(len(U_BOOT_DATA), entry.size)
4454
4455 self.assertEqual(len(data), image.size)
4456 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4457 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4458 image.uncomp_size)
4459 orig = self._decompress(image.data)
4460 self.assertEqual(orig, image.uncomp_data)
4461
4462 expected = {
4463 'blob:offset': 0,
4464 'blob:size': len(COMPRESS_DATA_BIG),
4465 'u-boot:offset': len(COMPRESS_DATA_BIG),
4466 'u-boot:size': len(U_BOOT_DATA),
4467 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4468 'offset': 0,
4469 'image-pos': 0,
4470 'size': len(data),
4471 }
4472 self.assertEqual(expected, props)
4473
4474 def testCompressSectionSize(self):
4475 """Test compression of a section with a fixed size"""
4476 self._CheckLz4()
4477 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4478 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4479 dtb = fdt.Fdt(out_dtb_fname)
4480 dtb.Scan()
4481 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4482 'uncomp-size'])
4483 orig = self._decompress(data)
4484 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4485 expected = {
4486 'section/blob:offset': 0,
4487 'section/blob:size': len(COMPRESS_DATA),
4488 'section/u-boot:offset': len(COMPRESS_DATA),
4489 'section/u-boot:size': len(U_BOOT_DATA),
4490 'section:offset': 0,
4491 'section:image-pos': 0,
4492 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4493 'section:size': 0x30,
4494 'offset': 0,
4495 'image-pos': 0,
4496 'size': 0x30,
4497 }
4498 self.assertEqual(expected, props)
4499
4500 def testCompressSection(self):
4501 """Test compression of a section with no fixed size"""
4502 self._CheckLz4()
4503 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4504 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4505 dtb = fdt.Fdt(out_dtb_fname)
4506 dtb.Scan()
4507 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4508 'uncomp-size'])
4509 orig = self._decompress(data)
4510 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4511 expected = {
4512 'section/blob:offset': 0,
4513 'section/blob:size': len(COMPRESS_DATA),
4514 'section/u-boot:offset': len(COMPRESS_DATA),
4515 'section/u-boot:size': len(U_BOOT_DATA),
4516 'section:offset': 0,
4517 'section:image-pos': 0,
4518 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4519 'section:size': len(data),
4520 'offset': 0,
4521 'image-pos': 0,
4522 'size': len(data),
4523 }
4524 self.assertEqual(expected, props)
4525
Stefan Herbrechtsmeierc3665a82022-08-19 16:25:31 +02004526 def testLz4Missing(self):
4527 """Test that binman still produces an image if lz4 is missing"""
4528 with test_util.capture_sys_output() as (_, stderr):
4529 self._DoTestFile('185_compress_section.dts',
4530 force_missing_bintools='lz4')
4531 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07004532 self.assertRegex(err, "Image 'image'.*missing bintools.*: lz4")
Stefan Herbrechtsmeierc3665a82022-08-19 16:25:31 +02004533
Simon Glass8f5ef892020-10-26 17:40:25 -06004534 def testCompressExtra(self):
4535 """Test compression of a section with no fixed size"""
4536 self._CheckLz4()
4537 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4538 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4539 dtb = fdt.Fdt(out_dtb_fname)
4540 dtb.Scan()
4541 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4542 'uncomp-size'])
4543
4544 base = data[len(U_BOOT_DATA):]
4545 self.assertEquals(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
4546 rest = base[len(U_BOOT_DATA):]
4547
4548 # Check compressed data
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +02004549 bintool = self.comp_bintools['lz4']
4550 expect1 = bintool.compress(COMPRESS_DATA + U_BOOT_DATA)
Stefan Herbrechtsmeierfa24f552022-08-19 16:25:23 +02004551 data1 = rest[:len(expect1)]
4552 section1 = self._decompress(data1)
4553 self.assertEquals(expect1, data1)
Simon Glass8f5ef892020-10-26 17:40:25 -06004554 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, section1)
4555 rest1 = rest[len(expect1):]
4556
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +02004557 expect2 = bintool.compress(COMPRESS_DATA + COMPRESS_DATA)
Stefan Herbrechtsmeierfa24f552022-08-19 16:25:23 +02004558 data2 = rest1[:len(expect2)]
4559 section2 = self._decompress(data2)
4560 self.assertEquals(expect2, data2)
Simon Glass8f5ef892020-10-26 17:40:25 -06004561 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA, section2)
4562 rest2 = rest1[len(expect2):]
4563
4564 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4565 len(expect2) + len(U_BOOT_DATA))
4566 #self.assertEquals(expect_size, len(data))
4567
4568 #self.assertEquals(U_BOOT_DATA, rest2)
4569
4570 self.maxDiff = None
4571 expected = {
4572 'u-boot:offset': 0,
4573 'u-boot:image-pos': 0,
4574 'u-boot:size': len(U_BOOT_DATA),
4575
4576 'base:offset': len(U_BOOT_DATA),
4577 'base:image-pos': len(U_BOOT_DATA),
4578 'base:size': len(data) - len(U_BOOT_DATA),
4579 'base/u-boot:offset': 0,
4580 'base/u-boot:image-pos': len(U_BOOT_DATA),
4581 'base/u-boot:size': len(U_BOOT_DATA),
4582 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4583 len(expect2),
4584 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4585 len(expect2),
4586 'base/u-boot2:size': len(U_BOOT_DATA),
4587
4588 'base/section:offset': len(U_BOOT_DATA),
4589 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4590 'base/section:size': len(expect1),
4591 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4592 'base/section/blob:offset': 0,
4593 'base/section/blob:size': len(COMPRESS_DATA),
4594 'base/section/u-boot:offset': len(COMPRESS_DATA),
4595 'base/section/u-boot:size': len(U_BOOT_DATA),
4596
4597 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4598 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4599 'base/section2:size': len(expect2),
4600 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4601 'base/section2/blob:offset': 0,
4602 'base/section2/blob:size': len(COMPRESS_DATA),
4603 'base/section2/blob2:offset': len(COMPRESS_DATA),
4604 'base/section2/blob2:size': len(COMPRESS_DATA),
4605
4606 'offset': 0,
4607 'image-pos': 0,
4608 'size': len(data),
4609 }
4610 self.assertEqual(expected, props)
4611
Simon Glass870a9ea2021-01-06 21:35:15 -07004612 def testSymbolsSubsection(self):
4613 """Test binman can assign symbols from a subsection"""
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03004614 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glass870a9ea2021-01-06 21:35:15 -07004615
Simon Glass939d1062021-01-06 21:35:16 -07004616 def testReadImageEntryArg(self):
4617 """Test reading an image that would need an entry arg to generate"""
4618 entry_args = {
4619 'cros-ec-rw-path': 'ecrw.bin',
4620 }
4621 data = self.data = self._DoReadFileDtb(
4622 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4623 entry_args=entry_args)
4624
Simon Glassc1aa66e2022-01-29 14:14:04 -07004625 image_fname = tools.get_output_filename('image.bin')
Simon Glass939d1062021-01-06 21:35:16 -07004626 orig_image = control.images['image']
4627
4628 # This should not generate an error about the missing 'cros-ec-rw-path'
4629 # since we are reading the image from a file. Compare with
4630 # testEntryArgsRequired()
4631 image = Image.FromFile(image_fname)
4632 self.assertEqual(orig_image.GetEntries().keys(),
4633 image.GetEntries().keys())
4634
Simon Glass6eb99322021-01-06 21:35:18 -07004635 def testFilesAlign(self):
4636 """Test alignment with files"""
4637 data = self._DoReadFile('190_files_align.dts')
4638
4639 # The first string is 15 bytes so will align to 16
4640 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4641 self.assertEqual(expect, data)
4642
Simon Glass5c6ba712021-01-06 21:35:19 -07004643 def testReadImageSkip(self):
4644 """Test reading an image and accessing its FDT map"""
4645 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004646 image_fname = tools.get_output_filename('image.bin')
Simon Glass5c6ba712021-01-06 21:35:19 -07004647 orig_image = control.images['image']
4648 image = Image.FromFile(image_fname)
4649 self.assertEqual(orig_image.GetEntries().keys(),
4650 image.GetEntries().keys())
4651
4652 orig_entry = orig_image.GetEntries()['fdtmap']
4653 entry = image.GetEntries()['fdtmap']
4654 self.assertEqual(orig_entry.offset, entry.offset)
4655 self.assertEqual(orig_entry.size, entry.size)
4656 self.assertEqual(16, entry.image_pos)
4657
4658 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4659
4660 self.assertEquals(U_BOOT_DATA, u_boot.ReadData())
4661
Simon Glass77a64e02021-03-18 20:24:57 +13004662 def testTplNoDtb(self):
4663 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
Simon Glass0fe44dc2021-04-25 08:39:32 +12004664 self._SetupTplElf()
Simon Glass77a64e02021-03-18 20:24:57 +13004665 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4666 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4667 data[:len(U_BOOT_TPL_NODTB_DATA)])
4668
Simon Glassd26efc82021-03-18 20:24:58 +13004669 def testTplBssPad(self):
4670 """Test that we can pad TPL's BSS with zeros"""
4671 # ELF file with a '__bss_size' symbol
4672 self._SetupTplElf()
4673 data = self._DoReadFile('193_tpl_bss_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004674 self.assertEqual(U_BOOT_TPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glassd26efc82021-03-18 20:24:58 +13004675 data)
4676
4677 def testTplBssPadMissing(self):
4678 """Test that a missing symbol is detected"""
4679 self._SetupTplElf('u_boot_ucode_ptr')
4680 with self.assertRaises(ValueError) as e:
4681 self._DoReadFile('193_tpl_bss_pad.dts')
4682 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4683 str(e.exception))
4684
Simon Glass06684922021-03-18 20:25:07 +13004685 def checkDtbSizes(self, data, pad_len, start):
4686 """Check the size arguments in a dtb embedded in an image
4687
4688 Args:
4689 data: The image data
4690 pad_len: Length of the pad section in the image, in bytes
4691 start: Start offset of the devicetree to examine, within the image
4692
4693 Returns:
4694 Size of the devicetree in bytes
4695 """
4696 dtb_data = data[start:]
4697 dtb = fdt.Fdt.FromData(dtb_data)
4698 fdt_size = dtb.GetFdtObj().totalsize()
4699 dtb.Scan()
4700 props = self._GetPropTree(dtb, 'size')
4701 self.assertEqual({
4702 'size': len(data),
4703 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4704 'u-boot-spl/u-boot-spl-dtb:size': 801,
4705 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4706 'u-boot-spl:size': 860,
4707 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4708 'u-boot/u-boot-dtb:size': 781,
4709 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4710 'u-boot:size': 827,
4711 }, props)
4712 return fdt_size
4713
4714 def testExpanded(self):
4715 """Test that an expanded entry type is selected when needed"""
4716 self._SetupSplElf()
4717 self._SetupTplElf()
4718
4719 # SPL has a devicetree, TPL does not
4720 entry_args = {
4721 'spl-dtb': '1',
4722 'spl-bss-pad': 'y',
4723 'tpl-dtb': '',
4724 }
4725 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4726 entry_args=entry_args)
4727 image = control.images['image']
4728 entries = image.GetEntries()
4729 self.assertEqual(3, len(entries))
4730
4731 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4732 self.assertIn('u-boot', entries)
4733 entry = entries['u-boot']
4734 self.assertEqual('u-boot-expanded', entry.etype)
4735 subent = entry.GetEntries()
4736 self.assertEqual(2, len(subent))
4737 self.assertIn('u-boot-nodtb', subent)
4738 self.assertIn('u-boot-dtb', subent)
4739
4740 # Second, u-boot-spl, which should be expanded into three parts
4741 self.assertIn('u-boot-spl', entries)
4742 entry = entries['u-boot-spl']
4743 self.assertEqual('u-boot-spl-expanded', entry.etype)
4744 subent = entry.GetEntries()
4745 self.assertEqual(3, len(subent))
4746 self.assertIn('u-boot-spl-nodtb', subent)
4747 self.assertIn('u-boot-spl-bss-pad', subent)
4748 self.assertIn('u-boot-spl-dtb', subent)
4749
4750 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4751 # devicetree
4752 self.assertIn('u-boot-tpl', entries)
4753 entry = entries['u-boot-tpl']
4754 self.assertEqual('u-boot-tpl', entry.etype)
4755 self.assertEqual(None, entry.GetEntries())
4756
4757 def testExpandedTpl(self):
4758 """Test that an expanded entry type is selected for TPL when needed"""
4759 self._SetupTplElf()
4760
4761 entry_args = {
4762 'tpl-bss-pad': 'y',
4763 'tpl-dtb': 'y',
4764 }
4765 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4766 entry_args=entry_args)
4767 image = control.images['image']
4768 entries = image.GetEntries()
4769 self.assertEqual(1, len(entries))
4770
4771 # We only have u-boot-tpl, which be expanded
4772 self.assertIn('u-boot-tpl', entries)
4773 entry = entries['u-boot-tpl']
4774 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4775 subent = entry.GetEntries()
4776 self.assertEqual(3, len(subent))
4777 self.assertIn('u-boot-tpl-nodtb', subent)
4778 self.assertIn('u-boot-tpl-bss-pad', subent)
4779 self.assertIn('u-boot-tpl-dtb', subent)
4780
4781 def testExpandedNoPad(self):
4782 """Test an expanded entry without BSS pad enabled"""
4783 self._SetupSplElf()
4784 self._SetupTplElf()
4785
4786 # SPL has a devicetree, TPL does not
4787 entry_args = {
4788 'spl-dtb': 'something',
4789 'spl-bss-pad': 'n',
4790 'tpl-dtb': '',
4791 }
4792 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4793 entry_args=entry_args)
4794 image = control.images['image']
4795 entries = image.GetEntries()
4796
4797 # Just check u-boot-spl, which should be expanded into two parts
4798 self.assertIn('u-boot-spl', entries)
4799 entry = entries['u-boot-spl']
4800 self.assertEqual('u-boot-spl-expanded', entry.etype)
4801 subent = entry.GetEntries()
4802 self.assertEqual(2, len(subent))
4803 self.assertIn('u-boot-spl-nodtb', subent)
4804 self.assertIn('u-boot-spl-dtb', subent)
4805
4806 def testExpandedTplNoPad(self):
4807 """Test that an expanded entry type with padding disabled in TPL"""
4808 self._SetupTplElf()
4809
4810 entry_args = {
4811 'tpl-bss-pad': '',
4812 'tpl-dtb': 'y',
4813 }
4814 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4815 entry_args=entry_args)
4816 image = control.images['image']
4817 entries = image.GetEntries()
4818 self.assertEqual(1, len(entries))
4819
4820 # We only have u-boot-tpl, which be expanded
4821 self.assertIn('u-boot-tpl', entries)
4822 entry = entries['u-boot-tpl']
4823 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4824 subent = entry.GetEntries()
4825 self.assertEqual(2, len(subent))
4826 self.assertIn('u-boot-tpl-nodtb', subent)
4827 self.assertIn('u-boot-tpl-dtb', subent)
4828
4829 def testFdtInclude(self):
4830 """Test that an Fdt is update within all binaries"""
4831 self._SetupSplElf()
4832 self._SetupTplElf()
4833
4834 # SPL has a devicetree, TPL does not
4835 self.maxDiff = None
4836 entry_args = {
4837 'spl-dtb': '1',
4838 'spl-bss-pad': 'y',
4839 'tpl-dtb': '',
4840 }
4841 # Build the image. It includes two separate devicetree binaries, each
4842 # with their own contents, but all contain the binman definition.
4843 data = self._DoReadFileDtb(
4844 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4845 update_dtb=True, entry_args=entry_args)[0]
4846 pad_len = 10
4847
4848 # Check the U-Boot dtb
4849 start = len(U_BOOT_NODTB_DATA)
4850 fdt_size = self.checkDtbSizes(data, pad_len, start)
4851
4852 # Now check SPL
4853 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4854 fdt_size = self.checkDtbSizes(data, pad_len, start)
4855
4856 # TPL has no devicetree
4857 start += fdt_size + len(U_BOOT_TPL_DATA)
4858 self.assertEqual(len(data), start)
Simon Glass7d398bb2020-10-26 17:40:14 -06004859
Simon Glass3d433382021-03-21 18:24:30 +13004860 def testSymbolsExpanded(self):
4861 """Test binman can assign symbols in expanded entries"""
4862 entry_args = {
4863 'spl-dtb': '1',
4864 }
4865 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4866 U_BOOT_SPL_DTB_DATA, 0x38,
4867 entry_args=entry_args, use_expanded=True)
4868
Simon Glass189f2912021-03-21 18:24:31 +13004869 def testCollection(self):
4870 """Test a collection"""
4871 data = self._DoReadFile('198_collection.dts')
4872 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
Simon Glassc1aa66e2022-01-29 14:14:04 -07004873 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
4874 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
Simon Glass189f2912021-03-21 18:24:31 +13004875 data)
4876
Simon Glass631f7522021-03-21 18:24:32 +13004877 def testCollectionSection(self):
4878 """Test a collection where a section must be built first"""
4879 # Sections never have their contents when GetData() is called, but when
Simon Glassd34bcdd2021-11-23 11:03:47 -07004880 # BuildSectionData() is called with required=True, a section will force
Simon Glass631f7522021-03-21 18:24:32 +13004881 # building the contents, producing an error is anything is still
4882 # missing.
4883 data = self._DoReadFile('199_collection_section.dts')
4884 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
Simon Glassc1aa66e2022-01-29 14:14:04 -07004885 self.assertEqual(section + U_BOOT_DATA + tools.get_bytes(0xff, 2) +
4886 section + tools.get_bytes(0xfe, 3) + U_BOOT_DATA,
Simon Glass631f7522021-03-21 18:24:32 +13004887 data)
4888
Simon Glass5ff9fed2021-03-21 18:24:33 +13004889 def testAlignDefault(self):
4890 """Test that default alignment works on sections"""
4891 data = self._DoReadFile('200_align_default.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004892 expected = (U_BOOT_DATA + tools.get_bytes(0, 8 - len(U_BOOT_DATA)) +
Simon Glass5ff9fed2021-03-21 18:24:33 +13004893 U_BOOT_DATA)
4894 # Special alignment for section
Simon Glassc1aa66e2022-01-29 14:14:04 -07004895 expected += tools.get_bytes(0, 32 - len(expected))
Simon Glass5ff9fed2021-03-21 18:24:33 +13004896 # No alignment within the nested section
4897 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
4898 # Now the final piece, which should be default-aligned
Simon Glassc1aa66e2022-01-29 14:14:04 -07004899 expected += tools.get_bytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
Simon Glass5ff9fed2021-03-21 18:24:33 +13004900 self.assertEqual(expected, data)
Simon Glass631f7522021-03-21 18:24:32 +13004901
Bin Meng4c4d6072021-05-10 20:23:33 +08004902 def testPackOpenSBI(self):
4903 """Test that an image with an OpenSBI binary can be created"""
4904 data = self._DoReadFile('201_opensbi.dts')
4905 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
4906
Simon Glassc69d19c2021-07-06 10:36:37 -06004907 def testSectionsSingleThread(self):
4908 """Test sections without multithreading"""
4909 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
Simon Glassc1aa66e2022-01-29 14:14:04 -07004910 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4911 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
4912 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glassc69d19c2021-07-06 10:36:37 -06004913 self.assertEqual(expected, data)
4914
4915 def testThreadTimeout(self):
4916 """Test handling a thread that takes too long"""
4917 with self.assertRaises(ValueError) as e:
4918 self._DoTestFile('202_section_timeout.dts',
4919 test_section_timeout=True)
Simon Glassb2dfe832021-10-18 12:13:15 -06004920 self.assertIn("Timed out obtaining contents", str(e.exception))
Simon Glassc69d19c2021-07-06 10:36:37 -06004921
Simon Glass03ebc202021-07-06 10:36:41 -06004922 def testTiming(self):
4923 """Test output of timing information"""
4924 data = self._DoReadFile('055_sections.dts')
4925 with test_util.capture_sys_output() as (stdout, stderr):
4926 state.TimingShow()
4927 self.assertIn('read:', stdout.getvalue())
4928 self.assertIn('compress:', stdout.getvalue())
4929
Simon Glass0427bed2021-11-03 21:09:18 -06004930 def testUpdateFdtInElf(self):
4931 """Test that we can update the devicetree in an ELF file"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02004932 if not elf.ELF_TOOLS:
4933 self.skipTest('Python elftools not available')
Simon Glass0427bed2021-11-03 21:09:18 -06004934 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4935 outfile = os.path.join(self._indir, 'u-boot.out')
4936 begin_sym = 'dtb_embed_begin'
4937 end_sym = 'dtb_embed_end'
4938 retcode = self._DoTestFile(
4939 '060_fdt_update.dts', update_dtb=True,
4940 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4941 self.assertEqual(0, retcode)
4942
4943 # Check that the output file does in fact contact a dtb with the binman
4944 # definition in the correct place
4945 syms = elf.GetSymbolFileOffset(infile,
4946 ['dtb_embed_begin', 'dtb_embed_end'])
Simon Glassc1aa66e2022-01-29 14:14:04 -07004947 data = tools.read_file(outfile)
Simon Glass0427bed2021-11-03 21:09:18 -06004948 dtb_data = data[syms['dtb_embed_begin'].offset:
4949 syms['dtb_embed_end'].offset]
4950
4951 dtb = fdt.Fdt.FromData(dtb_data)
4952 dtb.Scan()
4953 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4954 self.assertEqual({
4955 'image-pos': 0,
4956 'offset': 0,
4957 '_testing:offset': 32,
4958 '_testing:size': 2,
4959 '_testing:image-pos': 32,
4960 'section@0/u-boot:offset': 0,
4961 'section@0/u-boot:size': len(U_BOOT_DATA),
4962 'section@0/u-boot:image-pos': 0,
4963 'section@0:offset': 0,
4964 'section@0:size': 16,
4965 'section@0:image-pos': 0,
4966
4967 'section@1/u-boot:offset': 0,
4968 'section@1/u-boot:size': len(U_BOOT_DATA),
4969 'section@1/u-boot:image-pos': 16,
4970 'section@1:offset': 16,
4971 'section@1:size': 16,
4972 'section@1:image-pos': 16,
4973 'size': 40
4974 }, props)
4975
4976 def testUpdateFdtInElfInvalid(self):
4977 """Test that invalid args are detected with --update-fdt-in-elf"""
4978 with self.assertRaises(ValueError) as e:
4979 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
4980 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
4981 str(e.exception))
4982
4983 def testUpdateFdtInElfNoSyms(self):
4984 """Test that missing symbols are detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02004985 if not elf.ELF_TOOLS:
4986 self.skipTest('Python elftools not available')
Simon Glass0427bed2021-11-03 21:09:18 -06004987 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4988 outfile = ''
4989 begin_sym = 'wrong_begin'
4990 end_sym = 'wrong_end'
4991 with self.assertRaises(ValueError) as e:
4992 self._DoTestFile(
4993 '060_fdt_update.dts',
4994 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4995 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
4996 str(e.exception))
4997
4998 def testUpdateFdtInElfTooSmall(self):
4999 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02005000 if not elf.ELF_TOOLS:
5001 self.skipTest('Python elftools not available')
Simon Glass0427bed2021-11-03 21:09:18 -06005002 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
5003 outfile = os.path.join(self._indir, 'u-boot.out')
5004 begin_sym = 'dtb_embed_begin'
5005 end_sym = 'dtb_embed_end'
5006 with self.assertRaises(ValueError) as e:
5007 self._DoTestFile(
5008 '060_fdt_update.dts', update_dtb=True,
5009 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5010 self.assertRegex(
5011 str(e.exception),
5012 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
5013
Simon Glassc475dec2021-11-23 11:03:42 -07005014 def testVersion(self):
5015 """Test we can get the binman version"""
5016 version = '(unreleased)'
5017 self.assertEqual(version, state.GetVersion(self._indir))
5018
5019 with self.assertRaises(SystemExit):
5020 with test_util.capture_sys_output() as (_, stderr):
5021 self._DoBinman('-V')
5022 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
5023
5024 # Try running the tool too, just to be safe
5025 result = self._RunBinman('-V')
5026 self.assertEqual('Binman %s\n' % version, result.stderr)
5027
5028 # Set up a version file to make sure that works
5029 version = 'v2025.01-rc2'
Simon Glassc1aa66e2022-01-29 14:14:04 -07005030 tools.write_file(os.path.join(self._indir, 'version'), version,
Simon Glassc475dec2021-11-23 11:03:42 -07005031 binary=False)
5032 self.assertEqual(version, state.GetVersion(self._indir))
5033
Simon Glass943bf782021-11-23 21:09:50 -07005034 def testAltFormat(self):
5035 """Test that alternative formats can be used to extract"""
5036 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
5037
5038 try:
5039 tmpdir, updated_fname = self._SetupImageInTmpdir()
5040 with test_util.capture_sys_output() as (stdout, _):
5041 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
5042 self.assertEqual(
5043 '''Flag (-F) Entry type Description
5044fdt fdtmap Extract the devicetree blob from the fdtmap
5045''',
5046 stdout.getvalue())
5047
5048 dtb = os.path.join(tmpdir, 'fdt.dtb')
5049 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
5050 dtb, 'fdtmap')
5051
5052 # Check that we can read it and it can be scanning, meaning it does
5053 # not have a 16-byte fdtmap header
Simon Glassc1aa66e2022-01-29 14:14:04 -07005054 data = tools.read_file(dtb)
Simon Glass943bf782021-11-23 21:09:50 -07005055 dtb = fdt.Fdt.FromData(data)
5056 dtb.Scan()
5057
5058 # Now check u-boot which has no alt_format
5059 fname = os.path.join(tmpdir, 'fdt.dtb')
5060 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
5061 '-f', fname, 'u-boot')
Simon Glassc1aa66e2022-01-29 14:14:04 -07005062 data = tools.read_file(fname)
Simon Glass943bf782021-11-23 21:09:50 -07005063 self.assertEqual(U_BOOT_DATA, data)
5064
5065 finally:
5066 shutil.rmtree(tmpdir)
5067
Simon Glasscc2c5002021-11-23 21:09:52 -07005068 def testExtblobList(self):
5069 """Test an image with an external blob list"""
5070 data = self._DoReadFile('215_blob_ext_list.dts')
5071 self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
5072
5073 def testExtblobListMissing(self):
5074 """Test an image with a missing external blob"""
5075 with self.assertRaises(ValueError) as e:
5076 self._DoReadFile('216_blob_ext_list_missing.dts')
5077 self.assertIn("Filename 'missing-file' not found in input path",
5078 str(e.exception))
5079
5080 def testExtblobListMissingOk(self):
5081 """Test an image with an missing external blob that is allowed"""
5082 with test_util.capture_sys_output() as (stdout, stderr):
5083 self._DoTestFile('216_blob_ext_list_missing.dts',
5084 allow_missing=True)
5085 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07005086 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glasscc2c5002021-11-23 21:09:52 -07005087
Simon Glass75989722021-11-23 21:08:59 -07005088 def testFip(self):
5089 """Basic test of generation of an ARM Firmware Image Package (FIP)"""
5090 data = self._DoReadFile('203_fip.dts')
5091 hdr, fents = fip_util.decode_fip(data)
5092 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5093 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5094 self.assertEqual(0x123, hdr.flags)
5095
5096 self.assertEqual(2, len(fents))
5097
5098 fent = fents[0]
5099 self.assertEqual(
5100 bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
5101 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
5102 self.assertEqual('soc-fw', fent.fip_type)
5103 self.assertEqual(0x88, fent.offset)
5104 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5105 self.assertEqual(0x123456789abcdef, fent.flags)
5106 self.assertEqual(ATF_BL31_DATA, fent.data)
5107 self.assertEqual(True, fent.valid)
5108
5109 fent = fents[1]
5110 self.assertEqual(
5111 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
5112 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
5113 self.assertEqual('scp-fwu-cfg', fent.fip_type)
5114 self.assertEqual(0x8c, fent.offset)
5115 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5116 self.assertEqual(0, fent.flags)
5117 self.assertEqual(ATF_BL2U_DATA, fent.data)
5118 self.assertEqual(True, fent.valid)
5119
5120 def testFipOther(self):
5121 """Basic FIP with something that isn't a external blob"""
5122 data = self._DoReadFile('204_fip_other.dts')
5123 hdr, fents = fip_util.decode_fip(data)
5124
5125 self.assertEqual(2, len(fents))
5126 fent = fents[1]
5127 self.assertEqual('rot-cert', fent.fip_type)
5128 self.assertEqual(b'aa', fent.data)
5129
Simon Glass75989722021-11-23 21:08:59 -07005130 def testFipNoType(self):
5131 """FIP with an entry of an unknown type"""
5132 with self.assertRaises(ValueError) as e:
5133 self._DoReadFile('205_fip_no_type.dts')
5134 self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
5135 str(e.exception))
5136
5137 def testFipUuid(self):
5138 """Basic FIP with a manual uuid"""
5139 data = self._DoReadFile('206_fip_uuid.dts')
5140 hdr, fents = fip_util.decode_fip(data)
5141
5142 self.assertEqual(2, len(fents))
5143 fent = fents[1]
5144 self.assertEqual(None, fent.fip_type)
5145 self.assertEqual(
5146 bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
5147 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
5148 fent.uuid)
5149 self.assertEqual(U_BOOT_DATA, fent.data)
5150
5151 def testFipLs(self):
5152 """Test listing a FIP"""
5153 data = self._DoReadFileRealDtb('207_fip_ls.dts')
5154 hdr, fents = fip_util.decode_fip(data)
5155
5156 try:
5157 tmpdir, updated_fname = self._SetupImageInTmpdir()
5158 with test_util.capture_sys_output() as (stdout, stderr):
5159 self._DoBinman('ls', '-i', updated_fname)
5160 finally:
5161 shutil.rmtree(tmpdir)
5162 lines = stdout.getvalue().splitlines()
5163 expected = [
Simon Glass193d3db2023-02-07 14:34:18 -07005164'Name Image-pos Size Entry-type Offset Uncomp-size',
5165'--------------------------------------------------------------',
5166'image 0 2d3 section 0',
5167' atf-fip 0 90 atf-fip 0',
5168' soc-fw 88 4 blob-ext 88',
5169' u-boot 8c 4 u-boot 8c',
5170' fdtmap 90 243 fdtmap 90',
Simon Glass75989722021-11-23 21:08:59 -07005171]
5172 self.assertEqual(expected, lines)
5173
5174 image = control.images['image']
5175 entries = image.GetEntries()
5176 fdtmap = entries['fdtmap']
5177
5178 fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
5179 magic = fdtmap_data[:8]
5180 self.assertEqual(b'_FDTMAP_', magic)
Simon Glassc1aa66e2022-01-29 14:14:04 -07005181 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass75989722021-11-23 21:08:59 -07005182
5183 fdt_data = fdtmap_data[16:]
5184 dtb = fdt.Fdt.FromData(fdt_data)
5185 dtb.Scan()
5186 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
5187 self.assertEqual({
5188 'atf-fip/soc-fw:image-pos': 136,
5189 'atf-fip/soc-fw:offset': 136,
5190 'atf-fip/soc-fw:size': 4,
5191 'atf-fip/u-boot:image-pos': 140,
5192 'atf-fip/u-boot:offset': 140,
5193 'atf-fip/u-boot:size': 4,
5194 'atf-fip:image-pos': 0,
5195 'atf-fip:offset': 0,
5196 'atf-fip:size': 144,
5197 'image-pos': 0,
5198 'offset': 0,
5199 'fdtmap:image-pos': fdtmap.image_pos,
5200 'fdtmap:offset': fdtmap.offset,
5201 'fdtmap:size': len(fdtmap_data),
5202 'size': len(data),
5203 }, props)
5204
5205 def testFipExtractOneEntry(self):
5206 """Test extracting a single entry fron an FIP"""
5207 self._DoReadFileRealDtb('207_fip_ls.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07005208 image_fname = tools.get_output_filename('image.bin')
Simon Glass75989722021-11-23 21:08:59 -07005209 fname = os.path.join(self._indir, 'output.extact')
5210 control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
Simon Glassc1aa66e2022-01-29 14:14:04 -07005211 data = tools.read_file(fname)
Simon Glass75989722021-11-23 21:08:59 -07005212 self.assertEqual(U_BOOT_DATA, data)
5213
5214 def testFipReplace(self):
5215 """Test replacing a single file in a FIP"""
Simon Glassc1aa66e2022-01-29 14:14:04 -07005216 expected = U_BOOT_DATA + tools.get_bytes(0x78, 50)
Simon Glass75989722021-11-23 21:08:59 -07005217 data = self._DoReadFileRealDtb('208_fip_replace.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07005218 updated_fname = tools.get_output_filename('image-updated.bin')
5219 tools.write_file(updated_fname, data)
Simon Glass75989722021-11-23 21:08:59 -07005220 entry_name = 'atf-fip/u-boot'
5221 control.WriteEntry(updated_fname, entry_name, expected,
5222 allow_resize=True)
5223 actual = control.ReadEntry(updated_fname, entry_name)
5224 self.assertEqual(expected, actual)
5225
Simon Glassc1aa66e2022-01-29 14:14:04 -07005226 new_data = tools.read_file(updated_fname)
Simon Glass75989722021-11-23 21:08:59 -07005227 hdr, fents = fip_util.decode_fip(new_data)
5228
5229 self.assertEqual(2, len(fents))
5230
5231 # Check that the FIP entry is updated
5232 fent = fents[1]
5233 self.assertEqual(0x8c, fent.offset)
5234 self.assertEqual(len(expected), fent.size)
5235 self.assertEqual(0, fent.flags)
5236 self.assertEqual(expected, fent.data)
5237 self.assertEqual(True, fent.valid)
5238
5239 def testFipMissing(self):
5240 with test_util.capture_sys_output() as (stdout, stderr):
5241 self._DoTestFile('209_fip_missing.dts', allow_missing=True)
5242 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07005243 self.assertRegex(err, "Image 'image'.*missing.*: rmm-fw")
Simon Glass75989722021-11-23 21:08:59 -07005244
5245 def testFipSize(self):
5246 """Test a FIP with a size property"""
5247 data = self._DoReadFile('210_fip_size.dts')
5248 self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
5249 hdr, fents = fip_util.decode_fip(data)
5250 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5251 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5252
5253 self.assertEqual(1, len(fents))
5254
5255 fent = fents[0]
5256 self.assertEqual('soc-fw', fent.fip_type)
5257 self.assertEqual(0x60, fent.offset)
5258 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5259 self.assertEqual(ATF_BL31_DATA, fent.data)
5260 self.assertEqual(True, fent.valid)
5261
5262 rest = data[0x60 + len(ATF_BL31_DATA):0x100]
Simon Glassc1aa66e2022-01-29 14:14:04 -07005263 self.assertEqual(tools.get_bytes(0xff, len(rest)), rest)
Simon Glass75989722021-11-23 21:08:59 -07005264
5265 def testFipBadAlign(self):
5266 """Test that an invalid alignment value in a FIP is detected"""
5267 with self.assertRaises(ValueError) as e:
5268 self._DoTestFile('211_fip_bad_align.dts')
5269 self.assertIn(
5270 "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
5271 str(e.exception))
5272
5273 def testFipCollection(self):
5274 """Test using a FIP in a collection"""
5275 data = self._DoReadFile('212_fip_collection.dts')
5276 entry1 = control.images['image'].GetEntries()['collection']
5277 data1 = data[:entry1.size]
5278 hdr1, fents2 = fip_util.decode_fip(data1)
5279
5280 entry2 = control.images['image'].GetEntries()['atf-fip']
5281 data2 = data[entry2.offset:entry2.offset + entry2.size]
5282 hdr1, fents2 = fip_util.decode_fip(data2)
5283
5284 # The 'collection' entry should have U-Boot included at the end
5285 self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
5286 self.assertEqual(data1, data2 + U_BOOT_DATA)
5287 self.assertEqual(U_BOOT_DATA, data1[-4:])
5288
5289 # There should be a U-Boot after the final FIP
5290 self.assertEqual(U_BOOT_DATA, data[-4:])
Simon Glassc69d19c2021-07-06 10:36:37 -06005291
Simon Glass32d4f102022-01-12 13:10:35 -07005292 def testFakeBlob(self):
5293 """Test handling of faking an external blob"""
5294 with test_util.capture_sys_output() as (stdout, stderr):
5295 self._DoTestFile('217_fake_blob.dts', allow_missing=True,
5296 allow_fake_blobs=True)
5297 err = stderr.getvalue()
5298 self.assertRegex(
5299 err,
5300 "Image '.*' has faked external blobs and is non-functional: .*")
Simon Glass32d4f102022-01-12 13:10:35 -07005301
Simon Glassf4590e02022-01-09 20:13:46 -07005302 def testExtblobListFaked(self):
5303 """Test an extblob with missing external blob that are faked"""
5304 with test_util.capture_sys_output() as (stdout, stderr):
5305 self._DoTestFile('216_blob_ext_list_missing.dts',
5306 allow_fake_blobs=True)
5307 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07005308 self.assertRegex(err, "Image 'image'.*faked.*: blob-ext-list")
Simon Glassf4590e02022-01-09 20:13:46 -07005309
Simon Glass56ee85e2022-01-09 20:13:57 -07005310 def testListBintools(self):
5311 args = ['tool', '--list']
5312 with test_util.capture_sys_output() as (stdout, _):
5313 self._DoBinman(*args)
5314 out = stdout.getvalue().splitlines()
5315 self.assertTrue(len(out) >= 2)
5316
5317 def testFetchBintools(self):
5318 def fail_download(url):
Simon Glassc1aa66e2022-01-29 14:14:04 -07005319 """Take the tools.download() function by raising an exception"""
Simon Glass56ee85e2022-01-09 20:13:57 -07005320 raise urllib.error.URLError('my error')
5321
5322 args = ['tool']
5323 with self.assertRaises(ValueError) as e:
5324 self._DoBinman(*args)
5325 self.assertIn("Invalid arguments to 'tool' subcommand",
5326 str(e.exception))
5327
5328 args = ['tool', '--fetch']
5329 with self.assertRaises(ValueError) as e:
5330 self._DoBinman(*args)
5331 self.assertIn('Please specify bintools to fetch', str(e.exception))
5332
5333 args = ['tool', '--fetch', '_testing']
Simon Glassc1aa66e2022-01-29 14:14:04 -07005334 with unittest.mock.patch.object(tools, 'download',
Simon Glass56ee85e2022-01-09 20:13:57 -07005335 side_effect=fail_download):
5336 with test_util.capture_sys_output() as (stdout, _):
5337 self._DoBinman(*args)
5338 self.assertIn('failed to fetch with all methods', stdout.getvalue())
5339
Simon Glassbc570642022-01-09 20:14:11 -07005340 def testBintoolDocs(self):
5341 """Test for creation of bintool documentation"""
5342 with test_util.capture_sys_output() as (stdout, stderr):
5343 control.write_bintool_docs(control.bintool.Bintool.get_tool_list())
5344 self.assertTrue(len(stdout.getvalue()) > 0)
5345
5346 def testBintoolDocsMissing(self):
5347 """Test handling of missing bintool documentation"""
5348 with self.assertRaises(ValueError) as e:
5349 with test_util.capture_sys_output() as (stdout, stderr):
5350 control.write_bintool_docs(
5351 control.bintool.Bintool.get_tool_list(), 'mkimage')
5352 self.assertIn('Documentation is missing for modules: mkimage',
5353 str(e.exception))
5354
Jan Kiszkafcc87ef2022-01-28 20:37:53 +01005355 def testListWithGenNode(self):
5356 """Check handling of an FDT map when the section cannot be found"""
5357 entry_args = {
5358 'of-list': 'test-fdt1 test-fdt2',
5359 }
5360 data = self._DoReadFileDtb(
5361 '219_fit_gennode.dts',
5362 entry_args=entry_args,
5363 use_real_dtb=True,
5364 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])
5365
5366 try:
5367 tmpdir, updated_fname = self._SetupImageInTmpdir()
5368 with test_util.capture_sys_output() as (stdout, stderr):
5369 self._RunBinman('ls', '-i', updated_fname)
5370 finally:
5371 shutil.rmtree(tmpdir)
5372
Alper Nebi Yasaked293c32022-02-08 01:08:05 +03005373 def testFitSubentryUsesBintool(self):
5374 """Test that binman FIT subentries can use bintools"""
5375 command.test_result = self._HandleGbbCommand
5376 entry_args = {
5377 'keydir': 'devkeys',
5378 'bmpblk': 'bmpblk.bin',
5379 }
5380 data, _, _, _ = self._DoReadFileDtb('220_fit_subentry_bintool.dts',
5381 entry_args=entry_args)
5382
Alper Nebi Yasakf3078d42022-02-08 01:08:07 +03005383 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
5384 tools.get_bytes(0, 0x2180 - 16))
Alper Nebi Yasaked293c32022-02-08 01:08:05 +03005385 self.assertIn(expected, data)
5386
5387 def testFitSubentryMissingBintool(self):
5388 """Test that binman reports missing bintools for FIT subentries"""
5389 entry_args = {
5390 'keydir': 'devkeys',
5391 }
5392 with test_util.capture_sys_output() as (_, stderr):
5393 self._DoTestFile('220_fit_subentry_bintool.dts',
5394 force_missing_bintools='futility', entry_args=entry_args)
5395 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07005396 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass32d4f102022-01-12 13:10:35 -07005397
Alper Nebi Yasakee813c82022-02-09 22:02:35 +03005398 def testFitSubentryHashSubnode(self):
5399 """Test an image with a FIT inside"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06005400 self._SetupSplElf()
Alper Nebi Yasakee813c82022-02-09 22:02:35 +03005401 data, _, _, out_dtb_name = self._DoReadFileDtb(
5402 '221_fit_subentry_hash.dts', use_real_dtb=True, update_dtb=True)
5403
5404 mkimage_dtb = fdt.Fdt.FromData(data)
5405 mkimage_dtb.Scan()
5406 binman_dtb = fdt.Fdt(out_dtb_name)
5407 binman_dtb.Scan()
5408
5409 # Check that binman didn't add hash values
5410 fnode = binman_dtb.GetNode('/binman/fit/images/kernel/hash')
5411 self.assertNotIn('value', fnode.props)
5412
5413 fnode = binman_dtb.GetNode('/binman/fit/images/fdt-1/hash')
5414 self.assertNotIn('value', fnode.props)
5415
5416 # Check that mkimage added hash values
5417 fnode = mkimage_dtb.GetNode('/images/kernel/hash')
5418 self.assertIn('value', fnode.props)
5419
5420 fnode = mkimage_dtb.GetNode('/images/fdt-1/hash')
5421 self.assertIn('value', fnode.props)
5422
Roger Quadros47f420a2022-02-19 20:50:04 +02005423 def testPackTeeOs(self):
5424 """Test that an image with an TEE binary can be created"""
5425 data = self._DoReadFile('222_tee_os.dts')
5426 self.assertEqual(TEE_OS_DATA, data[:len(TEE_OS_DATA)])
5427
Simon Glass6a0b5f82022-02-08 11:50:03 -07005428 def testFitFdtOper(self):
5429 """Check handling of a specified FIT operation"""
5430 entry_args = {
5431 'of-list': 'test-fdt1 test-fdt2',
5432 'default-dt': 'test-fdt2',
5433 }
5434 self._DoReadFileDtb(
5435 '223_fit_fdt_oper.dts',
5436 entry_args=entry_args,
5437 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
5438
5439 def testFitFdtBadOper(self):
5440 """Check handling of an FDT map when the section cannot be found"""
5441 with self.assertRaises(ValueError) as exc:
5442 self._DoReadFileDtb('224_fit_bad_oper.dts')
Simon Glassce4e4022022-03-05 20:19:09 -07005443 self.assertIn("Node '/binman/fit': subnode 'images/@fdt-SEQ': Unknown operation 'unknown'",
Simon Glass6a0b5f82022-02-08 11:50:03 -07005444 str(exc.exception))
5445
Simon Glass80a66ae2022-03-05 20:18:59 -07005446 def test_uses_expand_size(self):
5447 """Test that the 'expand-size' property cannot be used anymore"""
5448 with self.assertRaises(ValueError) as e:
5449 data = self._DoReadFile('225_expand_size_bad.dts')
5450 self.assertIn(
5451 "Node '/binman/u-boot': Please use 'extend-size' instead of 'expand-size'",
5452 str(e.exception))
5453
Simon Glass40c8bdd2022-03-05 20:19:12 -07005454 def testFitSplitElf(self):
5455 """Test an image with an FIT with an split-elf operation"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02005456 if not elf.ELF_TOOLS:
5457 self.skipTest('Python elftools not available')
Simon Glass40c8bdd2022-03-05 20:19:12 -07005458 entry_args = {
5459 'of-list': 'test-fdt1 test-fdt2',
5460 'default-dt': 'test-fdt2',
5461 'atf-bl31-path': 'bl31.elf',
5462 'tee-os-path': 'tee.elf',
5463 }
5464 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5465 data = self._DoReadFileDtb(
5466 '226_fit_split_elf.dts',
5467 entry_args=entry_args,
5468 extra_indirs=[test_subdir])[0]
5469
5470 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
5471 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
5472
5473 base_keys = {'description', 'type', 'arch', 'os', 'compression',
5474 'data', 'load'}
5475 dtb = fdt.Fdt.FromData(fit_data)
5476 dtb.Scan()
5477
5478 elf_data = tools.read_file(os.path.join(self._indir, 'bl31.elf'))
5479 segments, entry = elf.read_loadable_segments(elf_data)
5480
5481 # We assume there are two segments
5482 self.assertEquals(2, len(segments))
5483
5484 atf1 = dtb.GetNode('/images/atf-1')
5485 _, start, data = segments[0]
5486 self.assertEqual(base_keys | {'entry'}, atf1.props.keys())
5487 self.assertEqual(entry,
5488 fdt_util.fdt32_to_cpu(atf1.props['entry'].value))
5489 self.assertEqual(start,
5490 fdt_util.fdt32_to_cpu(atf1.props['load'].value))
5491 self.assertEqual(data, atf1.props['data'].bytes)
5492
Jonas Karlman00b3d532023-01-21 19:01:48 +00005493 hash_node = atf1.FindNode('hash')
5494 self.assertIsNotNone(hash_node)
5495 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5496
Simon Glass40c8bdd2022-03-05 20:19:12 -07005497 atf2 = dtb.GetNode('/images/atf-2')
5498 self.assertEqual(base_keys, atf2.props.keys())
5499 _, start, data = segments[1]
5500 self.assertEqual(start,
5501 fdt_util.fdt32_to_cpu(atf2.props['load'].value))
5502 self.assertEqual(data, atf2.props['data'].bytes)
5503
Jonas Karlman00b3d532023-01-21 19:01:48 +00005504 hash_node = atf2.FindNode('hash')
5505 self.assertIsNotNone(hash_node)
5506 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5507
5508 hash_node = dtb.GetNode('/images/tee-1/hash-1')
5509 self.assertIsNotNone(hash_node)
5510 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5511
Simon Glass40c8bdd2022-03-05 20:19:12 -07005512 conf = dtb.GetNode('/configurations')
5513 self.assertEqual({'default'}, conf.props.keys())
5514
5515 for subnode in conf.subnodes:
5516 self.assertEqual({'description', 'fdt', 'loadables'},
5517 subnode.props.keys())
5518 self.assertEqual(
5519 ['atf-1', 'atf-2', 'tee-1', 'tee-2'],
5520 fdt_util.GetStringList(subnode, 'loadables'))
5521
5522 def _check_bad_fit(self, dts):
5523 """Check a bad FIT
5524
5525 This runs with the given dts and returns the assertion raised
5526
5527 Args:
5528 dts (str): dts filename to use
5529
5530 Returns:
5531 str: Assertion string raised
5532 """
5533 entry_args = {
5534 'of-list': 'test-fdt1 test-fdt2',
5535 'default-dt': 'test-fdt2',
5536 'atf-bl31-path': 'bl31.elf',
5537 'tee-os-path': 'tee.elf',
5538 }
5539 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5540 with self.assertRaises(ValueError) as exc:
5541 self._DoReadFileDtb(dts, entry_args=entry_args,
5542 extra_indirs=[test_subdir])[0]
5543 return str(exc.exception)
5544
5545 def testFitSplitElfBadElf(self):
5546 """Test a FIT split-elf operation with an invalid ELF file"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02005547 if not elf.ELF_TOOLS:
5548 self.skipTest('Python elftools not available')
Simon Glass40c8bdd2022-03-05 20:19:12 -07005549 TestFunctional._MakeInputFile('bad.elf', tools.get_bytes(100, 100))
5550 entry_args = {
5551 'of-list': 'test-fdt1 test-fdt2',
5552 'default-dt': 'test-fdt2',
5553 'atf-bl31-path': 'bad.elf',
5554 'tee-os-path': 'tee.elf',
5555 }
5556 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5557 with self.assertRaises(ValueError) as exc:
5558 self._DoReadFileDtb(
5559 '226_fit_split_elf.dts',
5560 entry_args=entry_args,
5561 extra_indirs=[test_subdir])[0]
5562 self.assertIn(
5563 "Node '/binman/fit': subnode 'images/@atf-SEQ': Failed to read ELF file: Magic number does not match",
5564 str(exc.exception))
5565
Simon Glass40c8bdd2022-03-05 20:19:12 -07005566 def checkFitSplitElf(self, **kwargs):
Simon Glass7960a0a2022-08-07 09:46:46 -06005567 """Test an split-elf FIT with a missing ELF file
5568
5569 Args:
5570 kwargs (dict of str): Arguments to pass to _DoTestFile()
5571
5572 Returns:
5573 tuple:
5574 str: stdout result
5575 str: stderr result
5576 """
Simon Glass40c8bdd2022-03-05 20:19:12 -07005577 entry_args = {
5578 'of-list': 'test-fdt1 test-fdt2',
5579 'default-dt': 'test-fdt2',
5580 'atf-bl31-path': 'bl31.elf',
5581 'tee-os-path': 'missing.elf',
5582 }
5583 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5584 with test_util.capture_sys_output() as (stdout, stderr):
5585 self._DoTestFile(
5586 '226_fit_split_elf.dts', entry_args=entry_args,
Simon Glass7960a0a2022-08-07 09:46:46 -06005587 extra_indirs=[test_subdir], verbosity=3, **kwargs)
5588 out = stdout.getvalue()
5589 err = stderr.getvalue()
5590 return out, err
Simon Glass40c8bdd2022-03-05 20:19:12 -07005591
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005592 def testFitSplitElfBadDirective(self):
5593 """Test a FIT split-elf invalid fit,xxx directive in an image node"""
5594 if not elf.ELF_TOOLS:
5595 self.skipTest('Python elftools not available')
5596 err = self._check_bad_fit('227_fit_bad_dir.dts')
5597 self.assertIn(
5598 "Node '/binman/fit': subnode 'images/@atf-SEQ': Unknown directive 'fit,something'",
5599 err)
5600
5601 def testFitSplitElfBadDirectiveConfig(self):
5602 """Test a FIT split-elf with invalid fit,xxx directive in config"""
5603 if not elf.ELF_TOOLS:
5604 self.skipTest('Python elftools not available')
5605 err = self._check_bad_fit('228_fit_bad_dir_config.dts')
5606 self.assertEqual(
5607 "Node '/binman/fit': subnode 'configurations/@config-SEQ': Unknown directive 'fit,config'",
5608 err)
5609
5610
Simon Glass40c8bdd2022-03-05 20:19:12 -07005611 def testFitSplitElfMissing(self):
5612 """Test an split-elf FIT with a missing ELF file"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02005613 if not elf.ELF_TOOLS:
5614 self.skipTest('Python elftools not available')
Simon Glass7960a0a2022-08-07 09:46:46 -06005615 out, err = self.checkFitSplitElf(allow_missing=True)
Simon Glass40c8bdd2022-03-05 20:19:12 -07005616 self.assertRegex(
5617 err,
5618 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7960a0a2022-08-07 09:46:46 -06005619 self.assertNotRegex(out, '.*Faked blob.*')
5620 fname = tools.get_output_filename('binman-fake/missing.elf')
5621 self.assertFalse(os.path.exists(fname))
Simon Glass40c8bdd2022-03-05 20:19:12 -07005622
5623 def testFitSplitElfFaked(self):
5624 """Test an split-elf FIT with faked ELF file"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02005625 if not elf.ELF_TOOLS:
5626 self.skipTest('Python elftools not available')
Simon Glass7960a0a2022-08-07 09:46:46 -06005627 out, err = self.checkFitSplitElf(allow_missing=True, allow_fake_blobs=True)
Simon Glass40c8bdd2022-03-05 20:19:12 -07005628 self.assertRegex(
5629 err,
5630 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7960a0a2022-08-07 09:46:46 -06005631 self.assertRegex(
5632 out,
5633 "Entry '/binman/fit/images/@tee-SEQ/tee-os': Faked blob '.*binman-fake/missing.elf")
5634 fname = tools.get_output_filename('binman-fake/missing.elf')
5635 self.assertTrue(os.path.exists(fname))
Simon Glass40c8bdd2022-03-05 20:19:12 -07005636
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005637 def testMkimageMissingBlob(self):
5638 """Test using mkimage to build an image"""
5639 with test_util.capture_sys_output() as (stdout, stderr):
5640 self._DoTestFile('229_mkimage_missing.dts', allow_missing=True,
5641 allow_fake_blobs=True)
5642 err = stderr.getvalue()
5643 self.assertRegex(
5644 err,
5645 "Image '.*' has faked external blobs and is non-functional: .*")
5646
Philippe Reynesb1c50932022-03-28 22:57:04 +02005647 def testPreLoad(self):
5648 """Test an image with a pre-load header"""
5649 entry_args = {
Simon Glassefda8ab2023-07-24 09:19:57 -06005650 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
Philippe Reynesb1c50932022-03-28 22:57:04 +02005651 }
Simon Glassefda8ab2023-07-24 09:19:57 -06005652 data = self._DoReadFileDtb(
5653 '230_pre_load.dts', entry_args=entry_args,
5654 extra_indirs=[os.path.join(self._binman_dir, 'test')])[0]
Philippe Reynesb1c50932022-03-28 22:57:04 +02005655 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5656 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5657 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5658
Simon Glassefda8ab2023-07-24 09:19:57 -06005659 def testPreLoadNoKey(self):
5660 """Test an image with a pre-load heade0r with missing key"""
5661 with self.assertRaises(FileNotFoundError) as exc:
5662 self._DoReadFile('230_pre_load.dts')
5663 self.assertIn("No such file or directory: 'dev.key'",
5664 str(exc.exception))
5665
Philippe Reynesb1c50932022-03-28 22:57:04 +02005666 def testPreLoadPkcs(self):
5667 """Test an image with a pre-load header with padding pkcs"""
Simon Glassefda8ab2023-07-24 09:19:57 -06005668 entry_args = {
5669 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5670 }
5671 data = self._DoReadFileDtb('231_pre_load_pkcs.dts',
5672 entry_args=entry_args)[0]
Philippe Reynesb1c50932022-03-28 22:57:04 +02005673 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5674 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5675 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5676
5677 def testPreLoadPss(self):
5678 """Test an image with a pre-load header with padding pss"""
Simon Glassefda8ab2023-07-24 09:19:57 -06005679 entry_args = {
5680 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5681 }
5682 data = self._DoReadFileDtb('232_pre_load_pss.dts',
5683 entry_args=entry_args)[0]
Philippe Reynesb1c50932022-03-28 22:57:04 +02005684 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5685 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5686 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5687
5688 def testPreLoadInvalidPadding(self):
5689 """Test an image with a pre-load header with an invalid padding"""
Simon Glassefda8ab2023-07-24 09:19:57 -06005690 entry_args = {
5691 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5692 }
Philippe Reynesb1c50932022-03-28 22:57:04 +02005693 with self.assertRaises(ValueError) as e:
Simon Glassefda8ab2023-07-24 09:19:57 -06005694 self._DoReadFileDtb('233_pre_load_invalid_padding.dts',
5695 entry_args=entry_args)
Philippe Reynesb1c50932022-03-28 22:57:04 +02005696
5697 def testPreLoadInvalidSha(self):
5698 """Test an image with a pre-load header with an invalid hash"""
Simon Glassefda8ab2023-07-24 09:19:57 -06005699 entry_args = {
5700 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5701 }
Philippe Reynesb1c50932022-03-28 22:57:04 +02005702 with self.assertRaises(ValueError) as e:
Simon Glassefda8ab2023-07-24 09:19:57 -06005703 self._DoReadFileDtb('234_pre_load_invalid_sha.dts',
5704 entry_args=entry_args)
Philippe Reynesb1c50932022-03-28 22:57:04 +02005705
5706 def testPreLoadInvalidAlgo(self):
5707 """Test an image with a pre-load header with an invalid algo"""
5708 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005709 data = self._DoReadFile('235_pre_load_invalid_algo.dts')
Philippe Reynesb1c50932022-03-28 22:57:04 +02005710
5711 def testPreLoadInvalidKey(self):
5712 """Test an image with a pre-load header with an invalid key"""
Simon Glassefda8ab2023-07-24 09:19:57 -06005713 entry_args = {
5714 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5715 }
Philippe Reynesb1c50932022-03-28 22:57:04 +02005716 with self.assertRaises(ValueError) as e:
Simon Glassefda8ab2023-07-24 09:19:57 -06005717 data = self._DoReadFileDtb('236_pre_load_invalid_key.dts',
5718 entry_args=entry_args)
Roger Quadros47f420a2022-02-19 20:50:04 +02005719
Alper Nebi Yasak67bf2c82022-03-27 18:31:44 +03005720 def _CheckSafeUniqueNames(self, *images):
5721 """Check all entries of given images for unsafe unique names"""
5722 for image in images:
5723 entries = {}
5724 image._CollectEntries(entries, {}, image)
5725 for entry in entries.values():
5726 uniq = entry.GetUniqueName()
5727
5728 # Used as part of a filename, so must not be absolute paths.
5729 self.assertFalse(os.path.isabs(uniq))
5730
5731 def testSafeUniqueNames(self):
5732 """Test entry unique names are safe in single image configuration"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005733 data = self._DoReadFileRealDtb('237_unique_names.dts')
Alper Nebi Yasak67bf2c82022-03-27 18:31:44 +03005734
5735 orig_image = control.images['image']
5736 image_fname = tools.get_output_filename('image.bin')
5737 image = Image.FromFile(image_fname)
5738
5739 self._CheckSafeUniqueNames(orig_image, image)
5740
5741 def testSafeUniqueNamesMulti(self):
5742 """Test entry unique names are safe with multiple images"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005743 data = self._DoReadFileRealDtb('238_unique_names_multi.dts')
Alper Nebi Yasak67bf2c82022-03-27 18:31:44 +03005744
5745 orig_image = control.images['image']
5746 image_fname = tools.get_output_filename('image.bin')
5747 image = Image.FromFile(image_fname)
5748
5749 self._CheckSafeUniqueNames(orig_image, image)
5750
Alper Nebi Yasak8ee4ec92022-03-27 18:31:45 +03005751 def testReplaceCmdWithBintool(self):
5752 """Test replacing an entry that needs a bintool to pack"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005753 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasak8ee4ec92022-03-27 18:31:45 +03005754 expected = U_BOOT_DATA + b'aa'
5755 self.assertEqual(expected, data[:len(expected)])
5756
5757 try:
5758 tmpdir, updated_fname = self._SetupImageInTmpdir()
5759 fname = os.path.join(tmpdir, 'update-testing.bin')
5760 tools.write_file(fname, b'zz')
5761 self._DoBinman('replace', '-i', updated_fname,
5762 '_testing', '-f', fname)
5763
5764 data = tools.read_file(updated_fname)
5765 expected = U_BOOT_DATA + b'zz'
5766 self.assertEqual(expected, data[:len(expected)])
5767 finally:
5768 shutil.rmtree(tmpdir)
5769
5770 def testReplaceCmdOtherWithBintool(self):
5771 """Test replacing an entry when another needs a bintool to pack"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005772 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasak8ee4ec92022-03-27 18:31:45 +03005773 expected = U_BOOT_DATA + b'aa'
5774 self.assertEqual(expected, data[:len(expected)])
5775
5776 try:
5777 tmpdir, updated_fname = self._SetupImageInTmpdir()
5778 fname = os.path.join(tmpdir, 'update-u-boot.bin')
5779 tools.write_file(fname, b'x' * len(U_BOOT_DATA))
5780 self._DoBinman('replace', '-i', updated_fname,
5781 'u-boot', '-f', fname)
5782
5783 data = tools.read_file(updated_fname)
5784 expected = b'x' * len(U_BOOT_DATA) + b'aa'
5785 self.assertEqual(expected, data[:len(expected)])
5786 finally:
5787 shutil.rmtree(tmpdir)
5788
Alper Nebi Yasake2ce4fb2022-03-27 18:31:46 +03005789 def testReplaceResizeNoRepackSameSize(self):
5790 """Test replacing entries with same-size data without repacking"""
5791 expected = b'x' * len(U_BOOT_DATA)
5792 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected)
5793 self.assertEqual(expected, data)
5794
5795 path, fdtmap = state.GetFdtContents('fdtmap')
5796 self.assertIsNotNone(path)
5797 self.assertEqual(expected_fdtmap, fdtmap)
5798
5799 def testReplaceResizeNoRepackSmallerSize(self):
5800 """Test replacing entries with smaller-size data without repacking"""
5801 new_data = b'x'
5802 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', new_data)
5803 expected = new_data.ljust(len(U_BOOT_DATA), b'\0')
5804 self.assertEqual(expected, data)
5805
5806 path, fdtmap = state.GetFdtContents('fdtmap')
5807 self.assertIsNotNone(path)
5808 self.assertEqual(expected_fdtmap, fdtmap)
5809
Alper Nebi Yasak74d3b232022-03-27 18:31:48 +03005810 def testExtractFit(self):
5811 """Test extracting a FIT section"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005812 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak74d3b232022-03-27 18:31:48 +03005813 image_fname = tools.get_output_filename('image.bin')
5814
5815 fit_data = control.ReadEntry(image_fname, 'fit')
5816 fit = fdt.Fdt.FromData(fit_data)
5817 fit.Scan()
5818
5819 # Check subentry data inside the extracted fit
5820 for node_path, expected in [
5821 ('/images/kernel', U_BOOT_DATA),
5822 ('/images/fdt-1', U_BOOT_NODTB_DATA),
5823 ('/images/scr-1', COMPRESS_DATA),
5824 ]:
5825 node = fit.GetNode(node_path)
5826 data = fit.GetProps(node)['data'].bytes
5827 self.assertEqual(expected, data)
5828
5829 def testExtractFitSubentries(self):
5830 """Test extracting FIT section subentries"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005831 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak74d3b232022-03-27 18:31:48 +03005832 image_fname = tools.get_output_filename('image.bin')
5833
5834 for entry_path, expected in [
5835 ('fit/kernel', U_BOOT_DATA),
5836 ('fit/kernel/u-boot', U_BOOT_DATA),
5837 ('fit/fdt-1', U_BOOT_NODTB_DATA),
5838 ('fit/fdt-1/u-boot-nodtb', U_BOOT_NODTB_DATA),
5839 ('fit/scr-1', COMPRESS_DATA),
5840 ('fit/scr-1/blob', COMPRESS_DATA),
5841 ]:
5842 data = control.ReadEntry(image_fname, entry_path)
5843 self.assertEqual(expected, data)
5844
Alper Nebi Yasak99283e52022-03-27 18:31:49 +03005845 def testReplaceFitSubentryLeafSameSize(self):
5846 """Test replacing a FIT leaf subentry with same-size data"""
5847 new_data = b'x' * len(U_BOOT_DATA)
5848 data, expected_fdtmap, _ = self._RunReplaceCmd(
5849 'fit/kernel/u-boot', new_data,
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005850 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak99283e52022-03-27 18:31:49 +03005851 self.assertEqual(new_data, data)
5852
5853 path, fdtmap = state.GetFdtContents('fdtmap')
5854 self.assertIsNotNone(path)
5855 self.assertEqual(expected_fdtmap, fdtmap)
5856
5857 def testReplaceFitSubentryLeafBiggerSize(self):
5858 """Test replacing a FIT leaf subentry with bigger-size data"""
5859 new_data = b'ub' * len(U_BOOT_NODTB_DATA)
5860 data, expected_fdtmap, _ = self._RunReplaceCmd(
5861 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005862 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak99283e52022-03-27 18:31:49 +03005863 self.assertEqual(new_data, data)
5864
5865 # Will be repacked, so fdtmap must change
5866 path, fdtmap = state.GetFdtContents('fdtmap')
5867 self.assertIsNotNone(path)
5868 self.assertNotEqual(expected_fdtmap, fdtmap)
5869
5870 def testReplaceFitSubentryLeafSmallerSize(self):
5871 """Test replacing a FIT leaf subentry with smaller-size data"""
5872 new_data = b'x'
5873 expected = new_data.ljust(len(U_BOOT_NODTB_DATA), b'\0')
5874 data, expected_fdtmap, _ = self._RunReplaceCmd(
5875 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005876 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak99283e52022-03-27 18:31:49 +03005877 self.assertEqual(expected, data)
5878
5879 path, fdtmap = state.GetFdtContents('fdtmap')
5880 self.assertIsNotNone(path)
5881 self.assertEqual(expected_fdtmap, fdtmap)
5882
Alper Nebi Yasak82337bb2022-03-27 18:31:50 +03005883 def testReplaceSectionSimple(self):
Simon Glass7caa3722023-03-02 17:02:44 -07005884 """Test replacing a simple section with same-sized data"""
Alper Nebi Yasak82337bb2022-03-27 18:31:50 +03005885 new_data = b'w' * len(COMPRESS_DATA + U_BOOT_DATA)
Simon Glass7caa3722023-03-02 17:02:44 -07005886 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5887 new_data, dts='241_replace_section_simple.dts')
5888 self.assertEqual(new_data, data)
5889
5890 entries = image.GetEntries()
5891 self.assertIn('section', entries)
5892 entry = entries['section']
5893 self.assertEqual(len(new_data), entry.size)
5894
5895 def testReplaceSectionLarger(self):
5896 """Test replacing a simple section with larger data"""
5897 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
5898 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5899 new_data, dts='241_replace_section_simple.dts')
5900 self.assertEqual(new_data, data)
5901
5902 entries = image.GetEntries()
5903 self.assertIn('section', entries)
5904 entry = entries['section']
5905 self.assertEqual(len(new_data), entry.size)
5906 fentry = entries['fdtmap']
5907 self.assertEqual(entry.offset + entry.size, fentry.offset)
5908
5909 def testReplaceSectionSmaller(self):
5910 """Test replacing a simple section with smaller data"""
5911 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1) + b'\0'
5912 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5913 new_data, dts='241_replace_section_simple.dts')
5914 self.assertEqual(new_data, data)
5915
5916 # The new size is the same as the old, just with a pad byte at the end
5917 entries = image.GetEntries()
5918 self.assertIn('section', entries)
5919 entry = entries['section']
5920 self.assertEqual(len(new_data), entry.size)
5921
5922 def testReplaceSectionSmallerAllow(self):
5923 """Test failing to replace a simple section with smaller data"""
5924 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1)
5925 try:
5926 state.SetAllowEntryContraction(True)
5927 with self.assertRaises(ValueError) as exc:
5928 self._RunReplaceCmd('section', new_data,
5929 dts='241_replace_section_simple.dts')
5930 finally:
5931 state.SetAllowEntryContraction(False)
5932
5933 # Since we have no information about the position of things within the
5934 # section, we cannot adjust the position of /section-u-boot so it ends
5935 # up outside the section
Simon Glass73593e42022-08-13 11:40:46 -06005936 self.assertIn(
Simon Glass7caa3722023-03-02 17:02:44 -07005937 "Node '/section/u-boot': Offset 0x24 (36) size 0x4 (4) is outside "
5938 "the section '/section' starting at 0x0 (0) of size 0x27 (39)",
Simon Glass73593e42022-08-13 11:40:46 -06005939 str(exc.exception))
Alper Nebi Yasak82337bb2022-03-27 18:31:50 +03005940
Simon Glassdfe1db42022-08-13 11:40:48 -06005941 def testMkimageImagename(self):
5942 """Test using mkimage with -n holding the data too"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06005943 self._SetupSplElf()
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005944 data = self._DoReadFile('242_mkimage_name.dts')
Simon Glassdfe1db42022-08-13 11:40:48 -06005945
5946 # Check that the data appears in the file somewhere
5947 self.assertIn(U_BOOT_SPL_DATA, data)
5948
Simon Glassf3543e62022-09-06 20:26:52 -06005949 # Get struct legacy_img_hdr -> ih_name
Simon Glassdfe1db42022-08-13 11:40:48 -06005950 name = data[0x20:0x40]
5951
5952 # Build the filename that we expect to be placed in there, by virtue of
5953 # the -n paraameter
5954 expect = os.path.join(tools.get_output_dir(), 'mkimage.mkimage')
5955
5956 # Check that the image name is set to the temporary filename used
5957 self.assertEqual(expect.encode('utf-8')[:0x20], name)
5958
Simon Glass9db9e932022-08-13 11:40:49 -06005959 def testMkimageImage(self):
5960 """Test using mkimage with -n holding the data too"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06005961 self._SetupSplElf()
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005962 data = self._DoReadFile('243_mkimage_image.dts')
Simon Glass9db9e932022-08-13 11:40:49 -06005963
5964 # Check that the data appears in the file somewhere
5965 self.assertIn(U_BOOT_SPL_DATA, data)
5966
Simon Glassf3543e62022-09-06 20:26:52 -06005967 # Get struct legacy_img_hdr -> ih_name
Simon Glass9db9e932022-08-13 11:40:49 -06005968 name = data[0x20:0x40]
5969
5970 # Build the filename that we expect to be placed in there, by virtue of
5971 # the -n paraameter
5972 expect = os.path.join(tools.get_output_dir(), 'mkimage-n.mkimage')
5973
5974 # Check that the image name is set to the temporary filename used
5975 self.assertEqual(expect.encode('utf-8')[:0x20], name)
5976
5977 # Check the corect data is in the imagename file
5978 self.assertEqual(U_BOOT_DATA, tools.read_file(expect))
5979
5980 def testMkimageImageNoContent(self):
5981 """Test using mkimage with -n and no data"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06005982 self._SetupSplElf()
Simon Glass9db9e932022-08-13 11:40:49 -06005983 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005984 self._DoReadFile('244_mkimage_image_no_content.dts')
Simon Glass9db9e932022-08-13 11:40:49 -06005985 self.assertIn('Could not complete processing of contents',
5986 str(exc.exception))
5987
5988 def testMkimageImageBad(self):
5989 """Test using mkimage with imagename node and data-to-imagename"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06005990 self._SetupSplElf()
Simon Glass9db9e932022-08-13 11:40:49 -06005991 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005992 self._DoReadFile('245_mkimage_image_bad.dts')
Simon Glass9db9e932022-08-13 11:40:49 -06005993 self.assertIn('Cannot use both imagename node and data-to-imagename',
5994 str(exc.exception))
5995
Simon Glassd626e822022-08-13 11:40:50 -06005996 def testCollectionOther(self):
5997 """Test a collection where the data comes from another section"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005998 data = self._DoReadFile('246_collection_other.dts')
Simon Glassd626e822022-08-13 11:40:50 -06005999 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
6000 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
6001 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
6002 data)
6003
6004 def testMkimageCollection(self):
6005 """Test using a collection referring to an entry in a mkimage entry"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06006006 self._SetupSplElf()
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02006007 data = self._DoReadFile('247_mkimage_coll.dts')
Simon Glassd626e822022-08-13 11:40:50 -06006008 expect = U_BOOT_SPL_DATA + U_BOOT_DATA
6009 self.assertEqual(expect, data[:len(expect)])
6010
Stefan Herbrechtsmeier6aa80002022-08-19 16:25:25 +02006011 def testCompressDtbPrependInvalid(self):
6012 """Test that invalid header is detected"""
6013 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02006014 self._DoReadFileDtb('248_compress_dtb_prepend_invalid.dts')
Stefan Herbrechtsmeier6aa80002022-08-19 16:25:25 +02006015 self.assertIn("Node '/binman/u-boot-dtb': Invalid prepend in "
6016 "'u-boot-dtb': 'invalid'", str(e.exception))
6017
6018 def testCompressDtbPrependLength(self):
6019 """Test that compress with length header works as expected"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02006020 data = self._DoReadFileRealDtb('249_compress_dtb_prepend_length.dts')
Stefan Herbrechtsmeier6aa80002022-08-19 16:25:25 +02006021 image = control.images['image']
6022 entries = image.GetEntries()
6023 self.assertIn('u-boot-dtb', entries)
6024 u_boot_dtb = entries['u-boot-dtb']
6025 self.assertIn('fdtmap', entries)
6026 fdtmap = entries['fdtmap']
6027
6028 image_fname = tools.get_output_filename('image.bin')
6029 orig = control.ReadEntry(image_fname, 'u-boot-dtb')
6030 dtb = fdt.Fdt.FromData(orig)
6031 dtb.Scan()
6032 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
6033 expected = {
6034 'u-boot:size': len(U_BOOT_DATA),
6035 'u-boot-dtb:uncomp-size': len(orig),
6036 'u-boot-dtb:size': u_boot_dtb.size,
6037 'fdtmap:size': fdtmap.size,
6038 'size': len(data),
6039 }
6040 self.assertEqual(expected, props)
6041
6042 # Check implementation
6043 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6044 rest = data[len(U_BOOT_DATA):]
6045 comp_data_len = struct.unpack('<I', rest[:4])[0]
6046 comp_data = rest[4:4 + comp_data_len]
6047 orig2 = self._decompress(comp_data)
6048 self.assertEqual(orig, orig2)
6049
Stefan Herbrechtsmeierec7d27d2022-08-19 16:25:30 +02006050 def testInvalidCompress(self):
6051 """Test that invalid compress algorithm is detected"""
6052 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02006053 self._DoTestFile('250_compress_dtb_invalid.dts')
Stefan Herbrechtsmeierec7d27d2022-08-19 16:25:30 +02006054 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
6055
Stefan Herbrechtsmeierda1af352022-08-19 16:25:32 +02006056 def testCompUtilCompressions(self):
6057 """Test compression algorithms"""
6058 for bintool in self.comp_bintools.values():
6059 self._CheckBintool(bintool)
6060 data = bintool.compress(COMPRESS_DATA)
6061 self.assertNotEqual(COMPRESS_DATA, data)
6062 orig = bintool.decompress(data)
6063 self.assertEquals(COMPRESS_DATA, orig)
6064
6065 def testCompUtilVersions(self):
6066 """Test tool version of compression algorithms"""
6067 for bintool in self.comp_bintools.values():
6068 self._CheckBintool(bintool)
6069 version = bintool.version()
6070 self.assertRegex(version, '^v?[0-9]+[0-9.]*')
6071
6072 def testCompUtilPadding(self):
6073 """Test padding of compression algorithms"""
Stefan Herbrechtsmeiercd15b642022-08-19 16:25:38 +02006074 # Skip zstd because it doesn't support padding
6075 for bintool in [v for k,v in self.comp_bintools.items() if k != 'zstd']:
Stefan Herbrechtsmeierda1af352022-08-19 16:25:32 +02006076 self._CheckBintool(bintool)
6077 data = bintool.compress(COMPRESS_DATA)
6078 self.assertNotEqual(COMPRESS_DATA, data)
6079 data += tools.get_bytes(0, 64)
6080 orig = bintool.decompress(data)
6081 self.assertEquals(COMPRESS_DATA, orig)
6082
Stefan Herbrechtsmeiercd15b642022-08-19 16:25:38 +02006083 def testCompressDtbZstd(self):
6084 """Test that zstd compress of device-tree files failed"""
6085 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02006086 self._DoTestFile('251_compress_dtb_zstd.dts')
Stefan Herbrechtsmeiercd15b642022-08-19 16:25:38 +02006087 self.assertIn("Node '/binman/u-boot-dtb': The zstd compression "
6088 "requires a length header", str(e.exception))
6089
Quentin Schulz4d91df02022-09-02 15:10:48 +02006090 def testMkimageMultipleDataFiles(self):
6091 """Test passing multiple files to mkimage in a mkimage entry"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06006092 self._SetupSplElf()
6093 self._SetupTplElf()
Quentin Schulz4d91df02022-09-02 15:10:48 +02006094 data = self._DoReadFile('252_mkimage_mult_data.dts')
6095 # Size of files are packed in their 4B big-endian format
6096 expect = struct.pack('>I', len(U_BOOT_TPL_DATA))
6097 expect += struct.pack('>I', len(U_BOOT_SPL_DATA))
6098 # Size info is always followed by a 4B zero value.
6099 expect += tools.get_bytes(0, 4)
6100 expect += U_BOOT_TPL_DATA
6101 # All but last files are 4B-aligned
6102 align_pad = len(U_BOOT_TPL_DATA) % 4
6103 if align_pad:
6104 expect += tools.get_bytes(0, align_pad)
6105 expect += U_BOOT_SPL_DATA
6106 self.assertEqual(expect, data[-len(expect):])
6107
Marek Vasutfadad3a2023-07-18 07:23:58 -06006108 def testMkimageMultipleExpanded(self):
6109 """Test passing multiple files to mkimage in a mkimage entry"""
6110 self._SetupSplElf()
6111 self._SetupTplElf()
6112 entry_args = {
6113 'spl-bss-pad': 'y',
6114 'spl-dtb': 'y',
6115 }
6116 data = self._DoReadFileDtb('252_mkimage_mult_data.dts',
6117 use_expanded=True, entry_args=entry_args)[0]
6118 pad_len = 10
6119 tpl_expect = U_BOOT_TPL_DATA
6120 spl_expect = U_BOOT_SPL_NODTB_DATA + tools.get_bytes(0, pad_len)
6121 spl_expect += U_BOOT_SPL_DTB_DATA
6122
6123 content = data[0x40:]
6124 lens = struct.unpack('>III', content[:12])
6125
6126 # Size of files are packed in their 4B big-endian format
6127 # Size info is always followed by a 4B zero value.
6128 self.assertEqual(len(tpl_expect), lens[0])
6129 self.assertEqual(len(spl_expect), lens[1])
6130 self.assertEqual(0, lens[2])
6131
6132 rest = content[12:]
6133 self.assertEqual(tpl_expect, rest[:len(tpl_expect)])
6134
6135 rest = rest[len(tpl_expect):]
6136 align_pad = len(tpl_expect) % 4
6137 self.assertEqual(tools.get_bytes(0, align_pad), rest[:align_pad])
6138 rest = rest[align_pad:]
6139 self.assertEqual(spl_expect, rest)
6140
Quentin Schulz4d91df02022-09-02 15:10:48 +02006141 def testMkimageMultipleNoContent(self):
6142 """Test passing multiple data files to mkimage with one data file having no content"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06006143 self._SetupSplElf()
Quentin Schulz4d91df02022-09-02 15:10:48 +02006144 with self.assertRaises(ValueError) as exc:
6145 self._DoReadFile('253_mkimage_mult_no_content.dts')
6146 self.assertIn('Could not complete processing of contents',
6147 str(exc.exception))
6148
Quentin Schulz6cc29dc2022-09-02 15:10:49 +02006149 def testMkimageFilename(self):
6150 """Test using mkimage to build a binary with a filename"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06006151 self._SetupSplElf()
Quentin Schulz6cc29dc2022-09-02 15:10:49 +02006152 retcode = self._DoTestFile('254_mkimage_filename.dts')
6153 self.assertEqual(0, retcode)
6154 fname = tools.get_output_filename('mkimage-test.bin')
6155 self.assertTrue(os.path.exists(fname))
6156
Simon Glass6ad24522022-02-28 07:16:54 -07006157 def testVpl(self):
6158 """Test that an image with VPL and its device tree can be created"""
6159 # ELF file with a '__bss_size' symbol
6160 self._SetupVplElf()
6161 data = self._DoReadFile('255_u_boot_vpl.dts')
6162 self.assertEqual(U_BOOT_VPL_DATA + U_BOOT_VPL_DTB_DATA, data)
6163
6164 def testVplNoDtb(self):
6165 """Test that an image with vpl/u-boot-vpl-nodtb.bin can be created"""
6166 self._SetupVplElf()
6167 data = self._DoReadFile('256_u_boot_vpl_nodtb.dts')
6168 self.assertEqual(U_BOOT_VPL_NODTB_DATA,
6169 data[:len(U_BOOT_VPL_NODTB_DATA)])
6170
6171 def testExpandedVpl(self):
6172 """Test that an expanded entry type is selected for TPL when needed"""
6173 self._SetupVplElf()
6174
6175 entry_args = {
6176 'vpl-bss-pad': 'y',
6177 'vpl-dtb': 'y',
6178 }
6179 self._DoReadFileDtb('257_fdt_incl_vpl.dts', use_expanded=True,
6180 entry_args=entry_args)
6181 image = control.images['image']
6182 entries = image.GetEntries()
6183 self.assertEqual(1, len(entries))
6184
6185 # We only have u-boot-vpl, which be expanded
6186 self.assertIn('u-boot-vpl', entries)
6187 entry = entries['u-boot-vpl']
6188 self.assertEqual('u-boot-vpl-expanded', entry.etype)
6189 subent = entry.GetEntries()
6190 self.assertEqual(3, len(subent))
6191 self.assertIn('u-boot-vpl-nodtb', subent)
6192 self.assertIn('u-boot-vpl-bss-pad', subent)
6193 self.assertIn('u-boot-vpl-dtb', subent)
6194
6195 def testVplBssPadMissing(self):
6196 """Test that a missing symbol is detected"""
6197 self._SetupVplElf('u_boot_ucode_ptr')
6198 with self.assertRaises(ValueError) as e:
6199 self._DoReadFile('258_vpl_bss_pad.dts')
6200 self.assertIn('Expected __bss_size symbol in vpl/u-boot-vpl',
6201 str(e.exception))
6202
Neha Malcom Francis3545e852022-10-17 16:36:25 +05306203 def testSymlink(self):
Andrew Davis15432ea2023-07-22 00:14:44 +05306204 """Test that image files can be symlinked"""
Neha Malcom Francis3545e852022-10-17 16:36:25 +05306205 retcode = self._DoTestFile('259_symlink.dts', debug=True, map=True)
6206 self.assertEqual(0, retcode)
6207 image = control.images['test_image']
6208 fname = tools.get_output_filename('test_image.bin')
6209 sname = tools.get_output_filename('symlink_to_test.bin')
6210 self.assertTrue(os.path.islink(sname))
6211 self.assertEqual(os.readlink(sname), fname)
Alper Nebi Yasak8ee4ec92022-03-27 18:31:45 +03006212
Andrew Davis15432ea2023-07-22 00:14:44 +05306213 def testSymlinkOverwrite(self):
6214 """Test that symlinked images can be overwritten"""
6215 testdir = TestFunctional._MakeInputDir('symlinktest')
6216 self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
6217 # build the same image again in the same directory so that existing symlink is present
6218 self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
6219 fname = tools.get_output_filename('test_image.bin')
6220 sname = tools.get_output_filename('symlink_to_test.bin')
6221 self.assertTrue(os.path.islink(sname))
6222 self.assertEqual(os.readlink(sname), fname)
6223
Simon Glassd2afb9e2022-10-20 18:22:47 -06006224 def testSymbolsElf(self):
6225 """Test binman can assign symbols embedded in an ELF file"""
6226 if not elf.ELF_TOOLS:
6227 self.skipTest('Python elftools not available')
6228 self._SetupTplElf('u_boot_binman_syms')
6229 self._SetupVplElf('u_boot_binman_syms')
6230 self._SetupSplElf('u_boot_binman_syms')
6231 data = self._DoReadFileDtb('260_symbols_elf.dts')[0]
6232 image_fname = tools.get_output_filename('image.bin')
6233
6234 image = control.images['image']
6235 entries = image.GetEntries()
6236
6237 for entry in entries.values():
6238 # No symbols in u-boot and it has faked contents anyway
6239 if entry.name == 'u-boot':
6240 continue
6241 edata = data[entry.image_pos:entry.image_pos + entry.size]
6242 efname = tools.get_output_filename(f'edata-{entry.name}')
6243 tools.write_file(efname, edata)
6244
6245 syms = elf.GetSymbolFileOffset(efname, ['_binman_u_boot'])
6246 re_name = re.compile('_binman_(u_boot_(.*))_prop_(.*)')
6247 for name, sym in syms.items():
6248 msg = 'test'
6249 val = elf.GetSymbolValue(sym, edata, msg)
6250 entry_m = re_name.match(name)
6251 if entry_m:
6252 ename, prop = entry_m.group(1), entry_m.group(3)
6253 entry, entry_name, prop_name = image.LookupEntry(entries,
6254 name, msg)
6255 if prop_name == 'offset':
6256 expect_val = entry.offset
6257 elif prop_name == 'image_pos':
6258 expect_val = entry.image_pos
6259 elif prop_name == 'size':
6260 expect_val = entry.size
6261 self.assertEqual(expect_val, val)
6262
6263 def testSymbolsElfBad(self):
6264 """Check error when trying to write symbols without the elftools lib"""
6265 if not elf.ELF_TOOLS:
6266 self.skipTest('Python elftools not available')
6267 self._SetupTplElf('u_boot_binman_syms')
6268 self._SetupVplElf('u_boot_binman_syms')
6269 self._SetupSplElf('u_boot_binman_syms')
6270 try:
6271 elf.ELF_TOOLS = False
6272 with self.assertRaises(ValueError) as exc:
6273 self._DoReadFileDtb('260_symbols_elf.dts')
6274 finally:
6275 elf.ELF_TOOLS = True
6276 self.assertIn(
6277 "Section '/binman': entry '/binman/u-boot-spl-elf': "
6278 'Cannot write symbols to an ELF file without Python elftools',
6279 str(exc.exception))
6280
Simon Glassefddab62023-01-07 14:07:08 -07006281 def testSectionFilename(self):
6282 """Check writing of section contents to a file"""
6283 data = self._DoReadFile('261_section_fname.dts')
6284 expected = (b'&&' + U_BOOT_DATA + b'&&&' +
6285 tools.get_bytes(ord('!'), 7) +
6286 U_BOOT_DATA + tools.get_bytes(ord('&'), 12))
6287 self.assertEqual(expected, data)
6288
6289 sect_fname = tools.get_output_filename('outfile.bin')
6290 self.assertTrue(os.path.exists(sect_fname))
6291 sect_data = tools.read_file(sect_fname)
6292 self.assertEqual(U_BOOT_DATA, sect_data)
6293
Simon Glassc8c9f312023-01-07 14:07:12 -07006294 def testAbsent(self):
6295 """Check handling of absent entries"""
6296 data = self._DoReadFile('262_absent.dts')
6297 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6298
Simon Glass2f80c5e2023-01-07 14:07:14 -07006299 def testPackTeeOsOptional(self):
6300 """Test that an image with an optional TEE binary can be created"""
6301 entry_args = {
6302 'tee-os-path': 'tee.elf',
6303 }
6304 data = self._DoReadFileDtb('263_tee_os_opt.dts',
6305 entry_args=entry_args)[0]
6306 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6307
6308 def checkFitTee(self, dts, tee_fname):
6309 """Check that a tee-os entry works and returns data
6310
6311 Args:
6312 dts (str): Device tree filename to use
6313 tee_fname (str): filename containing tee-os
6314
6315 Returns:
6316 bytes: Image contents
6317 """
6318 if not elf.ELF_TOOLS:
6319 self.skipTest('Python elftools not available')
6320 entry_args = {
6321 'of-list': 'test-fdt1 test-fdt2',
6322 'default-dt': 'test-fdt2',
6323 'tee-os-path': tee_fname,
6324 }
6325 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
6326 data = self._DoReadFileDtb(dts, entry_args=entry_args,
6327 extra_indirs=[test_subdir])[0]
6328 return data
6329
6330 def testFitTeeOsOptionalFit(self):
6331 """Test an image with a FIT with an optional OP-TEE binary"""
6332 data = self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bin')
6333
6334 # There should be only one node, holding the data set up in SetUpClass()
6335 # for tee.bin
6336 dtb = fdt.Fdt.FromData(data)
6337 dtb.Scan()
6338 node = dtb.GetNode('/images/tee-1')
6339 self.assertEqual(TEE_ADDR,
6340 fdt_util.fdt32_to_cpu(node.props['load'].value))
6341 self.assertEqual(TEE_ADDR,
6342 fdt_util.fdt32_to_cpu(node.props['entry'].value))
6343 self.assertEqual(U_BOOT_DATA, node.props['data'].bytes)
6344
6345 def testFitTeeOsOptionalFitBad(self):
6346 """Test an image with a FIT with an optional OP-TEE binary"""
6347 with self.assertRaises(ValueError) as exc:
6348 self.checkFitTee('265_tee_os_opt_fit_bad.dts', 'tee.bin')
6349 self.assertIn(
6350 "Node '/binman/fit': subnode 'images/@tee-SEQ': Failed to read ELF file: Magic number does not match",
6351 str(exc.exception))
6352
6353 def testFitTeeOsBad(self):
6354 """Test an OP-TEE binary with wrong formats"""
6355 self.make_tee_bin('tee.bad1', 123)
6356 with self.assertRaises(ValueError) as exc:
6357 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad1')
6358 self.assertIn(
6359 "Node '/binman/fit/images/@tee-SEQ/tee-os': OP-TEE paged mode not supported",
6360 str(exc.exception))
6361
6362 self.make_tee_bin('tee.bad2', 0, b'extra data')
6363 with self.assertRaises(ValueError) as exc:
6364 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad2')
6365 self.assertIn(
6366 "Node '/binman/fit/images/@tee-SEQ/tee-os': Invalid OP-TEE file: size mismatch (expected 0x4, have 0xe)",
6367 str(exc.exception))
6368
Simon Glass67a05012023-01-07 14:07:15 -07006369 def testExtblobOptional(self):
6370 """Test an image with an external blob that is optional"""
6371 with test_util.capture_sys_output() as (stdout, stderr):
6372 data = self._DoReadFile('266_blob_ext_opt.dts')
6373 self.assertEqual(REFCODE_DATA, data)
6374 err = stderr.getvalue()
6375 self.assertRegex(
6376 err,
6377 "Image '.*' is missing external blobs but is still functional: missing")
6378
Simon Glass0b079fc2023-01-11 16:10:12 -07006379 def testSectionInner(self):
6380 """Test an inner section with a size"""
6381 data = self._DoReadFile('267_section_inner.dts')
6382 expected = U_BOOT_DATA + tools.get_bytes(0, 12)
6383 self.assertEqual(expected, data)
6384
Simon Glass62ef2f72023-01-11 16:10:14 -07006385 def testNull(self):
6386 """Test an image with a null entry"""
6387 data = self._DoReadFile('268_null.dts')
6388 self.assertEqual(U_BOOT_DATA + b'\xff\xff\xff\xff' + U_BOOT_IMG_DATA, data)
6389
Simon Glass9766f692023-01-11 16:10:16 -07006390 def testOverlap(self):
6391 """Test an image with a overlapping entry"""
6392 data = self._DoReadFile('269_overlap.dts')
6393 self.assertEqual(U_BOOT_DATA[:1] + b'aa' + U_BOOT_DATA[3:], data)
6394
6395 image = control.images['image']
6396 entries = image.GetEntries()
6397
6398 self.assertIn('inset', entries)
6399 inset = entries['inset']
6400 self.assertEqual(1, inset.offset);
6401 self.assertEqual(1, inset.image_pos);
6402 self.assertEqual(2, inset.size);
6403
6404 def testOverlapNull(self):
6405 """Test an image with a null overlap"""
6406 data = self._DoReadFile('270_overlap_null.dts')
6407 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6408
6409 # Check the FMAP
6410 fhdr, fentries = fmap_util.DecodeFmap(data[len(U_BOOT_DATA):])
6411 self.assertEqual(4, fhdr.nareas)
6412 fiter = iter(fentries)
6413
6414 fentry = next(fiter)
6415 self.assertEqual(b'SECTION', fentry.name)
6416 self.assertEqual(0, fentry.offset)
6417 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6418 self.assertEqual(0, fentry.flags)
6419
6420 fentry = next(fiter)
6421 self.assertEqual(b'U_BOOT', fentry.name)
6422 self.assertEqual(0, fentry.offset)
6423 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6424 self.assertEqual(0, fentry.flags)
6425
6426 # Make sure that the NULL entry appears in the FMAP
6427 fentry = next(fiter)
6428 self.assertEqual(b'NULL', fentry.name)
6429 self.assertEqual(1, fentry.offset)
6430 self.assertEqual(2, fentry.size)
6431 self.assertEqual(0, fentry.flags)
6432
6433 fentry = next(fiter)
6434 self.assertEqual(b'FMAP', fentry.name)
6435 self.assertEqual(len(U_BOOT_DATA), fentry.offset)
6436
6437 def testOverlapBad(self):
6438 """Test an image with a bad overlapping entry"""
6439 with self.assertRaises(ValueError) as exc:
6440 self._DoReadFile('271_overlap_bad.dts')
6441 self.assertIn(
6442 "Node '/binman/inset': Offset 0x10 (16) ending at 0x12 (18) must overlap with existing entries",
6443 str(exc.exception))
6444
6445 def testOverlapNoOffset(self):
6446 """Test an image with a bad overlapping entry"""
6447 with self.assertRaises(ValueError) as exc:
6448 self._DoReadFile('272_overlap_no_size.dts')
6449 self.assertIn(
6450 "Node '/binman/inset': 'fill' entry is missing properties: size",
6451 str(exc.exception))
6452
Simon Glassc1157862023-01-11 16:10:17 -07006453 def testBlobSymbol(self):
6454 """Test a blob with symbols read from an ELF file"""
6455 elf_fname = self.ElfTestFile('blob_syms')
6456 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6457 TestFunctional._MakeInputFile('blob_syms.bin',
6458 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6459
6460 data = self._DoReadFile('273_blob_symbol.dts')
6461
6462 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6463 addr = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6464 self.assertEqual(syms['_binman_sym_magic'].address, addr)
6465 self.assertEqual(syms['_binman_inset_prop_offset'].address, addr + 4)
6466 self.assertEqual(syms['_binman_inset_prop_size'].address, addr + 8)
6467
6468 sym_values = struct.pack('<LLL', elf.BINMAN_SYM_MAGIC_VALUE, 4, 8)
6469 expected = sym_values
6470 self.assertEqual(expected, data[:len(expected)])
6471
Simon Glass571bc4e2023-01-11 16:10:19 -07006472 def testOffsetFromElf(self):
6473 """Test a blob with symbols read from an ELF file"""
6474 elf_fname = self.ElfTestFile('blob_syms')
6475 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6476 TestFunctional._MakeInputFile('blob_syms.bin',
6477 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6478
6479 data = self._DoReadFile('274_offset_from_elf.dts')
6480
6481 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6482 base = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6483
6484 image = control.images['image']
6485 entries = image.GetEntries()
6486
6487 self.assertIn('inset', entries)
6488 inset = entries['inset']
6489
6490 self.assertEqual(base + 4, inset.offset);
6491 self.assertEqual(base + 4, inset.image_pos);
6492 self.assertEqual(4, inset.size);
6493
6494 self.assertIn('inset2', entries)
6495 inset = entries['inset2']
6496 self.assertEqual(base + 8, inset.offset);
6497 self.assertEqual(base + 8, inset.image_pos);
6498 self.assertEqual(4, inset.size);
6499
Jonas Karlman9b2fd2d2023-01-21 19:01:39 +00006500 def testFitAlign(self):
6501 """Test an image with an FIT with aligned external data"""
6502 data = self._DoReadFile('275_fit_align.dts')
6503 self.assertEqual(4096, len(data))
6504
6505 dtb = fdt.Fdt.FromData(data)
6506 dtb.Scan()
6507
6508 props = self._GetPropTree(dtb, ['data-position'])
6509 expected = {
6510 'u-boot:data-position': 1024,
6511 'fdt-1:data-position': 2048,
6512 'fdt-2:data-position': 3072,
6513 }
6514 self.assertEqual(expected, props)
6515
Jonas Karlmanf584d442023-01-21 19:02:12 +00006516 def testFitFirmwareLoadables(self):
6517 """Test an image with an FIT that use fit,firmware"""
6518 if not elf.ELF_TOOLS:
6519 self.skipTest('Python elftools not available')
6520 entry_args = {
6521 'of-list': 'test-fdt1',
6522 'default-dt': 'test-fdt1',
6523 'atf-bl31-path': 'bl31.elf',
6524 'tee-os-path': 'missing.bin',
6525 }
6526 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
Simon Glass7c4027a2023-02-23 18:18:01 -07006527 with test_util.capture_sys_output() as (stdout, stderr):
6528 data = self._DoReadFileDtb(
6529 '276_fit_firmware_loadables.dts',
6530 entry_args=entry_args,
6531 extra_indirs=[test_subdir])[0]
Jonas Karlmanf584d442023-01-21 19:02:12 +00006532
6533 dtb = fdt.Fdt.FromData(data)
6534 dtb.Scan()
6535
6536 node = dtb.GetNode('/configurations/conf-uboot-1')
6537 self.assertEqual('u-boot', node.props['firmware'].value)
6538 self.assertEqual(['atf-1', 'atf-2'],
6539 fdt_util.GetStringList(node, 'loadables'))
6540
6541 node = dtb.GetNode('/configurations/conf-atf-1')
6542 self.assertEqual('atf-1', node.props['firmware'].value)
6543 self.assertEqual(['u-boot', 'atf-2'],
6544 fdt_util.GetStringList(node, 'loadables'))
6545
6546 node = dtb.GetNode('/configurations/conf-missing-uboot-1')
6547 self.assertEqual('u-boot', node.props['firmware'].value)
6548 self.assertEqual(['atf-1', 'atf-2'],
6549 fdt_util.GetStringList(node, 'loadables'))
6550
6551 node = dtb.GetNode('/configurations/conf-missing-atf-1')
6552 self.assertEqual('atf-1', node.props['firmware'].value)
6553 self.assertEqual(['u-boot', 'atf-2'],
6554 fdt_util.GetStringList(node, 'loadables'))
6555
6556 node = dtb.GetNode('/configurations/conf-missing-tee-1')
6557 self.assertEqual('atf-1', node.props['firmware'].value)
6558 self.assertEqual(['u-boot', 'atf-2'],
6559 fdt_util.GetStringList(node, 'loadables'))
6560
Simon Glassfe7e9242023-02-22 12:14:49 -07006561 def testTooldir(self):
6562 """Test that we can specify the tooldir"""
6563 with test_util.capture_sys_output() as (stdout, stderr):
6564 self.assertEqual(0, self._DoBinman('--tooldir', 'fred',
6565 'tool', '-l'))
6566 self.assertEqual('fred', bintool.Bintool.tooldir)
6567
6568 # Check that the toolpath is updated correctly
6569 self.assertEqual(['fred'], tools.tool_search_paths)
6570
6571 # Try with a few toolpaths; the tooldir should be at the end
6572 with test_util.capture_sys_output() as (stdout, stderr):
6573 self.assertEqual(0, self._DoBinman(
6574 '--toolpath', 'mary', '--toolpath', 'anna', '--tooldir', 'fred',
6575 'tool', '-l'))
6576 self.assertEqual(['mary', 'anna', 'fred'], tools.tool_search_paths)
6577
Simon Glass7caa3722023-03-02 17:02:44 -07006578 def testReplaceSectionEntry(self):
6579 """Test replacing an entry in a section"""
6580 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6581 entry_data, expected_fdtmap, image = self._RunReplaceCmd('section/blob',
6582 expect_data, dts='241_replace_section_simple.dts')
6583 self.assertEqual(expect_data, entry_data)
6584
6585 entries = image.GetEntries()
6586 self.assertIn('section', entries)
6587 section = entries['section']
6588
6589 sect_entries = section.GetEntries()
6590 self.assertIn('blob', sect_entries)
6591 entry = sect_entries['blob']
6592 self.assertEqual(len(expect_data), entry.size)
6593
6594 fname = tools.get_output_filename('image-updated.bin')
6595 data = tools.read_file(fname)
6596
6597 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6598 self.assertEqual(expect_data, new_blob_data)
6599
6600 self.assertEqual(U_BOOT_DATA,
6601 data[entry.image_pos + len(expect_data):]
6602 [:len(U_BOOT_DATA)])
6603
6604 def testReplaceSectionDeep(self):
6605 """Test replacing an entry in two levels of sections"""
6606 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6607 entry_data, expected_fdtmap, image = self._RunReplaceCmd(
6608 'section/section/blob', expect_data,
6609 dts='278_replace_section_deep.dts')
6610 self.assertEqual(expect_data, entry_data)
6611
6612 entries = image.GetEntries()
6613 self.assertIn('section', entries)
6614 section = entries['section']
6615
6616 subentries = section.GetEntries()
6617 self.assertIn('section', subentries)
6618 section = subentries['section']
6619
6620 sect_entries = section.GetEntries()
6621 self.assertIn('blob', sect_entries)
6622 entry = sect_entries['blob']
6623 self.assertEqual(len(expect_data), entry.size)
6624
6625 fname = tools.get_output_filename('image-updated.bin')
6626 data = tools.read_file(fname)
6627
6628 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6629 self.assertEqual(expect_data, new_blob_data)
6630
6631 self.assertEqual(U_BOOT_DATA,
6632 data[entry.image_pos + len(expect_data):]
6633 [:len(U_BOOT_DATA)])
6634
6635 def testReplaceFitSibling(self):
6636 """Test an image with a FIT inside where we replace its sibling"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06006637 self._SetupSplElf()
Simon Glass7caa3722023-03-02 17:02:44 -07006638 fname = TestFunctional._MakeInputFile('once', b'available once')
6639 self._DoReadFileRealDtb('277_replace_fit_sibling.dts')
6640 os.remove(fname)
6641
6642 try:
6643 tmpdir, updated_fname = self._SetupImageInTmpdir()
6644
6645 fname = os.path.join(tmpdir, 'update-blob')
6646 expected = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
6647 tools.write_file(fname, expected)
6648
6649 self._DoBinman('replace', '-i', updated_fname, 'blob', '-f', fname)
6650 data = tools.read_file(updated_fname)
6651 start = len(U_BOOT_DTB_DATA)
6652 self.assertEqual(expected, data[start:start + len(expected)])
6653 map_fname = os.path.join(tmpdir, 'image-updated.map')
6654 self.assertFalse(os.path.exists(map_fname))
6655 finally:
6656 shutil.rmtree(tmpdir)
6657
Simon Glass953d4172023-03-02 17:02:45 -07006658 def testX509Cert(self):
6659 """Test creating an X509 certificate"""
6660 keyfile = self.TestFile('key.key')
6661 entry_args = {
6662 'keyfile': keyfile,
6663 }
6664 data = self._DoReadFileDtb('279_x509_cert.dts',
6665 entry_args=entry_args)[0]
6666 cert = data[:-4]
6667 self.assertEqual(U_BOOT_DATA, data[-4:])
6668
6669 # TODO: verify the signature
6670
6671 def testX509CertMissing(self):
6672 """Test that binman still produces an image if openssl is missing"""
6673 keyfile = self.TestFile('key.key')
6674 entry_args = {
6675 'keyfile': 'keyfile',
6676 }
6677 with test_util.capture_sys_output() as (_, stderr):
6678 self._DoTestFile('279_x509_cert.dts',
6679 force_missing_bintools='openssl',
6680 entry_args=entry_args)
6681 err = stderr.getvalue()
6682 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
6683
Jonas Karlman05b978b2023-02-25 19:01:33 +00006684 def testPackRockchipTpl(self):
6685 """Test that an image with a Rockchip TPL binary can be created"""
Simon Glass176f1f62023-07-24 09:19:58 -06006686 data = self._DoReadFile('291_rockchip_tpl.dts')
Jonas Karlman05b978b2023-02-25 19:01:33 +00006687 self.assertEqual(ROCKCHIP_TPL_DATA, data[:len(ROCKCHIP_TPL_DATA)])
6688
Jonas Karlman40389c22023-02-25 19:01:35 +00006689 def testMkimageMissingBlobMultiple(self):
6690 """Test missing blob with mkimage entry and multiple-data-files"""
6691 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass176f1f62023-07-24 09:19:58 -06006692 self._DoTestFile('292_mkimage_missing_multiple.dts', allow_missing=True)
Jonas Karlman40389c22023-02-25 19:01:35 +00006693 err = stderr.getvalue()
6694 self.assertIn("is missing external blobs and is non-functional", err)
6695
6696 with self.assertRaises(ValueError) as e:
Simon Glass176f1f62023-07-24 09:19:58 -06006697 self._DoTestFile('292_mkimage_missing_multiple.dts', allow_missing=False)
Jonas Karlman40389c22023-02-25 19:01:35 +00006698 self.assertIn("not found in input path", str(e.exception))
6699
Ivan Mikhaylov5b34efe2023-03-08 01:13:40 +00006700 def _PrepareSignEnv(self, dts='280_fit_sign.dts'):
6701 """Prepare sign environment
6702
6703 Create private and public keys, add pubkey into dtb.
6704
6705 Returns:
6706 Tuple:
6707 FIT container
6708 Image name
6709 Private key
6710 DTB
6711 """
Marek Vasutfadad3a2023-07-18 07:23:58 -06006712 self._SetupSplElf()
Ivan Mikhaylov5b34efe2023-03-08 01:13:40 +00006713 data = self._DoReadFileRealDtb(dts)
6714 updated_fname = tools.get_output_filename('image-updated.bin')
6715 tools.write_file(updated_fname, data)
6716 dtb = tools.get_output_filename('source.dtb')
6717 private_key = tools.get_output_filename('test_key.key')
6718 public_key = tools.get_output_filename('test_key.crt')
6719 fit = tools.get_output_filename('fit.fit')
6720 key_dir = tools.get_output_dir()
6721
6722 tools.run('openssl', 'req', '-batch' , '-newkey', 'rsa:4096',
6723 '-sha256', '-new', '-nodes', '-x509', '-keyout',
6724 private_key, '-out', public_key)
6725 tools.run('fdt_add_pubkey', '-a', 'sha256,rsa4096', '-k', key_dir,
6726 '-n', 'test_key', '-r', 'conf', dtb)
6727
6728 return fit, updated_fname, private_key, dtb
6729
6730 def testSignSimple(self):
6731 """Test that a FIT container can be signed in image"""
6732 is_signed = False
6733 fit, fname, private_key, dtb = self._PrepareSignEnv()
6734
6735 # do sign with private key
6736 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6737 ['fit'])
6738 is_signed = self._CheckSign(fit, dtb)
6739
6740 self.assertEqual(is_signed, True)
6741
6742 def testSignExactFIT(self):
6743 """Test that a FIT container can be signed and replaced in image"""
6744 is_signed = False
6745 fit, fname, private_key, dtb = self._PrepareSignEnv()
6746
6747 # Make sure we propagate the toolpath, since mkimage may not be on PATH
6748 args = []
6749 if self.toolpath:
6750 for path in self.toolpath:
6751 args += ['--toolpath', path]
6752
6753 # do sign with private key
6754 self._DoBinman(*args, 'sign', '-i', fname, '-k', private_key, '-a',
6755 'sha256,rsa4096', '-f', fit, 'fit')
6756 is_signed = self._CheckSign(fit, dtb)
6757
6758 self.assertEqual(is_signed, True)
6759
6760 def testSignNonFit(self):
6761 """Test a non-FIT entry cannot be signed"""
6762 is_signed = False
6763 fit, fname, private_key, _ = self._PrepareSignEnv(
6764 '281_sign_non_fit.dts')
6765
6766 # do sign with private key
6767 with self.assertRaises(ValueError) as e:
6768 self._DoBinman('sign', '-i', fname, '-k', private_key, '-a',
6769 'sha256,rsa4096', '-f', fit, 'u-boot')
6770 self.assertIn(
6771 "Node '/u-boot': Updating signatures is not supported with this entry type",
6772 str(e.exception))
6773
6774 def testSignMissingMkimage(self):
6775 """Test that FIT signing handles a missing mkimage tool"""
6776 fit, fname, private_key, _ = self._PrepareSignEnv()
6777
6778 # try to sign with a missing mkimage tool
6779 bintool.Bintool.set_missing_list(['mkimage'])
6780 with self.assertRaises(ValueError) as e:
6781 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6782 ['fit'])
6783 self.assertIn("Node '/fit': Missing tool: 'mkimage'", str(e.exception))
6784
Simon Glass4649bea2023-07-18 07:23:54 -06006785 def testSymbolNoWrite(self):
6786 """Test disabling of symbol writing"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06006787 self._SetupSplElf()
Simon Glass4649bea2023-07-18 07:23:54 -06006788 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_DATA, 0x1c,
6789 no_write_symbols=True)
6790
6791 def testSymbolNoWriteExpanded(self):
6792 """Test disabling of symbol writing in expanded entries"""
6793 entry_args = {
6794 'spl-dtb': '1',
6795 }
6796 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_NODTB_DATA +
6797 U_BOOT_SPL_DTB_DATA, 0x38,
6798 entry_args=entry_args, use_expanded=True,
6799 no_write_symbols=True)
6800
Marek Vasutfadad3a2023-07-18 07:23:58 -06006801 def testMkimageSpecial(self):
6802 """Test mkimage ignores special hash-1 node"""
6803 data = self._DoReadFile('283_mkimage_special.dts')
6804
6805 # Just check that the data appears in the file somewhere
6806 self.assertIn(U_BOOT_DATA, data)
6807
Simon Glassb1e40ee2023-07-18 07:23:59 -06006808 def testFitFdtList(self):
6809 """Test an image with an FIT with the fit,fdt-list-val option"""
6810 entry_args = {
6811 'default-dt': 'test-fdt2',
6812 }
6813 data = self._DoReadFileDtb(
6814 '284_fit_fdt_list.dts',
6815 entry_args=entry_args,
6816 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
6817 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
6818 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
6819
Simon Glasse1ad57e2023-07-18 07:24:01 -06006820 def testSplEmptyBss(self):
6821 """Test an expanded SPL with a zero-size BSS"""
6822 # ELF file with a '__bss_size' symbol
6823 self._SetupSplElf(src_fname='bss_data_zero')
6824
6825 entry_args = {
6826 'spl-bss-pad': 'y',
6827 'spl-dtb': 'y',
6828 }
6829 data = self._DoReadFileDtb('285_spl_expand.dts',
6830 use_expanded=True, entry_args=entry_args)[0]
6831
Simon Glassf6abd522023-07-18 07:24:04 -06006832 def testTemplate(self):
6833 """Test using a template"""
6834 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
6835 data = self._DoReadFile('286_template.dts')
6836 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
6837 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
6838 self.assertEqual(U_BOOT_IMG_DATA + first + second, data)
6839
Simon Glass35f72fb2023-07-18 07:24:05 -06006840 def testTemplateBlobMulti(self):
6841 """Test using a template with 'multiple-images' enabled"""
6842 TestFunctional._MakeInputFile('my-blob.bin', b'blob')
6843 TestFunctional._MakeInputFile('my-blob2.bin', b'other')
6844 retcode = self._DoTestFile('287_template_multi.dts')
6845
6846 self.assertEqual(0, retcode)
6847 image = control.images['image']
6848 image_fname = tools.get_output_filename('my-image.bin')
6849 data = tools.read_file(image_fname)
6850 self.assertEqual(b'blob@@@@other', data)
6851
Simon Glassdb0e3f12023-07-18 07:24:06 -06006852 def testTemplateFit(self):
6853 """Test using a template in a FIT"""
6854 fit_data = self._DoReadFile('288_template_fit.dts')
6855 fname = os.path.join(self._indir, 'fit_data.fit')
6856 tools.write_file(fname, fit_data)
6857 out = tools.run('dumpimage', '-l', fname)
6858
Simon Glass696f2b72023-07-18 07:24:07 -06006859 def testTemplateSection(self):
6860 """Test using a template in a section (not at top level)"""
6861 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
6862 data = self._DoReadFile('289_template_section.dts')
6863 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
6864 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
6865 self.assertEqual(U_BOOT_IMG_DATA + first + second + first, data)
6866
Simon Glass23b96e92023-07-18 07:24:08 -06006867 def testMkimageSymbols(self):
6868 """Test using mkimage to build an image with symbols in it"""
6869 self._SetupSplElf('u_boot_binman_syms')
6870 data = self._DoReadFile('290_mkimage_sym.dts')
6871
6872 image = control.images['image']
6873 entries = image.GetEntries()
6874 self.assertIn('u-boot', entries)
6875 u_boot = entries['u-boot']
6876
6877 mkim = entries['mkimage']
6878 mkim_entries = mkim.GetEntries()
6879 self.assertIn('u-boot-spl', mkim_entries)
6880 spl = mkim_entries['u-boot-spl']
6881 self.assertIn('u-boot-spl2', mkim_entries)
6882 spl2 = mkim_entries['u-boot-spl2']
6883
6884 # skip the mkimage header and the area sizes
6885 mk_data = data[mkim.offset + 0x40:]
6886 size, term = struct.unpack('>LL', mk_data[:8])
6887
6888 # There should be only one image, so check that the zero terminator is
6889 # present
6890 self.assertEqual(0, term)
6891
6892 content = mk_data[8:8 + size]
6893
6894 # The image should contain the symbols from u_boot_binman_syms.c
6895 # Note that image_pos is adjusted by the base address of the image,
6896 # which is 0x10 in our test image
6897 spl_data = content[:0x18]
6898 content = content[0x1b:]
6899
6900 # After the header is a table of offsets for each image. There should
6901 # only be one image, then a 0 terminator, so figure out the real start
6902 # of the image data
6903 base = 0x40 + 8
6904
6905 # Check symbols in both u-boot-spl and u-boot-spl2
6906 for i in range(2):
6907 vals = struct.unpack('<LLQLL', spl_data)
6908
6909 # The image should contain the symbols from u_boot_binman_syms.c
6910 # Note that image_pos is adjusted by the base address of the image,
6911 # which is 0x10 in our 'u_boot_binman_syms' test image
6912 self.assertEqual(elf.BINMAN_SYM_MAGIC_VALUE, vals[0])
6913 self.assertEqual(base, vals[1])
6914 self.assertEqual(spl2.offset, vals[2])
6915 # figure out the internal positions of its components
6916 self.assertEqual(0x10 + u_boot.image_pos, vals[3])
6917
6918 # Check that spl and spl2 are actually at the indicated positions
6919 self.assertEqual(
6920 elf.BINMAN_SYM_MAGIC_VALUE,
6921 struct.unpack('<I', data[spl.image_pos:spl.image_pos + 4])[0])
6922 self.assertEqual(
6923 elf.BINMAN_SYM_MAGIC_VALUE,
6924 struct.unpack('<I', data[spl2.image_pos:spl2.image_pos + 4])[0])
6925
6926 self.assertEqual(len(U_BOOT_DATA), vals[4])
6927
6928 # Move to next
6929 spl_data = content[:0x18]
6930
Neha Malcom Francis6c66ccf2023-07-22 00:14:24 +05306931 def testTIBoardConfig(self):
6932 """Test that a schema validated board config file can be generated"""
Simon Glassa6b44ac2023-07-24 09:19:59 -06006933 data = self._DoReadFile('293_ti_board_cfg.dts')
Neha Malcom Francis6c66ccf2023-07-22 00:14:24 +05306934 self.assertEqual(TI_BOARD_CONFIG_DATA, data)
6935
6936 def testTIBoardConfigCombined(self):
6937 """Test that a schema validated combined board config file can be generated"""
Simon Glassa6b44ac2023-07-24 09:19:59 -06006938 data = self._DoReadFile('294_ti_board_cfg_combined.dts')
Neha Malcom Francis6c66ccf2023-07-22 00:14:24 +05306939 configlen_noheader = TI_BOARD_CONFIG_DATA * 4
6940 self.assertGreater(data, configlen_noheader)
6941
6942 def testTIBoardConfigNoDataType(self):
6943 """Test that error is thrown when data type is not supported"""
6944 with self.assertRaises(ValueError) as e:
Simon Glassa6b44ac2023-07-24 09:19:59 -06006945 data = self._DoReadFile('295_ti_board_cfg_no_type.dts')
Neha Malcom Francis6c66ccf2023-07-22 00:14:24 +05306946 self.assertIn("Schema validation error", str(e.exception))
Simon Glassefddab62023-01-07 14:07:08 -07006947
Neha Malcom Francis78144822023-07-22 00:14:25 +05306948 def testPackTiSecure(self):
6949 """Test that an image with a TI secured binary can be created"""
6950 keyfile = self.TestFile('key.key')
6951 entry_args = {
6952 'keyfile': keyfile,
6953 }
Simon Glassa6b44ac2023-07-24 09:19:59 -06006954 data = self._DoReadFileDtb('296_ti_secure.dts',
Neha Malcom Francis78144822023-07-22 00:14:25 +05306955 entry_args=entry_args)[0]
6956 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
6957
6958 def testPackTiSecureMissingTool(self):
6959 """Test that an image with a TI secured binary (non-functional) can be created
6960 when openssl is missing"""
6961 keyfile = self.TestFile('key.key')
6962 entry_args = {
6963 'keyfile': keyfile,
6964 }
6965 with test_util.capture_sys_output() as (_, stderr):
Simon Glassa6b44ac2023-07-24 09:19:59 -06006966 self._DoTestFile('296_ti_secure.dts',
Neha Malcom Francis78144822023-07-22 00:14:25 +05306967 force_missing_bintools='openssl',
6968 entry_args=entry_args)
6969 err = stderr.getvalue()
6970 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
6971
6972 def testPackTiSecureROM(self):
6973 """Test that a ROM image with a TI secured binary can be created"""
6974 keyfile = self.TestFile('key.key')
6975 entry_args = {
6976 'keyfile': keyfile,
6977 }
Simon Glassa6b44ac2023-07-24 09:19:59 -06006978 data = self._DoReadFileDtb('297_ti_secure_rom.dts',
Neha Malcom Francis78144822023-07-22 00:14:25 +05306979 entry_args=entry_args)[0]
Simon Glassa6b44ac2023-07-24 09:19:59 -06006980 data_a = self._DoReadFileDtb('299_ti_secure_rom_a.dts',
Neha Malcom Francis78144822023-07-22 00:14:25 +05306981 entry_args=entry_args)[0]
Simon Glassa6b44ac2023-07-24 09:19:59 -06006982 data_b = self._DoReadFileDtb('300_ti_secure_rom_b.dts',
Neha Malcom Francis78144822023-07-22 00:14:25 +05306983 entry_args=entry_args)[0]
6984 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
6985 self.assertGreater(len(data_a), len(TI_UNSECURE_DATA))
6986 self.assertGreater(len(data_b), len(TI_UNSECURE_DATA))
6987
6988 def testPackTiSecureROMCombined(self):
6989 """Test that a ROM image with a TI secured binary can be created"""
6990 keyfile = self.TestFile('key.key')
6991 entry_args = {
6992 'keyfile': keyfile,
6993 }
Simon Glassa6b44ac2023-07-24 09:19:59 -06006994 data = self._DoReadFileDtb('298_ti_secure_rom_combined.dts',
Neha Malcom Francis78144822023-07-22 00:14:25 +05306995 entry_args=entry_args)[0]
6996 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
6997
Simon Glass9fc60b42017-11-12 21:52:22 -07006998if __name__ == "__main__":
6999 unittest.main()