blob: d930e353faf8543e0c6d0dba61f406806d0c193c [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 Glass7081a942024-07-20 11:49:45 +010010import glob
Simon Glass16287932020-04-17 18:09:03 -060011import gzip
Simon Glasse0e5df92018-09-14 04:57:31 -060012import hashlib
Simon Glass4f443042016-11-25 20:15:52 -070013from optparse import OptionParser
14import os
Simon Glassfdc34362020-07-09 18:39:45 -060015import re
Simon Glass4f443042016-11-25 20:15:52 -070016import shutil
17import struct
18import sys
19import tempfile
20import unittest
Simon Glass56ee85e2022-01-09 20:13:57 -070021import unittest.mock
22import urllib.error
Simon Glass4f443042016-11-25 20:15:52 -070023
Simon Glass386c63c2022-01-09 20:13:50 -070024from binman import bintool
Simon Glass16287932020-04-17 18:09:03 -060025from binman import cbfs_util
26from binman import cmdline
27from binman import control
28from binman import elf
29from binman import elf_test
Simon Glass75989722021-11-23 21:08:59 -070030from binman import fip_util
Simon Glass16287932020-04-17 18:09:03 -060031from binman import fmap_util
Simon Glass16287932020-04-17 18:09:03 -060032from binman import state
33from dtoc import fdt
34from dtoc import fdt_util
35from binman.etype import fdtmap
36from binman.etype import image_header
Simon Glass07237982020-08-05 13:27:47 -060037from binman.image import Image
Simon Glass4583c002023-02-23 18:18:04 -070038from u_boot_pylib import command
39from u_boot_pylib import test_util
40from u_boot_pylib import tools
41from u_boot_pylib import tout
Simon Glass4f443042016-11-25 20:15:52 -070042
43# Contents of test files, corresponding to different entry types
Simon Glassc6c10e72019-05-17 22:00:46 -060044U_BOOT_DATA = b'1234'
45U_BOOT_IMG_DATA = b'img'
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +030046U_BOOT_SPL_DATA = b'56780123456789abcdefghijklm'
47U_BOOT_TPL_DATA = b'tpl9876543210fedcbazywvuts'
Simon Glass6ad24522022-02-28 07:16:54 -070048U_BOOT_VPL_DATA = b'vpl76543210fedcbazywxyz_'
Simon Glassc6c10e72019-05-17 22:00:46 -060049BLOB_DATA = b'89'
50ME_DATA = b'0abcd'
51VGA_DATA = b'vga'
Sughosh Ganub6176112023-08-22 23:09:59 +053052EFI_CAPSULE_DATA = b'efi'
Simon Glassc6c10e72019-05-17 22:00:46 -060053U_BOOT_DTB_DATA = b'udtb'
54U_BOOT_SPL_DTB_DATA = b'spldtb'
55U_BOOT_TPL_DTB_DATA = b'tpldtb'
Simon Glass6ad24522022-02-28 07:16:54 -070056U_BOOT_VPL_DTB_DATA = b'vpldtb'
Simon Glassc6c10e72019-05-17 22:00:46 -060057X86_START16_DATA = b'start16'
58X86_START16_SPL_DATA = b'start16spl'
59X86_START16_TPL_DATA = b'start16tpl'
Simon Glass2250ee62019-08-24 07:22:48 -060060X86_RESET16_DATA = b'reset16'
61X86_RESET16_SPL_DATA = b'reset16spl'
62X86_RESET16_TPL_DATA = b'reset16tpl'
Simon Glassc6c10e72019-05-17 22:00:46 -060063PPC_MPC85XX_BR_DATA = b'ppcmpc85xxbr'
64U_BOOT_NODTB_DATA = b'nodtb with microcode pointer somewhere in here'
65U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here'
66U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here'
Simon Glass6ad24522022-02-28 07:16:54 -070067U_BOOT_VPL_NODTB_DATA = b'vplnodtb'
Alper Nebi Yasak21353312022-02-08 01:08:04 +030068U_BOOT_EXP_DATA = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
69U_BOOT_SPL_EXP_DATA = U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA
70U_BOOT_TPL_EXP_DATA = U_BOOT_TPL_NODTB_DATA + U_BOOT_TPL_DTB_DATA
Simon Glassc6c10e72019-05-17 22:00:46 -060071FSP_DATA = b'fsp'
72CMC_DATA = b'cmc'
73VBT_DATA = b'vbt'
74MRC_DATA = b'mrc'
Simon Glassbb748372018-07-17 13:25:33 -060075TEXT_DATA = 'text'
76TEXT_DATA2 = 'text2'
77TEXT_DATA3 = 'text3'
Simon Glassc6c10e72019-05-17 22:00:46 -060078CROS_EC_RW_DATA = b'ecrw'
79GBB_DATA = b'gbbd'
80BMPBLK_DATA = b'bmp'
81VBLOCK_DATA = b'vblk'
82FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
83 b"sorry you're alive\n")
Simon Glassff5c7e32019-07-08 13:18:42 -060084COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
Simon Glass8f5ef892020-10-26 17:40:25 -060085COMPRESS_DATA_BIG = COMPRESS_DATA * 2
Simon Glassc6c10e72019-05-17 22:00:46 -060086REFCODE_DATA = b'refcode'
Simon Glassea0fff92019-08-24 07:23:07 -060087FSP_M_DATA = b'fsp_m'
Simon Glassbc6a88f2019-10-20 21:31:35 -060088FSP_S_DATA = b'fsp_s'
Simon Glass998d1482019-10-20 21:31:36 -060089FSP_T_DATA = b'fsp_t'
Simon Glassdc2f81a2020-09-01 05:13:58 -060090ATF_BL31_DATA = b'bl31'
Roger Quadros47f420a2022-02-19 20:50:04 +020091TEE_OS_DATA = b'this is some tee OS data'
Neha Malcom Francis23d2ef92023-12-05 15:12:18 +053092TI_DM_DATA = b'tidmtidm'
Simon Glass75989722021-11-23 21:08:59 -070093ATF_BL2U_DATA = b'bl2u'
Bin Meng4c4d6072021-05-10 20:23:33 +080094OPENSBI_DATA = b'opensbi'
Samuel Holland18bd4552020-10-21 21:12:15 -050095SCP_DATA = b'scp'
Jonas Karlman05b978b2023-02-25 19:01:33 +000096ROCKCHIP_TPL_DATA = b'rockchip-tpl'
Simon Glass6cf99532020-09-01 05:13:59 -060097TEST_FDT1_DATA = b'fdt1'
98TEST_FDT2_DATA = b'test-fdt2'
Simon Glassfb91d562020-09-06 10:35:33 -060099ENV_DATA = b'var1=1\nvar2="2"'
Christian Taedcke289e6002023-07-17 09:05:54 +0200100ENCRYPTED_IV_DATA = b'123456'
101ENCRYPTED_KEY_DATA = b'abcde'
Philippe Reynesb1c50932022-03-28 22:57:04 +0200102PRE_LOAD_MAGIC = b'UBSH'
103PRE_LOAD_VERSION = 0x11223344.to_bytes(4, 'big')
104PRE_LOAD_HDR_SIZE = 0x00001000.to_bytes(4, 'big')
Neha Malcom Francis6c66ccf2023-07-22 00:14:24 +0530105TI_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 +0530106TI_UNSECURE_DATA = b'unsecuredata'
Simon Glass6cf99532020-09-01 05:13:59 -0600107
108# Subdirectory of the input dir to use to put test FDTs
109TEST_FDT_SUBDIR = 'fdts'
Simon Glassec127af2018-07-17 13:25:39 -0600110
Simon Glass6ccbfcd2019-07-20 12:23:47 -0600111# The expected size for the device tree in some tests
Simon Glassf667e452019-07-08 14:25:50 -0600112EXTRACT_DTB_SIZE = 0x3c9
113
Simon Glass6ccbfcd2019-07-20 12:23:47 -0600114# Properties expected to be in the device tree when update_dtb is used
115BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
116
Simon Glass12bb1a92019-07-20 12:23:51 -0600117# Extra properties expected to be in the device tree when allow-repack is used
118REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
119
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +0200120# Supported compression bintools
Stefan Herbrechtsmeiercd15b642022-08-19 16:25:38 +0200121COMP_BINTOOLS = ['bzip2', 'gzip', 'lz4', 'lzma_alone', 'lzop', 'xz', 'zstd']
Simon Glass4f443042016-11-25 20:15:52 -0700122
Simon Glass2f80c5e2023-01-07 14:07:14 -0700123TEE_ADDR = 0x5678
124
Sughosh Ganub6176112023-08-22 23:09:59 +0530125# Firmware Management Protocol(FMP) GUID
Sughosh Ganu809f28e2023-10-10 14:40:57 +0530126FW_MGMT_GUID = '6dcbd5ed-e82d-4c44-bda1-7194199ad92a'
Sughosh Ganub6176112023-08-22 23:09:59 +0530127# Image GUID specified in the DTS
Sughosh Ganu809f28e2023-10-10 14:40:57 +0530128CAPSULE_IMAGE_GUID = '09d7cf52-0720-4710-91d1-08469b7fe9c8'
129# Windows cert GUID
130WIN_CERT_TYPE_EFI_GUID = '4aafd29d-68df-49ee-8aa9-347d375665a7'
Sughosh Ganu74aae502023-10-10 14:40:59 +0530131# Empty capsule GUIDs
132EMPTY_CAPSULE_ACCEPT_GUID = '0c996046-bcc0-4d04-85ec-e1fcedf1c6f8'
133EMPTY_CAPSULE_REVERT_GUID = 'acd58b4b-c0e8-475f-99b5-6b3f7e07aaf0'
Sughosh Ganub6176112023-08-22 23:09:59 +0530134
Simon Glass4f443042016-11-25 20:15:52 -0700135class TestFunctional(unittest.TestCase):
136 """Functional tests for binman
137
138 Most of these use a sample .dts file to build an image and then check
139 that it looks correct. The sample files are in the test/ subdirectory
140 and are numbered.
141
142 For each entry type a very small test file is created using fixed
143 string contents. This makes it easy to test that things look right, and
144 debug problems.
145
146 In some cases a 'real' file must be used - these are also supplied in
147 the test/ diurectory.
148 """
149 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600150 def setUpClass(cls):
Simon Glass4d5994f2017-11-12 21:52:20 -0700151 global entry
Simon Glass16287932020-04-17 18:09:03 -0600152 from binman import entry
Simon Glass4d5994f2017-11-12 21:52:20 -0700153
Simon Glass4f443042016-11-25 20:15:52 -0700154 # Handle the case where argv[0] is 'python'
Simon Glassb986b3b2019-08-24 07:22:43 -0600155 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
156 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
Simon Glass4f443042016-11-25 20:15:52 -0700157
158 # Create a temporary directory for input files
Simon Glassb986b3b2019-08-24 07:22:43 -0600159 cls._indir = tempfile.mkdtemp(prefix='binmant.')
Simon Glass4f443042016-11-25 20:15:52 -0700160
161 # Create some test files
162 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
163 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
164 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glassb8ef5b62018-07-17 13:25:48 -0600165 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass6ad24522022-02-28 07:16:54 -0700166 TestFunctional._MakeInputFile('vpl/u-boot-vpl.bin', U_BOOT_VPL_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700167 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -0700168 TestFunctional._MakeInputFile('me.bin', ME_DATA)
169 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glassb986b3b2019-08-24 07:22:43 -0600170 cls._ResetDtbs()
Simon Glass2250ee62019-08-24 07:22:48 -0600171
Jagdish Gediya9d368f32018-09-03 21:35:08 +0530172 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glass2250ee62019-08-24 07:22:48 -0600173
Simon Glass5e239182019-08-24 07:22:49 -0600174 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
175 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
Simon Glass87722132017-11-12 21:52:26 -0700176 X86_START16_SPL_DATA)
Simon Glass5e239182019-08-24 07:22:49 -0600177 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
Simon Glass35b384c2018-09-14 04:57:10 -0600178 X86_START16_TPL_DATA)
Simon Glass2250ee62019-08-24 07:22:48 -0600179
180 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
181 X86_RESET16_DATA)
182 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
183 X86_RESET16_SPL_DATA)
184 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
185 X86_RESET16_TPL_DATA)
186
Simon Glass4f443042016-11-25 20:15:52 -0700187 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass6b187df2017-11-12 21:52:27 -0700188 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
189 U_BOOT_SPL_NODTB_DATA)
Simon Glassf0253632018-09-14 04:57:32 -0600190 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
191 U_BOOT_TPL_NODTB_DATA)
Simon Glass6ad24522022-02-28 07:16:54 -0700192 TestFunctional._MakeInputFile('vpl/u-boot-vpl-nodtb.bin',
193 U_BOOT_VPL_NODTB_DATA)
Simon Glassda229092016-11-25 20:15:56 -0700194 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
195 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Meng59ea8c22017-08-15 22:41:54 -0700196 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassca4f4ff2017-11-12 21:52:28 -0700197 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassec127af2018-07-17 13:25:39 -0600198 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glass0ef87aa2018-07-17 13:25:44 -0600199 TestFunctional._MakeInputDir('devkeys')
200 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass3ae192c2018-10-01 12:22:31 -0600201 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glassea0fff92019-08-24 07:23:07 -0600202 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
Simon Glassbc6a88f2019-10-20 21:31:35 -0600203 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
Simon Glass998d1482019-10-20 21:31:36 -0600204 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700205
Simon Glass53e22bf2019-08-24 07:22:53 -0600206 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
207 elf_test.BuildElfTestFiles(cls._elf_testdir)
208
Simon Glasse0ff8552016-11-25 20:15:53 -0700209 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glassf514d8f2019-08-24 07:22:54 -0600210 TestFunctional._MakeInputFile('u-boot',
Simon Glassc1aa66e2022-01-29 14:14:04 -0700211 tools.read_file(cls.ElfTestFile('u_boot_ucode_ptr')))
Simon Glasse0ff8552016-11-25 20:15:53 -0700212
213 # Intel flash descriptor file
Simon Glass0ba4b3d2020-07-09 18:39:41 -0600214 cls._SetupDescriptor()
Simon Glasse0ff8552016-11-25 20:15:53 -0700215
Simon Glassb986b3b2019-08-24 07:22:43 -0600216 shutil.copytree(cls.TestFile('files'),
217 os.path.join(cls._indir, 'files'))
Simon Glass0a98b282018-09-14 04:57:28 -0600218
Neha Malcom Francis6c66ccf2023-07-22 00:14:24 +0530219 shutil.copytree(cls.TestFile('yaml'),
220 os.path.join(cls._indir, 'yaml'))
221
Simon Glass83d73c22018-09-14 04:57:26 -0600222 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
Simon Glass8f5ef892020-10-26 17:40:25 -0600223 TestFunctional._MakeInputFile('compress_big', COMPRESS_DATA_BIG)
Simon Glassdc2f81a2020-09-01 05:13:58 -0600224 TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
Roger Quadros47f420a2022-02-19 20:50:04 +0200225 TestFunctional._MakeInputFile('tee-pager.bin', TEE_OS_DATA)
Neha Malcom Francis23d2ef92023-12-05 15:12:18 +0530226 TestFunctional._MakeInputFile('dm.bin', TI_DM_DATA)
Simon Glass75989722021-11-23 21:08:59 -0700227 TestFunctional._MakeInputFile('bl2u.bin', ATF_BL2U_DATA)
Bin Meng4c4d6072021-05-10 20:23:33 +0800228 TestFunctional._MakeInputFile('fw_dynamic.bin', OPENSBI_DATA)
Samuel Holland18bd4552020-10-21 21:12:15 -0500229 TestFunctional._MakeInputFile('scp.bin', SCP_DATA)
Jonas Karlman05b978b2023-02-25 19:01:33 +0000230 TestFunctional._MakeInputFile('rockchip-tpl.bin', ROCKCHIP_TPL_DATA)
Neha Malcom Francis78144822023-07-22 00:14:25 +0530231 TestFunctional._MakeInputFile('ti_unsecure.bin', TI_UNSECURE_DATA)
Sughosh Ganub6176112023-08-22 23:09:59 +0530232 TestFunctional._MakeInputFile('capsule_input.bin', EFI_CAPSULE_DATA)
Simon Glass83d73c22018-09-14 04:57:26 -0600233
Simon Glass6cf99532020-09-01 05:13:59 -0600234 # Add a few .dtb files for testing
235 TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR,
236 TEST_FDT1_DATA)
237 TestFunctional._MakeInputFile('%s/test-fdt2.dtb' % TEST_FDT_SUBDIR,
238 TEST_FDT2_DATA)
239
Simon Glassfb91d562020-09-06 10:35:33 -0600240 TestFunctional._MakeInputFile('env.txt', ENV_DATA)
241
Simon Glass40c8bdd2022-03-05 20:19:12 -0700242 # ELF file with two sections in different parts of memory, used for both
243 # ATF and OP_TEE
244 TestFunctional._MakeInputFile('bl31.elf',
245 tools.read_file(cls.ElfTestFile('elf_sections')))
246 TestFunctional._MakeInputFile('tee.elf',
247 tools.read_file(cls.ElfTestFile('elf_sections')))
248
Simon Glass2f80c5e2023-01-07 14:07:14 -0700249 # Newer OP_TEE file in v1 binary format
250 cls.make_tee_bin('tee.bin')
251
Christian Taedcke289e6002023-07-17 09:05:54 +0200252 # test files for encrypted tests
253 TestFunctional._MakeInputFile('encrypted-file.iv', ENCRYPTED_IV_DATA)
254 TestFunctional._MakeInputFile('encrypted-file.key', ENCRYPTED_KEY_DATA)
255
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +0200256 cls.comp_bintools = {}
257 for name in COMP_BINTOOLS:
258 cls.comp_bintools[name] = bintool.Bintool.create(name)
Simon Glassac62fba2019-07-08 13:18:53 -0600259
Simon Glass4f443042016-11-25 20:15:52 -0700260 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600261 def tearDownClass(cls):
Simon Glass4f443042016-11-25 20:15:52 -0700262 """Remove the temporary input directory and its contents"""
Simon Glassb986b3b2019-08-24 07:22:43 -0600263 if cls.preserve_indir:
264 print('Preserving input dir: %s' % cls._indir)
Simon Glassd5164a72019-07-08 13:18:49 -0600265 else:
Simon Glassb986b3b2019-08-24 07:22:43 -0600266 if cls._indir:
267 shutil.rmtree(cls._indir)
268 cls._indir = None
Simon Glass4f443042016-11-25 20:15:52 -0700269
Simon Glassd5164a72019-07-08 13:18:49 -0600270 @classmethod
Simon Glass8acce602019-07-08 13:18:50 -0600271 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
Simon Glass53cd5d92019-07-08 14:25:29 -0600272 toolpath=None, verbosity=None):
Simon Glassd5164a72019-07-08 13:18:49 -0600273 """Accept arguments controlling test execution
274
275 Args:
276 preserve_indir: Preserve the shared input directory used by all
277 tests in this class.
278 preserve_outdir: Preserve the output directories used by tests. Each
279 test has its own, so this is normally only useful when running a
280 single test.
Simon Glass8acce602019-07-08 13:18:50 -0600281 toolpath: ist of paths to use for tools
Simon Glassd5164a72019-07-08 13:18:49 -0600282 """
283 cls.preserve_indir = preserve_indir
284 cls.preserve_outdirs = preserve_outdirs
Simon Glass8acce602019-07-08 13:18:50 -0600285 cls.toolpath = toolpath
Simon Glass53cd5d92019-07-08 14:25:29 -0600286 cls.verbosity = verbosity
Simon Glassd5164a72019-07-08 13:18:49 -0600287
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +0200288 def _CheckBintool(self, bintool):
289 if not bintool.is_present():
290 self.skipTest('%s not available' % bintool.name)
291
Simon Glassac62fba2019-07-08 13:18:53 -0600292 def _CheckLz4(self):
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +0200293 bintool = self.comp_bintools['lz4']
294 self._CheckBintool(bintool)
Simon Glassac62fba2019-07-08 13:18:53 -0600295
Simon Glassbf574f12019-07-20 12:24:09 -0600296 def _CleanupOutputDir(self):
297 """Remove the temporary output directory"""
298 if self.preserve_outdirs:
299 print('Preserving output dir: %s' % tools.outdir)
300 else:
Simon Glassc1aa66e2022-01-29 14:14:04 -0700301 tools._finalise_for_test()
Simon Glassbf574f12019-07-20 12:24:09 -0600302
Simon Glass4f443042016-11-25 20:15:52 -0700303 def setUp(self):
304 # Enable this to turn on debugging output
Simon Glassf3385a52022-01-29 14:14:15 -0700305 # tout.init(tout.DEBUG)
Simon Glass4f443042016-11-25 20:15:52 -0700306 command.test_result = None
307
308 def tearDown(self):
309 """Remove the temporary output directory"""
Simon Glassbf574f12019-07-20 12:24:09 -0600310 self._CleanupOutputDir()
Simon Glass4f443042016-11-25 20:15:52 -0700311
Simon Glassf86a7362019-07-20 12:24:10 -0600312 def _SetupImageInTmpdir(self):
313 """Set up the output image in a new temporary directory
314
315 This is used when an image has been generated in the output directory,
316 but we want to run binman again. This will create a new output
317 directory and fail to delete the original one.
318
319 This creates a new temporary directory, copies the image to it (with a
320 new name) and removes the old output directory.
321
322 Returns:
323 Tuple:
324 Temporary directory to use
325 New image filename
326 """
Simon Glassc1aa66e2022-01-29 14:14:04 -0700327 image_fname = tools.get_output_filename('image.bin')
Simon Glassf86a7362019-07-20 12:24:10 -0600328 tmpdir = tempfile.mkdtemp(prefix='binman.')
329 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
Simon Glassc1aa66e2022-01-29 14:14:04 -0700330 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassf86a7362019-07-20 12:24:10 -0600331 self._CleanupOutputDir()
332 return tmpdir, updated_fname
333
Simon Glassb8ef5b62018-07-17 13:25:48 -0600334 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600335 def _ResetDtbs(cls):
Simon Glassb8ef5b62018-07-17 13:25:48 -0600336 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
337 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
338 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
Simon Glass6ad24522022-02-28 07:16:54 -0700339 TestFunctional._MakeInputFile('vpl/u-boot-vpl.dtb', U_BOOT_VPL_DTB_DATA)
Simon Glassb8ef5b62018-07-17 13:25:48 -0600340
Simon Glass4f443042016-11-25 20:15:52 -0700341 def _RunBinman(self, *args, **kwargs):
342 """Run binman using the command line
343
344 Args:
345 Arguments to pass, as a list of strings
346 kwargs: Arguments to pass to Command.RunPipe()
347 """
Simon Glassd9800692022-01-29 14:14:05 -0700348 result = command.run_pipe([[self._binman_pathname] + list(args)],
Simon Glass4f443042016-11-25 20:15:52 -0700349 capture=True, capture_stderr=True, raise_on_error=False)
350 if result.return_code and kwargs.get('raise_on_error', True):
351 raise Exception("Error running '%s': %s" % (' '.join(args),
352 result.stdout + result.stderr))
353 return result
354
Simon Glass53cd5d92019-07-08 14:25:29 -0600355 def _DoBinman(self, *argv):
Simon Glass4f443042016-11-25 20:15:52 -0700356 """Run binman using directly (in the same process)
357
358 Args:
359 Arguments to pass, as a list of strings
360 Returns:
361 Return value (0 for success)
362 """
Simon Glass53cd5d92019-07-08 14:25:29 -0600363 argv = list(argv)
364 args = cmdline.ParseArgs(argv)
365 args.pager = 'binman-invalid-pager'
366 args.build_dir = self._indir
Simon Glass4f443042016-11-25 20:15:52 -0700367
368 # For testing, you can force an increase in verbosity here
Simon Glass53cd5d92019-07-08 14:25:29 -0600369 # args.verbosity = tout.DEBUG
370 return control.Binman(args)
Simon Glass4f443042016-11-25 20:15:52 -0700371
Simon Glass53af22a2018-07-17 13:25:32 -0600372 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glasseb833d82019-04-25 21:58:34 -0600373 entry_args=None, images=None, use_real_dtb=False,
Simon Glass63aeaeb2021-03-18 20:25:05 +1300374 use_expanded=False, verbosity=None, allow_missing=False,
Heiko Thierya89c8f22022-01-06 11:49:41 +0100375 allow_fake_blobs=False, extra_indirs=None, threads=None,
Simon Glass4f9ee832022-01-09 20:14:09 -0700376 test_section_timeout=False, update_fdt_in_elf=None,
Andrew Davis15432ea2023-07-22 00:14:44 +0530377 force_missing_bintools='', ignore_missing=False, output_dir=None):
Simon Glass4f443042016-11-25 20:15:52 -0700378 """Run binman with a given test file
379
380 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600381 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600382 debug: True to enable debugging output
Simon Glass3b0c3822018-06-01 09:38:20 -0600383 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600384 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600385 tree before packing it into the image
Simon Glass0bfa7b02018-09-14 04:57:12 -0600386 entry_args: Dict of entry args to supply to binman
387 key: arg name
388 value: value of that arg
389 images: List of image names to build
Simon Glasse9d336d2020-09-01 05:13:55 -0600390 use_real_dtb: True to use the test file as the contents of
391 the u-boot-dtb entry. Normally this is not needed and the
392 test contents (the U_BOOT_DTB_DATA string) can be used.
393 But in some test we need the real contents.
Simon Glass63aeaeb2021-03-18 20:25:05 +1300394 use_expanded: True to use expanded entries where available, e.g.
395 'u-boot-expanded' instead of 'u-boot'
Simon Glasse9d336d2020-09-01 05:13:55 -0600396 verbosity: Verbosity level to use (0-3, None=don't set it)
397 allow_missing: Set the '--allow-missing' flag so that missing
398 external binaries just produce a warning instead of an error
Heiko Thierya89c8f22022-01-06 11:49:41 +0100399 allow_fake_blobs: Set the '--fake-ext-blobs' flag
Simon Glass6cf99532020-09-01 05:13:59 -0600400 extra_indirs: Extra input directories to add using -I
Simon Glassc69d19c2021-07-06 10:36:37 -0600401 threads: Number of threads to use (None for default, 0 for
402 single-threaded)
Simon Glass7115f002021-11-03 21:09:17 -0600403 test_section_timeout: True to force the first time to timeout, as
404 used in testThreadTimeout()
Simon Glass0427bed2021-11-03 21:09:18 -0600405 update_fdt_in_elf: Value to pass with --update-fdt-in-elf=xxx
Simon Glass4f9ee832022-01-09 20:14:09 -0700406 force_missing_tools (str): comma-separated list of bintools to
407 regard as missing
Andrew Davis15432ea2023-07-22 00:14:44 +0530408 output_dir: Specific output directory to use for image using -O
Simon Glass7115f002021-11-03 21:09:17 -0600409
410 Returns:
411 int return code, 0 on success
Simon Glass4f443042016-11-25 20:15:52 -0700412 """
Simon Glass53cd5d92019-07-08 14:25:29 -0600413 args = []
Simon Glass7fe91732017-11-13 18:55:00 -0700414 if debug:
415 args.append('-D')
Simon Glass53cd5d92019-07-08 14:25:29 -0600416 if verbosity is not None:
417 args.append('-v%d' % verbosity)
418 elif self.verbosity:
419 args.append('-v%d' % self.verbosity)
420 if self.toolpath:
421 for path in self.toolpath:
422 args += ['--toolpath', path]
Simon Glassc69d19c2021-07-06 10:36:37 -0600423 if threads is not None:
424 args.append('-T%d' % threads)
425 if test_section_timeout:
426 args.append('--test-section-timeout')
Simon Glass53cd5d92019-07-08 14:25:29 -0600427 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass3b0c3822018-06-01 09:38:20 -0600428 if map:
429 args.append('-m')
Simon Glass16b8d6b2018-07-06 10:27:42 -0600430 if update_dtb:
Simon Glass2569e102019-07-08 13:18:47 -0600431 args.append('-u')
Simon Glass93d17412018-09-14 04:57:23 -0600432 if not use_real_dtb:
433 args.append('--fake-dtb')
Simon Glass63aeaeb2021-03-18 20:25:05 +1300434 if not use_expanded:
435 args.append('--no-expanded')
Simon Glass53af22a2018-07-17 13:25:32 -0600436 if entry_args:
Simon Glass50979152019-05-14 15:53:41 -0600437 for arg, value in entry_args.items():
Simon Glass53af22a2018-07-17 13:25:32 -0600438 args.append('-a%s=%s' % (arg, value))
Simon Glass4f9f1052020-07-09 18:39:38 -0600439 if allow_missing:
440 args.append('-M')
Simon Glassb38da152022-11-09 19:14:42 -0700441 if ignore_missing:
442 args.append('-W')
Heiko Thierya89c8f22022-01-06 11:49:41 +0100443 if allow_fake_blobs:
444 args.append('--fake-ext-blobs')
Simon Glass4f9ee832022-01-09 20:14:09 -0700445 if force_missing_bintools:
446 args += ['--force-missing-bintools', force_missing_bintools]
Simon Glass0427bed2021-11-03 21:09:18 -0600447 if update_fdt_in_elf:
448 args += ['--update-fdt-in-elf', update_fdt_in_elf]
Simon Glass0bfa7b02018-09-14 04:57:12 -0600449 if images:
450 for image in images:
451 args += ['-i', image]
Simon Glass6cf99532020-09-01 05:13:59 -0600452 if extra_indirs:
453 for indir in extra_indirs:
454 args += ['-I', indir]
Andrew Davis15432ea2023-07-22 00:14:44 +0530455 if output_dir:
456 args += ['-O', output_dir]
Simon Glass7fe91732017-11-13 18:55:00 -0700457 return self._DoBinman(*args)
Simon Glass4f443042016-11-25 20:15:52 -0700458
459 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glasse0ff8552016-11-25 20:15:53 -0700460 """Set up a new test device-tree file
461
462 The given file is compiled and set up as the device tree to be used
463 for ths test.
464
465 Args:
466 fname: Filename of .dts file to read
Simon Glass7ae5f312018-06-01 09:38:19 -0600467 outfile: Output filename for compiled device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700468
469 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600470 Contents of device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700471 """
Simon Glassa004f292019-07-20 12:23:49 -0600472 tmpdir = tempfile.mkdtemp(prefix='binmant.')
473 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
Simon Glass1d0ebf72019-05-14 15:53:42 -0600474 with open(dtb, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700475 data = fd.read()
476 TestFunctional._MakeInputFile(outfile, data)
Simon Glassa004f292019-07-20 12:23:49 -0600477 shutil.rmtree(tmpdir)
Simon Glasse0e62752018-10-01 21:12:41 -0600478 return data
Simon Glass4f443042016-11-25 20:15:52 -0700479
Simon Glass6ad24522022-02-28 07:16:54 -0700480 def _GetDtbContentsForSpls(self, dtb_data, name):
481 """Create a version of the main DTB for SPL / TPL / VPL
Simon Glass6ed45ba2018-09-14 04:57:24 -0600482
483 For testing we don't actually have different versions of the DTB. With
484 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
485 we don't normally have any unwanted nodes.
486
487 We still want the DTBs for SPL and TPL to be different though, since
488 otherwise it is confusing to know which one we are looking at. So add
489 an 'spl' or 'tpl' property to the top-level node.
Simon Glasse9d336d2020-09-01 05:13:55 -0600490
491 Args:
492 dtb_data: dtb data to modify (this should be a value devicetree)
493 name: Name of a new property to add
494
495 Returns:
496 New dtb data with the property added
Simon Glass6ed45ba2018-09-14 04:57:24 -0600497 """
498 dtb = fdt.Fdt.FromData(dtb_data)
499 dtb.Scan()
500 dtb.GetNode('/binman').AddZeroProp(name)
501 dtb.Sync(auto_resize=True)
502 dtb.Pack()
503 return dtb.GetContents()
504
Simon Glass63aeaeb2021-03-18 20:25:05 +1300505 def _DoReadFileDtb(self, fname, use_real_dtb=False, use_expanded=False,
506 map=False, update_dtb=False, entry_args=None,
Simon Glassc69d19c2021-07-06 10:36:37 -0600507 reset_dtbs=True, extra_indirs=None, threads=None):
Simon Glass4f443042016-11-25 20:15:52 -0700508 """Run binman and return the resulting image
509
510 This runs binman with a given test file and then reads the resulting
511 output file. It is a shortcut function since most tests need to do
512 these steps.
513
514 Raises an assertion failure if binman returns a non-zero exit code.
515
516 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600517 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass4f443042016-11-25 20:15:52 -0700518 use_real_dtb: True to use the test file as the contents of
519 the u-boot-dtb entry. Normally this is not needed and the
520 test contents (the U_BOOT_DTB_DATA string) can be used.
521 But in some test we need the real contents.
Simon Glass63aeaeb2021-03-18 20:25:05 +1300522 use_expanded: True to use expanded entries where available, e.g.
523 'u-boot-expanded' instead of 'u-boot'
Simon Glass3b0c3822018-06-01 09:38:20 -0600524 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600525 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600526 tree before packing it into the image
Simon Glasse9d336d2020-09-01 05:13:55 -0600527 entry_args: Dict of entry args to supply to binman
528 key: arg name
529 value: value of that arg
530 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
531 function. If reset_dtbs is True, then the original test dtb
532 is written back before this function finishes
Simon Glass6cf99532020-09-01 05:13:59 -0600533 extra_indirs: Extra input directories to add using -I
Simon Glassc69d19c2021-07-06 10:36:37 -0600534 threads: Number of threads to use (None for default, 0 for
535 single-threaded)
Simon Glasse0ff8552016-11-25 20:15:53 -0700536
537 Returns:
538 Tuple:
539 Resulting image contents
540 Device tree contents
Simon Glass3b0c3822018-06-01 09:38:20 -0600541 Map data showing contents of image (or None if none)
Simon Glassea6922e2018-07-17 13:25:27 -0600542 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass4f443042016-11-25 20:15:52 -0700543 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700544 dtb_data = None
Simon Glass4f443042016-11-25 20:15:52 -0700545 # Use the compiled test file as the u-boot-dtb input
546 if use_real_dtb:
Simon Glasse0ff8552016-11-25 20:15:53 -0700547 dtb_data = self._SetupDtb(fname)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600548
549 # For testing purposes, make a copy of the DT for SPL and TPL. Add
Simon Glass57208dd2024-07-20 11:49:40 +0100550 # a node indicating which it is, to aid verification.
Simon Glass6ad24522022-02-28 07:16:54 -0700551 for name in ['spl', 'tpl', 'vpl']:
Simon Glass6ed45ba2018-09-14 04:57:24 -0600552 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
553 outfile = os.path.join(self._indir, dtb_fname)
554 TestFunctional._MakeInputFile(dtb_fname,
Simon Glass6ad24522022-02-28 07:16:54 -0700555 self._GetDtbContentsForSpls(dtb_data, name))
Simon Glass4f443042016-11-25 20:15:52 -0700556
557 try:
Simon Glass53af22a2018-07-17 13:25:32 -0600558 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glass6cf99532020-09-01 05:13:59 -0600559 entry_args=entry_args, use_real_dtb=use_real_dtb,
Simon Glassc69d19c2021-07-06 10:36:37 -0600560 use_expanded=use_expanded, extra_indirs=extra_indirs,
561 threads=threads)
Simon Glass4f443042016-11-25 20:15:52 -0700562 self.assertEqual(0, retcode)
Simon Glassc1aa66e2022-01-29 14:14:04 -0700563 out_dtb_fname = tools.get_output_filename('u-boot.dtb.out')
Simon Glass4f443042016-11-25 20:15:52 -0700564
565 # Find the (only) image, read it and return its contents
566 image = control.images['image']
Simon Glassc1aa66e2022-01-29 14:14:04 -0700567 image_fname = tools.get_output_filename('image.bin')
Simon Glass16b8d6b2018-07-06 10:27:42 -0600568 self.assertTrue(os.path.exists(image_fname))
Simon Glass3b0c3822018-06-01 09:38:20 -0600569 if map:
Simon Glassc1aa66e2022-01-29 14:14:04 -0700570 map_fname = tools.get_output_filename('image.map')
Simon Glass3b0c3822018-06-01 09:38:20 -0600571 with open(map_fname) as fd:
572 map_data = fd.read()
573 else:
574 map_data = None
Simon Glass1d0ebf72019-05-14 15:53:42 -0600575 with open(image_fname, 'rb') as fd:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600576 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass4f443042016-11-25 20:15:52 -0700577 finally:
578 # Put the test file back
Simon Glass6ed45ba2018-09-14 04:57:24 -0600579 if reset_dtbs and use_real_dtb:
Simon Glassb8ef5b62018-07-17 13:25:48 -0600580 self._ResetDtbs()
Simon Glass4f443042016-11-25 20:15:52 -0700581
Simon Glass3c081312019-07-08 14:25:26 -0600582 def _DoReadFileRealDtb(self, fname):
583 """Run binman with a real .dtb file and return the resulting data
584
585 Args:
586 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
587
588 Returns:
589 Resulting image contents
590 """
591 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
592
Simon Glasse0ff8552016-11-25 20:15:53 -0700593 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass7ae5f312018-06-01 09:38:19 -0600594 """Helper function which discards the device-tree binary
595
596 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600597 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600598 use_real_dtb: True to use the test file as the contents of
599 the u-boot-dtb entry. Normally this is not needed and the
600 test contents (the U_BOOT_DTB_DATA string) can be used.
601 But in some test we need the real contents.
Simon Glassea6922e2018-07-17 13:25:27 -0600602
603 Returns:
604 Resulting image contents
Simon Glass7ae5f312018-06-01 09:38:19 -0600605 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700606 return self._DoReadFileDtb(fname, use_real_dtb)[0]
607
Simon Glass4f443042016-11-25 20:15:52 -0700608 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600609 def _MakeInputFile(cls, fname, contents):
Simon Glass4f443042016-11-25 20:15:52 -0700610 """Create a new test input file, creating directories as needed
611
612 Args:
Simon Glass3ab95982018-08-01 15:22:37 -0600613 fname: Filename to create
Simon Glass4f443042016-11-25 20:15:52 -0700614 contents: File contents to write in to the file
615 Returns:
616 Full pathname of file created
617 """
Simon Glassb986b3b2019-08-24 07:22:43 -0600618 pathname = os.path.join(cls._indir, fname)
Simon Glass4f443042016-11-25 20:15:52 -0700619 dirname = os.path.dirname(pathname)
620 if dirname and not os.path.exists(dirname):
621 os.makedirs(dirname)
622 with open(pathname, 'wb') as fd:
623 fd.write(contents)
624 return pathname
625
626 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600627 def _MakeInputDir(cls, dirname):
Simon Glass0ef87aa2018-07-17 13:25:44 -0600628 """Create a new test input directory, creating directories as needed
629
630 Args:
631 dirname: Directory name to create
632
633 Returns:
634 Full pathname of directory created
635 """
Simon Glassb986b3b2019-08-24 07:22:43 -0600636 pathname = os.path.join(cls._indir, dirname)
Simon Glass0ef87aa2018-07-17 13:25:44 -0600637 if not os.path.exists(pathname):
638 os.makedirs(pathname)
639 return pathname
640
641 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600642 def _SetupSplElf(cls, src_fname='bss_data'):
Simon Glass11ae93e2018-10-01 21:12:47 -0600643 """Set up an ELF file with a '_dt_ucode_base_size' symbol
644
645 Args:
646 Filename of ELF file to use as SPL
647 """
Simon Glassc9a0b272019-08-24 07:22:59 -0600648 TestFunctional._MakeInputFile('spl/u-boot-spl',
Simon Glassc1aa66e2022-01-29 14:14:04 -0700649 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass11ae93e2018-10-01 21:12:47 -0600650
651 @classmethod
Simon Glass2090f1e2019-08-24 07:23:00 -0600652 def _SetupTplElf(cls, src_fname='bss_data'):
653 """Set up an ELF file with a '_dt_ucode_base_size' symbol
654
655 Args:
656 Filename of ELF file to use as TPL
657 """
658 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
Simon Glassc1aa66e2022-01-29 14:14:04 -0700659 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass2090f1e2019-08-24 07:23:00 -0600660
661 @classmethod
Simon Glass6ad24522022-02-28 07:16:54 -0700662 def _SetupVplElf(cls, src_fname='bss_data'):
663 """Set up an ELF file with a '_dt_ucode_base_size' symbol
664
665 Args:
666 Filename of ELF file to use as VPL
667 """
668 TestFunctional._MakeInputFile('vpl/u-boot-vpl',
669 tools.read_file(cls.ElfTestFile(src_fname)))
670
671 @classmethod
Lukas Funke8c1fbd12023-07-18 13:53:13 +0200672 def _SetupPmuFwlElf(cls, src_fname='bss_data'):
673 """Set up an ELF file with a '_dt_ucode_base_size' symbol
674
675 Args:
676 Filename of ELF file to use as VPL
677 """
678 TestFunctional._MakeInputFile('pmu-firmware.elf',
679 tools.read_file(cls.ElfTestFile(src_fname)))
680
681 @classmethod
Simon Glass0ba4b3d2020-07-09 18:39:41 -0600682 def _SetupDescriptor(cls):
683 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
684 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
685
686 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600687 def TestFile(cls, fname):
688 return os.path.join(cls._binman_dir, 'test', fname)
Simon Glass4f443042016-11-25 20:15:52 -0700689
Simon Glass53e22bf2019-08-24 07:22:53 -0600690 @classmethod
691 def ElfTestFile(cls, fname):
692 return os.path.join(cls._elf_testdir, fname)
693
Simon Glass2f80c5e2023-01-07 14:07:14 -0700694 @classmethod
695 def make_tee_bin(cls, fname, paged_sz=0, extra_data=b''):
696 init_sz, start_hi, start_lo, dummy = (len(U_BOOT_DATA), 0, TEE_ADDR, 0)
697 data = b'OPTE\x01xxx' + struct.pack('<5I', init_sz, start_hi, start_lo,
698 dummy, paged_sz) + U_BOOT_DATA
699 data += extra_data
700 TestFunctional._MakeInputFile(fname, data)
701
Simon Glass4f443042016-11-25 20:15:52 -0700702 def AssertInList(self, grep_list, target):
703 """Assert that at least one of a list of things is in a target
704
705 Args:
706 grep_list: List of strings to check
707 target: Target string
708 """
709 for grep in grep_list:
710 if grep in target:
711 return
Simon Glass1fc62de2019-05-17 22:00:50 -0600712 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass4f443042016-11-25 20:15:52 -0700713
714 def CheckNoGaps(self, entries):
715 """Check that all entries fit together without gaps
716
717 Args:
718 entries: List of entries to check
719 """
Simon Glass3ab95982018-08-01 15:22:37 -0600720 offset = 0
Simon Glass4f443042016-11-25 20:15:52 -0700721 for entry in entries.values():
Simon Glass3ab95982018-08-01 15:22:37 -0600722 self.assertEqual(offset, entry.offset)
723 offset += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700724
Simon Glasse0ff8552016-11-25 20:15:53 -0700725 def GetFdtLen(self, dtb):
Simon Glass7ae5f312018-06-01 09:38:19 -0600726 """Get the totalsize field from a device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700727
728 Args:
Simon Glass7ae5f312018-06-01 09:38:19 -0600729 dtb: Device-tree binary contents
Simon Glasse0ff8552016-11-25 20:15:53 -0700730
731 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600732 Total size of device-tree binary, from the header
Simon Glasse0ff8552016-11-25 20:15:53 -0700733 """
734 return struct.unpack('>L', dtb[4:8])[0]
735
Simon Glass086cec92019-07-08 14:25:27 -0600736 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glass16b8d6b2018-07-06 10:27:42 -0600737 def AddNode(node, path):
738 if node.name != '/':
739 path += '/' + node.name
Simon Glass086cec92019-07-08 14:25:27 -0600740 for prop in node.props.values():
741 if prop.name in prop_names:
742 prop_path = path + ':' + prop.name
743 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
744 prop.value)
Simon Glass16b8d6b2018-07-06 10:27:42 -0600745 for subnode in node.subnodes:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600746 AddNode(subnode, path)
747
748 tree = {}
Simon Glass16b8d6b2018-07-06 10:27:42 -0600749 AddNode(dtb.GetRoot(), '')
750 return tree
751
Ivan Mikhaylov5b34efe2023-03-08 01:13:40 +0000752 def _CheckSign(self, fit, key):
753 try:
754 tools.run('fit_check_sign', '-k', key, '-f', fit)
755 except:
756 self.fail('Expected signed FIT container')
757 return False
758 return True
759
Simon Glass4f443042016-11-25 20:15:52 -0700760 def testRun(self):
761 """Test a basic run with valid args"""
762 result = self._RunBinman('-h')
763
764 def testFullHelp(self):
765 """Test that the full help is displayed with -H"""
766 result = self._RunBinman('-H')
Simon Glass61adb2d2021-03-18 20:25:13 +1300767 help_file = os.path.join(self._binman_dir, 'README.rst')
Tom Rini3759df02018-01-16 15:29:50 -0500768 # Remove possible extraneous strings
769 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
770 gothelp = result.stdout.replace(extra, '')
771 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass4f443042016-11-25 20:15:52 -0700772 self.assertEqual(0, len(result.stderr))
773 self.assertEqual(0, result.return_code)
774
775 def testFullHelpInternal(self):
776 """Test that the full help is displayed with -H"""
777 try:
778 command.test_result = command.CommandResult()
779 result = self._DoBinman('-H')
Simon Glass61adb2d2021-03-18 20:25:13 +1300780 help_file = os.path.join(self._binman_dir, 'README.rst')
Simon Glass4f443042016-11-25 20:15:52 -0700781 finally:
782 command.test_result = None
783
784 def testHelp(self):
785 """Test that the basic help is displayed with -h"""
786 result = self._RunBinman('-h')
787 self.assertTrue(len(result.stdout) > 200)
788 self.assertEqual(0, len(result.stderr))
789 self.assertEqual(0, result.return_code)
790
Simon Glass4f443042016-11-25 20:15:52 -0700791 def testBoard(self):
792 """Test that we can run it with a specific board"""
Simon Glass741f2d62018-10-01 12:22:30 -0600793 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass4f443042016-11-25 20:15:52 -0700794 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glass63aeaeb2021-03-18 20:25:05 +1300795 result = self._DoBinman('build', '-n', '-b', 'sandbox')
Simon Glass4f443042016-11-25 20:15:52 -0700796 self.assertEqual(0, result)
797
798 def testNeedBoard(self):
799 """Test that we get an error when no board ius supplied"""
800 with self.assertRaises(ValueError) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600801 result = self._DoBinman('build')
Simon Glass4f443042016-11-25 20:15:52 -0700802 self.assertIn("Must provide a board to process (use -b <board>)",
803 str(e.exception))
804
805 def testMissingDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600806 """Test that an invalid device-tree file generates an error"""
Simon Glass4f443042016-11-25 20:15:52 -0700807 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600808 self._RunBinman('build', '-d', 'missing_file')
Simon Glass4f443042016-11-25 20:15:52 -0700809 # We get one error from libfdt, and a different one from fdtget.
810 self.AssertInList(["Couldn't open blob from 'missing_file'",
811 'No such file or directory'], str(e.exception))
812
813 def testBrokenDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600814 """Test that an invalid device-tree source file generates an error
Simon Glass4f443042016-11-25 20:15:52 -0700815
816 Since this is a source file it should be compiled and the error
817 will come from the device-tree compiler (dtc).
818 """
819 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600820 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700821 self.assertIn("FATAL ERROR: Unable to parse input tree",
822 str(e.exception))
823
824 def testMissingNode(self):
825 """Test that a device tree without a 'binman' node generates an error"""
826 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600827 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700828 self.assertIn("does not have a 'binman' node", str(e.exception))
829
830 def testEmpty(self):
831 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glass53cd5d92019-07-08 14:25:29 -0600832 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700833 self.assertEqual(0, len(result.stderr))
834 self.assertEqual(0, result.return_code)
835
836 def testInvalidEntry(self):
837 """Test that an invalid entry is flagged"""
838 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600839 result = self._RunBinman('build', '-d',
Simon Glass741f2d62018-10-01 12:22:30 -0600840 self.TestFile('004_invalid_entry.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700841 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
842 "'/binman/not-a-valid-type'", str(e.exception))
843
844 def testSimple(self):
845 """Test a simple binman with a single file"""
Simon Glass741f2d62018-10-01 12:22:30 -0600846 data = self._DoReadFile('005_simple.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700847 self.assertEqual(U_BOOT_DATA, data)
848
Simon Glass7fe91732017-11-13 18:55:00 -0700849 def testSimpleDebug(self):
850 """Test a simple binman run with debugging enabled"""
Simon Glasse2705fa2019-07-08 14:25:53 -0600851 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass7fe91732017-11-13 18:55:00 -0700852
Simon Glass4f443042016-11-25 20:15:52 -0700853 def testDual(self):
854 """Test that we can handle creating two images
855
856 This also tests image padding.
857 """
Simon Glass741f2d62018-10-01 12:22:30 -0600858 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700859 self.assertEqual(0, retcode)
860
861 image = control.images['image1']
Simon Glass8beb11e2019-07-08 14:25:47 -0600862 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glassc1aa66e2022-01-29 14:14:04 -0700863 fname = tools.get_output_filename('image1.bin')
Simon Glass4f443042016-11-25 20:15:52 -0700864 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600865 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700866 data = fd.read()
867 self.assertEqual(U_BOOT_DATA, data)
868
869 image = control.images['image2']
Simon Glass8beb11e2019-07-08 14:25:47 -0600870 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glassc1aa66e2022-01-29 14:14:04 -0700871 fname = tools.get_output_filename('image2.bin')
Simon Glass4f443042016-11-25 20:15:52 -0700872 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600873 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700874 data = fd.read()
875 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glassc1aa66e2022-01-29 14:14:04 -0700876 self.assertEqual(tools.get_bytes(0, 3), data[:3])
877 self.assertEqual(tools.get_bytes(0, 5), data[7:])
Simon Glass4f443042016-11-25 20:15:52 -0700878
879 def testBadAlign(self):
880 """Test that an invalid alignment value is detected"""
881 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600882 self._DoTestFile('007_bad_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700883 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
884 "of two", str(e.exception))
885
886 def testPackSimple(self):
887 """Test that packing works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600888 retcode = self._DoTestFile('008_pack.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700889 self.assertEqual(0, retcode)
890 self.assertIn('image', control.images)
891 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600892 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700893 self.assertEqual(5, len(entries))
894
895 # First u-boot
896 self.assertIn('u-boot', entries)
897 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600898 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700899 self.assertEqual(len(U_BOOT_DATA), entry.size)
900
901 # Second u-boot, aligned to 16-byte boundary
902 self.assertIn('u-boot-align', entries)
903 entry = entries['u-boot-align']
Simon Glass3ab95982018-08-01 15:22:37 -0600904 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700905 self.assertEqual(len(U_BOOT_DATA), entry.size)
906
907 # Third u-boot, size 23 bytes
908 self.assertIn('u-boot-size', entries)
909 entry = entries['u-boot-size']
Simon Glass3ab95982018-08-01 15:22:37 -0600910 self.assertEqual(20, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700911 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
912 self.assertEqual(23, entry.size)
913
914 # Fourth u-boot, placed immediate after the above
915 self.assertIn('u-boot-next', entries)
916 entry = entries['u-boot-next']
Simon Glass3ab95982018-08-01 15:22:37 -0600917 self.assertEqual(43, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700918 self.assertEqual(len(U_BOOT_DATA), entry.size)
919
Simon Glass3ab95982018-08-01 15:22:37 -0600920 # Fifth u-boot, placed at a fixed offset
Simon Glass4f443042016-11-25 20:15:52 -0700921 self.assertIn('u-boot-fixed', entries)
922 entry = entries['u-boot-fixed']
Simon Glass3ab95982018-08-01 15:22:37 -0600923 self.assertEqual(61, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700924 self.assertEqual(len(U_BOOT_DATA), entry.size)
925
Simon Glass8beb11e2019-07-08 14:25:47 -0600926 self.assertEqual(65, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700927
928 def testPackExtra(self):
929 """Test that extra packing feature works as expected"""
Simon Glass4eec34c2020-10-26 17:40:10 -0600930 data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
931 update_dtb=True)
Simon Glass4f443042016-11-25 20:15:52 -0700932
Simon Glass4f443042016-11-25 20:15:52 -0700933 self.assertIn('image', control.images)
934 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600935 entries = image.GetEntries()
Samuel Hollandb01ae032023-01-21 17:25:16 -0600936 self.assertEqual(6, len(entries))
Simon Glass4f443042016-11-25 20:15:52 -0700937
Samuel Hollandb01ae032023-01-21 17:25:16 -0600938 # First u-boot with padding before and after (included in minimum size)
Simon Glass4f443042016-11-25 20:15:52 -0700939 self.assertIn('u-boot', entries)
940 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600941 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700942 self.assertEqual(3, entry.pad_before)
943 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600944 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassc1aa66e2022-01-29 14:14:04 -0700945 self.assertEqual(tools.get_bytes(0, 3) + U_BOOT_DATA +
946 tools.get_bytes(0, 5), data[:entry.size])
Simon Glassef439ed2020-10-26 17:40:08 -0600947 pos = entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700948
949 # Second u-boot has an aligned size, but it has no effect
950 self.assertIn('u-boot-align-size-nop', entries)
951 entry = entries['u-boot-align-size-nop']
Simon Glassef439ed2020-10-26 17:40:08 -0600952 self.assertEqual(pos, entry.offset)
953 self.assertEqual(len(U_BOOT_DATA), entry.size)
954 self.assertEqual(U_BOOT_DATA, entry.data)
955 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
956 pos += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700957
958 # Third u-boot has an aligned size too
959 self.assertIn('u-boot-align-size', entries)
960 entry = entries['u-boot-align-size']
Simon Glassef439ed2020-10-26 17:40:08 -0600961 self.assertEqual(pos, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700962 self.assertEqual(32, entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600963 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassc1aa66e2022-01-29 14:14:04 -0700964 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
Simon Glassef439ed2020-10-26 17:40:08 -0600965 data[pos:pos + entry.size])
966 pos += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700967
968 # Fourth u-boot has an aligned end
969 self.assertIn('u-boot-align-end', entries)
970 entry = entries['u-boot-align-end']
Simon Glass3ab95982018-08-01 15:22:37 -0600971 self.assertEqual(48, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700972 self.assertEqual(16, entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600973 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glassc1aa66e2022-01-29 14:14:04 -0700974 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 16 - len(U_BOOT_DATA)),
Simon Glassef439ed2020-10-26 17:40:08 -0600975 data[pos:pos + entry.size])
976 pos += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700977
978 # Fifth u-boot immediately afterwards
979 self.assertIn('u-boot-align-both', entries)
980 entry = entries['u-boot-align-both']
Simon Glass3ab95982018-08-01 15:22:37 -0600981 self.assertEqual(64, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700982 self.assertEqual(64, entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600983 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glassc1aa66e2022-01-29 14:14:04 -0700984 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 64 - len(U_BOOT_DATA)),
Simon Glassef439ed2020-10-26 17:40:08 -0600985 data[pos:pos + entry.size])
Simon Glass4f443042016-11-25 20:15:52 -0700986
Samuel Hollandb01ae032023-01-21 17:25:16 -0600987 # Sixth u-boot with both minimum size and aligned size
988 self.assertIn('u-boot-min-size', entries)
989 entry = entries['u-boot-min-size']
990 self.assertEqual(128, entry.offset)
991 self.assertEqual(32, entry.size)
992 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
993 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
994 data[pos:pos + entry.size])
995
Simon Glass4f443042016-11-25 20:15:52 -0700996 self.CheckNoGaps(entries)
Samuel Hollandb01ae032023-01-21 17:25:16 -0600997 self.assertEqual(160, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700998
Simon Glass4eec34c2020-10-26 17:40:10 -0600999 dtb = fdt.Fdt(out_dtb_fname)
1000 dtb.Scan()
1001 props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
1002 expected = {
1003 'image-pos': 0,
1004 'offset': 0,
Samuel Hollandb01ae032023-01-21 17:25:16 -06001005 'size': 160,
Simon Glass4eec34c2020-10-26 17:40:10 -06001006
1007 'u-boot:image-pos': 0,
1008 'u-boot:offset': 0,
1009 'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
1010
1011 'u-boot-align-size-nop:image-pos': 12,
1012 'u-boot-align-size-nop:offset': 12,
1013 'u-boot-align-size-nop:size': 4,
1014
1015 'u-boot-align-size:image-pos': 16,
1016 'u-boot-align-size:offset': 16,
1017 'u-boot-align-size:size': 32,
1018
1019 'u-boot-align-end:image-pos': 48,
1020 'u-boot-align-end:offset': 48,
1021 'u-boot-align-end:size': 16,
1022
1023 'u-boot-align-both:image-pos': 64,
1024 'u-boot-align-both:offset': 64,
1025 'u-boot-align-both:size': 64,
Samuel Hollandb01ae032023-01-21 17:25:16 -06001026
1027 'u-boot-min-size:image-pos': 128,
1028 'u-boot-min-size:offset': 128,
1029 'u-boot-min-size:size': 32,
Simon Glass4eec34c2020-10-26 17:40:10 -06001030 }
1031 self.assertEqual(expected, props)
1032
Simon Glass4f443042016-11-25 20:15:52 -07001033 def testPackAlignPowerOf2(self):
1034 """Test that invalid entry alignment is detected"""
1035 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001036 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001037 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
1038 "of two", str(e.exception))
1039
1040 def testPackAlignSizePowerOf2(self):
1041 """Test that invalid entry size alignment is detected"""
1042 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001043 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001044 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
1045 "power of two", str(e.exception))
1046
1047 def testPackInvalidAlign(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001048 """Test detection of an offset that does not match its alignment"""
Simon Glass4f443042016-11-25 20:15:52 -07001049 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001050 self._DoTestFile('012_pack_inv_align.dts')
Simon Glass3ab95982018-08-01 15:22:37 -06001051 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass4f443042016-11-25 20:15:52 -07001052 "align 0x4 (4)", str(e.exception))
1053
1054 def testPackInvalidSizeAlign(self):
1055 """Test that invalid entry size alignment is detected"""
1056 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001057 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001058 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
1059 "align-size 0x4 (4)", str(e.exception))
1060
1061 def testPackOverlap(self):
1062 """Test that overlapping regions are detected"""
1063 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001064 self._DoTestFile('014_pack_overlap.dts')
Simon Glass3ab95982018-08-01 15:22:37 -06001065 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -07001066 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1067 str(e.exception))
1068
1069 def testPackEntryOverflow(self):
1070 """Test that entries that overflow their size are detected"""
1071 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001072 self._DoTestFile('015_pack_overflow.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001073 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
1074 "but entry size is 0x3 (3)", str(e.exception))
1075
1076 def testPackImageOverflow(self):
1077 """Test that entries which overflow the image size are detected"""
1078 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001079 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glass8f1da502018-06-01 09:38:12 -06001080 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass4f443042016-11-25 20:15:52 -07001081 "size 0x3 (3)", str(e.exception))
1082
1083 def testPackImageSize(self):
1084 """Test that the image size can be set"""
Simon Glass741f2d62018-10-01 12:22:30 -06001085 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001086 self.assertEqual(0, retcode)
1087 self.assertIn('image', control.images)
1088 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -06001089 self.assertEqual(7, image.size)
Simon Glass4f443042016-11-25 20:15:52 -07001090
1091 def testPackImageSizeAlign(self):
1092 """Test that image size alignemnt works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -06001093 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001094 self.assertEqual(0, retcode)
1095 self.assertIn('image', control.images)
1096 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -06001097 self.assertEqual(16, image.size)
Simon Glass4f443042016-11-25 20:15:52 -07001098
1099 def testPackInvalidImageAlign(self):
1100 """Test that invalid image alignment is detected"""
1101 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001102 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glass8f1da502018-06-01 09:38:12 -06001103 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass4f443042016-11-25 20:15:52 -07001104 "align-size 0x8 (8)", str(e.exception))
1105
Simon Glass8d2ef3e2022-02-11 13:23:21 -07001106 def testPackAlignPowerOf2Inv(self):
Simon Glass4f443042016-11-25 20:15:52 -07001107 """Test that invalid image alignment is detected"""
1108 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001109 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -06001110 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass4f443042016-11-25 20:15:52 -07001111 "two", str(e.exception))
1112
1113 def testImagePadByte(self):
1114 """Test that the image pad byte can be specified"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001115 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001116 data = self._DoReadFile('021_image_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001117 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0xff, 1) +
Simon Glasse6d85ff2019-05-14 15:53:47 -06001118 U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -07001119
1120 def testImageName(self):
1121 """Test that image files can be named"""
Simon Glass741f2d62018-10-01 12:22:30 -06001122 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001123 self.assertEqual(0, retcode)
1124 image = control.images['image1']
Simon Glassc1aa66e2022-01-29 14:14:04 -07001125 fname = tools.get_output_filename('test-name')
Simon Glass4f443042016-11-25 20:15:52 -07001126 self.assertTrue(os.path.exists(fname))
1127
1128 image = control.images['image2']
Simon Glassc1aa66e2022-01-29 14:14:04 -07001129 fname = tools.get_output_filename('test-name.xx')
Simon Glass4f443042016-11-25 20:15:52 -07001130 self.assertTrue(os.path.exists(fname))
1131
1132 def testBlobFilename(self):
1133 """Test that generic blobs can be provided by filename"""
Simon Glass741f2d62018-10-01 12:22:30 -06001134 data = self._DoReadFile('023_blob.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001135 self.assertEqual(BLOB_DATA, data)
1136
1137 def testPackSorted(self):
1138 """Test that entries can be sorted"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001139 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001140 data = self._DoReadFile('024_sorted.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001141 self.assertEqual(tools.get_bytes(0, 1) + U_BOOT_SPL_DATA +
1142 tools.get_bytes(0, 2) + U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -07001143
Simon Glass3ab95982018-08-01 15:22:37 -06001144 def testPackZeroOffset(self):
1145 """Test that an entry at offset 0 is not given a new offset"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06001146 self._SetupSplElf()
Simon Glass4f443042016-11-25 20:15:52 -07001147 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001148 self._DoTestFile('025_pack_zero_size.dts')
Simon Glass3ab95982018-08-01 15:22:37 -06001149 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -07001150 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1151 str(e.exception))
1152
1153 def testPackUbootDtb(self):
1154 """Test that a device tree can be added to U-Boot"""
Simon Glass741f2d62018-10-01 12:22:30 -06001155 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001156 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glasse0ff8552016-11-25 20:15:53 -07001157
1158 def testPackX86RomNoSize(self):
1159 """Test that the end-at-4gb property requires a size property"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06001160 self._SetupSplElf()
Simon Glasse0ff8552016-11-25 20:15:53 -07001161 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001162 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -06001163 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glasse0ff8552016-11-25 20:15:53 -07001164 "using end-at-4gb", str(e.exception))
1165
Jagdish Gediya94b57db2018-09-03 21:35:07 +05301166 def test4gbAndSkipAtStartTogether(self):
1167 """Test that the end-at-4gb and skip-at-size property can't be used
1168 together"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06001169 self._SetupSplElf()
Jagdish Gediya94b57db2018-09-03 21:35:07 +05301170 with self.assertRaises(ValueError) as e:
Simon Glassdfdd2b62019-08-24 07:23:02 -06001171 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -06001172 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya94b57db2018-09-03 21:35:07 +05301173 "'skip-at-start'", str(e.exception))
1174
Simon Glasse0ff8552016-11-25 20:15:53 -07001175 def testPackX86RomOutside(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001176 """Test that the end-at-4gb property checks for offset boundaries"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06001177 self._SetupSplElf()
Simon Glasse0ff8552016-11-25 20:15:53 -07001178 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001179 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glasse6bed4f2020-10-26 17:40:05 -06001180 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
1181 "is outside the section '/binman' starting at "
1182 '0xffffffe0 (4294967264) of size 0x20 (32)',
Simon Glasse0ff8552016-11-25 20:15:53 -07001183 str(e.exception))
1184
1185 def testPackX86Rom(self):
1186 """Test that a basic x86 ROM can be created"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001187 self._SetupSplElf()
Simon Glass9255f3c2019-08-24 07:23:01 -06001188 data = self._DoReadFile('029_x86_rom.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001189 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 3) + U_BOOT_SPL_DATA +
1190 tools.get_bytes(0, 2), data)
Simon Glasse0ff8552016-11-25 20:15:53 -07001191
1192 def testPackX86RomMeNoDesc(self):
1193 """Test that an invalid Intel descriptor entry is detected"""
Simon Glass0ba4b3d2020-07-09 18:39:41 -06001194 try:
Simon Glass52b10dd2020-07-25 15:11:19 -06001195 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
Simon Glass0ba4b3d2020-07-09 18:39:41 -06001196 with self.assertRaises(ValueError) as e:
Simon Glass52b10dd2020-07-25 15:11:19 -06001197 self._DoTestFile('163_x86_rom_me_empty.dts')
Simon Glass0ba4b3d2020-07-09 18:39:41 -06001198 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1199 str(e.exception))
1200 finally:
1201 self._SetupDescriptor()
Simon Glasse0ff8552016-11-25 20:15:53 -07001202
1203 def testPackX86RomBadDesc(self):
1204 """Test that the Intel requires a descriptor entry"""
1205 with self.assertRaises(ValueError) as e:
Simon Glass9255f3c2019-08-24 07:23:01 -06001206 self._DoTestFile('030_x86_rom_me_no_desc.dts')
Simon Glass3ab95982018-08-01 15:22:37 -06001207 self.assertIn("Node '/binman/intel-me': No offset set with "
1208 "offset-unset: should another entry provide this correct "
1209 "offset?", str(e.exception))
Simon Glasse0ff8552016-11-25 20:15:53 -07001210
1211 def testPackX86RomMe(self):
1212 """Test that an x86 ROM with an ME region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001213 data = self._DoReadFile('031_x86_rom_me.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001214 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glassc5ac1382019-07-08 13:18:54 -06001215 if data[:0x1000] != expected_desc:
1216 self.fail('Expected descriptor binary at start of image')
Simon Glasse0ff8552016-11-25 20:15:53 -07001217 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1218
1219 def testPackVga(self):
1220 """Test that an image with a VGA binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001221 data = self._DoReadFile('032_intel_vga.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -07001222 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1223
1224 def testPackStart16(self):
1225 """Test that an image with an x86 start16 region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001226 data = self._DoReadFile('033_x86_start16.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -07001227 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1228
Jagdish Gediya9d368f32018-09-03 21:35:08 +05301229 def testPackPowerpcMpc85xxBootpgResetvec(self):
1230 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1231 created"""
Simon Glassdfdd2b62019-08-24 07:23:02 -06001232 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
Jagdish Gediya9d368f32018-09-03 21:35:08 +05301233 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1234
Simon Glass736bb0a2018-07-06 10:27:17 -06001235 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glassadc57012018-07-06 10:27:16 -06001236 """Handle running a test for insertion of microcode
1237
1238 Args:
1239 dts_fname: Name of test .dts file
1240 nodtb_data: Data that we expect in the first section
Simon Glass736bb0a2018-07-06 10:27:17 -06001241 ucode_second: True if the microsecond entry is second instead of
1242 third
Simon Glassadc57012018-07-06 10:27:16 -06001243
1244 Returns:
1245 Tuple:
1246 Contents of first region (U-Boot or SPL)
Simon Glass3ab95982018-08-01 15:22:37 -06001247 Offset and size components of microcode pointer, as inserted
Simon Glassadc57012018-07-06 10:27:16 -06001248 in the above (two 4-byte words)
1249 """
Simon Glass6b187df2017-11-12 21:52:27 -07001250 data = self._DoReadFile(dts_fname, True)
Simon Glasse0ff8552016-11-25 20:15:53 -07001251
1252 # Now check the device tree has no microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001253 if ucode_second:
1254 ucode_content = data[len(nodtb_data):]
1255 ucode_pos = len(nodtb_data)
1256 dtb_with_ucode = ucode_content[16:]
1257 fdt_len = self.GetFdtLen(dtb_with_ucode)
1258 else:
1259 dtb_with_ucode = data[len(nodtb_data):]
1260 fdt_len = self.GetFdtLen(dtb_with_ucode)
1261 ucode_content = dtb_with_ucode[fdt_len:]
1262 ucode_pos = len(nodtb_data) + fdt_len
Simon Glassc1aa66e2022-01-29 14:14:04 -07001263 fname = tools.get_output_filename('test.dtb')
Simon Glasse0ff8552016-11-25 20:15:53 -07001264 with open(fname, 'wb') as fd:
Simon Glassadc57012018-07-06 10:27:16 -06001265 fd.write(dtb_with_ucode)
Simon Glassec3f3782017-05-27 07:38:29 -06001266 dtb = fdt.FdtScan(fname)
1267 ucode = dtb.GetNode('/microcode')
Simon Glasse0ff8552016-11-25 20:15:53 -07001268 self.assertTrue(ucode)
1269 for node in ucode.subnodes:
1270 self.assertFalse(node.props.get('data'))
1271
Simon Glasse0ff8552016-11-25 20:15:53 -07001272 # Check that the microcode appears immediately after the Fdt
1273 # This matches the concatenation of the data properties in
Simon Glass87722132017-11-12 21:52:26 -07001274 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glasse0ff8552016-11-25 20:15:53 -07001275 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1276 0x78235609)
Simon Glassadc57012018-07-06 10:27:16 -06001277 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glasse0ff8552016-11-25 20:15:53 -07001278
1279 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -06001280 # expected offset and size
Simon Glasse0ff8552016-11-25 20:15:53 -07001281 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1282 len(ucode_data))
Simon Glass736bb0a2018-07-06 10:27:17 -06001283 u_boot = data[:len(nodtb_data)]
1284 return u_boot, pos_and_size
Simon Glass6b187df2017-11-12 21:52:27 -07001285
1286 def testPackUbootMicrocode(self):
1287 """Test that x86 microcode can be handled correctly
1288
1289 We expect to see the following in the image, in order:
1290 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1291 place
1292 u-boot.dtb with the microcode removed
1293 the microcode
1294 """
Simon Glass741f2d62018-10-01 12:22:30 -06001295 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass6b187df2017-11-12 21:52:27 -07001296 U_BOOT_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001297 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1298 b' somewhere in here', first)
Simon Glasse0ff8552016-11-25 20:15:53 -07001299
Simon Glass160a7662017-05-27 07:38:26 -06001300 def _RunPackUbootSingleMicrocode(self):
Simon Glasse0ff8552016-11-25 20:15:53 -07001301 """Test that x86 microcode can be handled correctly
1302
1303 We expect to see the following in the image, in order:
1304 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1305 place
1306 u-boot.dtb with the microcode
1307 an empty microcode region
1308 """
1309 # We need the libfdt library to run this test since only that allows
1310 # finding the offset of a property. This is required by
1311 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass741f2d62018-10-01 12:22:30 -06001312 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glasse0ff8552016-11-25 20:15:53 -07001313
1314 second = data[len(U_BOOT_NODTB_DATA):]
1315
1316 fdt_len = self.GetFdtLen(second)
1317 third = second[fdt_len:]
1318 second = second[:fdt_len]
1319
Simon Glass160a7662017-05-27 07:38:26 -06001320 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1321 self.assertIn(ucode_data, second)
1322 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -07001323
Simon Glass160a7662017-05-27 07:38:26 -06001324 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -06001325 # expected offset and size
Simon Glass160a7662017-05-27 07:38:26 -06001326 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1327 len(ucode_data))
1328 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glassc6c10e72019-05-17 22:00:46 -06001329 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1330 b' somewhere in here', first)
Simon Glassc49deb82016-11-25 20:15:54 -07001331
Simon Glass75db0862016-11-25 20:15:55 -07001332 def testPackUbootSingleMicrocode(self):
1333 """Test that x86 microcode can be handled correctly with fdt_normal.
1334 """
Simon Glass160a7662017-05-27 07:38:26 -06001335 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001336
Simon Glassc49deb82016-11-25 20:15:54 -07001337 def testUBootImg(self):
1338 """Test that u-boot.img can be put in a file"""
Simon Glass741f2d62018-10-01 12:22:30 -06001339 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glassc49deb82016-11-25 20:15:54 -07001340 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glass75db0862016-11-25 20:15:55 -07001341
1342 def testNoMicrocode(self):
1343 """Test that a missing microcode region is detected"""
1344 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001345 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001346 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1347 "node found in ", str(e.exception))
1348
1349 def testMicrocodeWithoutNode(self):
1350 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1351 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001352 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001353 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1354 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1355
1356 def testMicrocodeWithoutNode2(self):
1357 """Test that a missing u-boot-ucode node is detected"""
1358 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001359 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001360 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1361 "microcode region u-boot-ucode", str(e.exception))
1362
1363 def testMicrocodeWithoutPtrInElf(self):
1364 """Test that a U-Boot binary without the microcode symbol is detected"""
1365 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glass75db0862016-11-25 20:15:55 -07001366 try:
Simon Glassbccd91d2019-08-24 07:22:55 -06001367 TestFunctional._MakeInputFile('u-boot',
Simon Glassc1aa66e2022-01-29 14:14:04 -07001368 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass75db0862016-11-25 20:15:55 -07001369
1370 with self.assertRaises(ValueError) as e:
Simon Glass160a7662017-05-27 07:38:26 -06001371 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001372 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1373 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1374
1375 finally:
1376 # Put the original file back
Simon Glassf514d8f2019-08-24 07:22:54 -06001377 TestFunctional._MakeInputFile('u-boot',
Simon Glassc1aa66e2022-01-29 14:14:04 -07001378 tools.read_file(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glass75db0862016-11-25 20:15:55 -07001379
1380 def testMicrocodeNotInImage(self):
1381 """Test that microcode must be placed within the image"""
1382 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001383 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001384 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1385 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glass25ac0e62018-06-01 09:38:14 -06001386 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glass75db0862016-11-25 20:15:55 -07001387
1388 def testWithoutMicrocode(self):
1389 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glassbccd91d2019-08-24 07:22:55 -06001390 TestFunctional._MakeInputFile('u-boot',
Simon Glassc1aa66e2022-01-29 14:14:04 -07001391 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass741f2d62018-10-01 12:22:30 -06001392 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001393
1394 # Now check the device tree has no microcode
1395 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1396 second = data[len(U_BOOT_NODTB_DATA):]
1397
1398 fdt_len = self.GetFdtLen(second)
1399 self.assertEqual(dtb, second[:fdt_len])
1400
1401 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1402 third = data[used_len:]
Simon Glassc1aa66e2022-01-29 14:14:04 -07001403 self.assertEqual(tools.get_bytes(0, 0x200 - used_len), third)
Simon Glass75db0862016-11-25 20:15:55 -07001404
1405 def testUnknownPosSize(self):
1406 """Test that microcode must be placed within the image"""
1407 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001408 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glass3ab95982018-08-01 15:22:37 -06001409 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glass75db0862016-11-25 20:15:55 -07001410 "entry 'invalid-entry'", str(e.exception))
Simon Glassda229092016-11-25 20:15:56 -07001411
1412 def testPackFsp(self):
1413 """Test that an image with a FSP binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001414 data = self._DoReadFile('042_intel_fsp.dts')
Simon Glassda229092016-11-25 20:15:56 -07001415 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1416
1417 def testPackCmc(self):
Bin Meng59ea8c22017-08-15 22:41:54 -07001418 """Test that an image with a CMC binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001419 data = self._DoReadFile('043_intel_cmc.dts')
Simon Glassda229092016-11-25 20:15:56 -07001420 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Meng59ea8c22017-08-15 22:41:54 -07001421
1422 def testPackVbt(self):
1423 """Test that an image with a VBT binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001424 data = self._DoReadFile('046_intel_vbt.dts')
Bin Meng59ea8c22017-08-15 22:41:54 -07001425 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glass9fc60b42017-11-12 21:52:22 -07001426
Simon Glass56509842017-11-12 21:52:25 -07001427 def testSplBssPad(self):
1428 """Test that we can pad SPL's BSS with zeros"""
Simon Glass6b187df2017-11-12 21:52:27 -07001429 # ELF file with a '__bss_size' symbol
Simon Glass11ae93e2018-10-01 21:12:47 -06001430 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001431 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001432 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glasse6d85ff2019-05-14 15:53:47 -06001433 data)
Simon Glass56509842017-11-12 21:52:25 -07001434
Simon Glass86af5112018-10-01 21:12:42 -06001435 def testSplBssPadMissing(self):
1436 """Test that a missing symbol is detected"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001437 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glassb50e5612017-11-13 18:54:54 -07001438 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001439 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassb50e5612017-11-13 18:54:54 -07001440 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1441 str(e.exception))
1442
Simon Glass87722132017-11-12 21:52:26 -07001443 def testPackStart16Spl(self):
Simon Glass35b384c2018-09-14 04:57:10 -06001444 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001445 data = self._DoReadFile('048_x86_start16_spl.dts')
Simon Glass87722132017-11-12 21:52:26 -07001446 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1447
Simon Glass736bb0a2018-07-06 10:27:17 -06001448 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1449 """Helper function for microcode tests
Simon Glass6b187df2017-11-12 21:52:27 -07001450
1451 We expect to see the following in the image, in order:
1452 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1453 correct place
1454 u-boot.dtb with the microcode removed
1455 the microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001456
1457 Args:
1458 dts: Device tree file to use for test
1459 ucode_second: True if the microsecond entry is second instead of
1460 third
Simon Glass6b187df2017-11-12 21:52:27 -07001461 """
Simon Glass11ae93e2018-10-01 21:12:47 -06001462 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass736bb0a2018-07-06 10:27:17 -06001463 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1464 ucode_second=ucode_second)
Simon Glassc6c10e72019-05-17 22:00:46 -06001465 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1466 b'ter somewhere in here', first)
Simon Glass6b187df2017-11-12 21:52:27 -07001467
Simon Glass736bb0a2018-07-06 10:27:17 -06001468 def testPackUbootSplMicrocode(self):
1469 """Test that x86 microcode can be handled correctly in SPL"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06001470 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001471 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass736bb0a2018-07-06 10:27:17 -06001472
1473 def testPackUbootSplMicrocodeReorder(self):
1474 """Test that order doesn't matter for microcode entries
1475
1476 This is the same as testPackUbootSplMicrocode but when we process the
1477 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1478 entry, so we reply on binman to try later.
1479 """
Simon Glass741f2d62018-10-01 12:22:30 -06001480 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass736bb0a2018-07-06 10:27:17 -06001481 ucode_second=True)
1482
Simon Glassca4f4ff2017-11-12 21:52:28 -07001483 def testPackMrc(self):
1484 """Test that an image with an MRC binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001485 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassca4f4ff2017-11-12 21:52:28 -07001486 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1487
Simon Glass47419ea2017-11-13 18:54:55 -07001488 def testSplDtb(self):
1489 """Test that an image with spl/u-boot-spl.dtb can be created"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06001490 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001491 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass47419ea2017-11-13 18:54:55 -07001492 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1493
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001494 def testSplNoDtb(self):
1495 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass0fe44dc2021-04-25 08:39:32 +12001496 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001497 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001498 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1499
Simon Glass3d433382021-03-21 18:24:30 +13001500 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
Simon Glass4649bea2023-07-18 07:23:54 -06001501 use_expanded=False, no_write_symbols=False):
Simon Glassf5898822021-03-18 20:24:56 +13001502 """Check the image contains the expected symbol values
1503
1504 Args:
1505 dts: Device tree file to use for test
1506 base_data: Data before and after 'u-boot' section
1507 u_boot_offset: Offset of 'u-boot' section in image
Simon Glass3d433382021-03-21 18:24:30 +13001508 entry_args: Dict of entry args to supply to binman
1509 key: arg name
1510 value: value of that arg
1511 use_expanded: True to use expanded entries where available, e.g.
1512 'u-boot-expanded' instead of 'u-boot'
Simon Glassf5898822021-03-18 20:24:56 +13001513 """
Simon Glass1542c8b2019-08-24 07:22:56 -06001514 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass19790632017-11-13 18:55:01 -07001515 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1516 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03001517 self.assertEqual(syms['_binman_sym_magic'].address, addr)
Simon Glassf5898822021-03-18 20:24:56 +13001518 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03001519 addr + 4)
Simon Glass19790632017-11-13 18:55:01 -07001520
Simon Glass11ae93e2018-10-01 21:12:47 -06001521 self._SetupSplElf('u_boot_binman_syms')
Simon Glass3d433382021-03-21 18:24:30 +13001522 data = self._DoReadFileDtb(dts, entry_args=entry_args,
1523 use_expanded=use_expanded)[0]
Simon Glassf5898822021-03-18 20:24:56 +13001524 # The image should contain the symbols from u_boot_binman_syms.c
1525 # Note that image_pos is adjusted by the base address of the image,
1526 # which is 0x10 in our test image
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03001527 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE,
1528 0x00, u_boot_offset + len(U_BOOT_DATA),
Simon Glassf5898822021-03-18 20:24:56 +13001529 0x10 + u_boot_offset, 0x04)
Simon Glass4649bea2023-07-18 07:23:54 -06001530 if no_write_symbols:
1531 expected = (base_data +
1532 tools.get_bytes(0xff, 0x38 - len(base_data)) +
1533 U_BOOT_DATA + base_data)
1534 else:
1535 expected = (sym_values + base_data[24:] +
1536 tools.get_bytes(0xff, 1) + U_BOOT_DATA + sym_values +
1537 base_data[24:])
Simon Glass19790632017-11-13 18:55:01 -07001538 self.assertEqual(expected, data)
1539
Simon Glassf5898822021-03-18 20:24:56 +13001540 def testSymbols(self):
1541 """Test binman can assign symbols embedded in U-Boot"""
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03001542 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glassf5898822021-03-18 20:24:56 +13001543
1544 def testSymbolsNoDtb(self):
1545 """Test binman can assign symbols embedded in U-Boot SPL"""
Simon Glasse9e0db82021-03-21 18:24:29 +13001546 self.checkSymbols('196_symbols_nodtb.dts',
Simon Glassf5898822021-03-18 20:24:56 +13001547 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1548 0x38)
1549
Simon Glassdd57c132018-06-01 09:38:11 -06001550 def testPackUnitAddress(self):
1551 """Test that we support multiple binaries with the same name"""
Simon Glass741f2d62018-10-01 12:22:30 -06001552 data = self._DoReadFile('054_unit_address.dts')
Simon Glassdd57c132018-06-01 09:38:11 -06001553 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1554
Simon Glass18546952018-06-01 09:38:16 -06001555 def testSections(self):
1556 """Basic test of sections"""
Simon Glass741f2d62018-10-01 12:22:30 -06001557 data = self._DoReadFile('055_sections.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001558 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1559 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
1560 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glass18546952018-06-01 09:38:16 -06001561 self.assertEqual(expected, data)
Simon Glass9fc60b42017-11-12 21:52:22 -07001562
Simon Glass3b0c3822018-06-01 09:38:20 -06001563 def testMap(self):
1564 """Tests outputting a map of the images"""
Simon Glass741f2d62018-10-01 12:22:30 -06001565 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001566 self.assertEqual('''ImagePos Offset Size Name
Simon Glass193d3db2023-02-07 14:34:18 -0700156700000000 00000000 00000028 image
Simon Glass1be70d22018-07-17 13:25:49 -0600156800000000 00000000 00000010 section@0
156900000000 00000000 00000004 u-boot
157000000010 00000010 00000010 section@1
157100000010 00000000 00000004 u-boot
157200000020 00000020 00000004 section@2
157300000020 00000000 00000004 u-boot
Simon Glass3b0c3822018-06-01 09:38:20 -06001574''', map_data)
1575
Simon Glassc8d48ef2018-06-01 09:38:21 -06001576 def testNamePrefix(self):
1577 """Tests that name prefixes are used"""
Simon Glass741f2d62018-10-01 12:22:30 -06001578 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001579 self.assertEqual('''ImagePos Offset Size Name
Simon Glass193d3db2023-02-07 14:34:18 -0700158000000000 00000000 00000028 image
Simon Glass1be70d22018-07-17 13:25:49 -0600158100000000 00000000 00000010 section@0
158200000000 00000000 00000004 ro-u-boot
158300000010 00000010 00000010 section@1
158400000010 00000000 00000004 rw-u-boot
Simon Glassc8d48ef2018-06-01 09:38:21 -06001585''', map_data)
1586
Simon Glass736bb0a2018-07-06 10:27:17 -06001587 def testUnknownContents(self):
1588 """Test that obtaining the contents works as expected"""
1589 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001590 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass8beb11e2019-07-08 14:25:47 -06001591 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glass16287932020-04-17 18:09:03 -06001592 "processing of contents: remaining ["
1593 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass736bb0a2018-07-06 10:27:17 -06001594
Simon Glass5c890232018-07-06 10:27:19 -06001595 def testBadChangeSize(self):
1596 """Test that trying to change the size of an entry fails"""
Simon Glassc52c9e72019-07-08 14:25:37 -06001597 try:
1598 state.SetAllowEntryExpansion(False)
1599 with self.assertRaises(ValueError) as e:
1600 self._DoReadFile('059_change_size.dts', True)
Simon Glass79d3c582019-07-20 12:23:57 -06001601 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glassc52c9e72019-07-08 14:25:37 -06001602 str(e.exception))
1603 finally:
1604 state.SetAllowEntryExpansion(True)
Simon Glass5c890232018-07-06 10:27:19 -06001605
Simon Glass16b8d6b2018-07-06 10:27:42 -06001606 def testUpdateFdt(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001607 """Test that we can update the device tree with offset/size info"""
Simon Glass741f2d62018-10-01 12:22:30 -06001608 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glass16b8d6b2018-07-06 10:27:42 -06001609 update_dtb=True)
Simon Glasscee02e62018-07-17 13:25:52 -06001610 dtb = fdt.Fdt(out_dtb_fname)
1611 dtb.Scan()
Simon Glass12bb1a92019-07-20 12:23:51 -06001612 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001613 self.assertEqual({
Simon Glassdbf6be92018-08-01 15:22:42 -06001614 'image-pos': 0,
Simon Glass8122f392018-07-17 13:25:28 -06001615 'offset': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001616 '_testing:offset': 32,
Simon Glass79d3c582019-07-20 12:23:57 -06001617 '_testing:size': 2,
Simon Glassdbf6be92018-08-01 15:22:42 -06001618 '_testing:image-pos': 32,
Simon Glass3ab95982018-08-01 15:22:37 -06001619 'section@0/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001620 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001621 'section@0/u-boot:image-pos': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001622 'section@0:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001623 'section@0:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001624 'section@0:image-pos': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001625
Simon Glass3ab95982018-08-01 15:22:37 -06001626 'section@1/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001627 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001628 'section@1/u-boot:image-pos': 16,
Simon Glass3ab95982018-08-01 15:22:37 -06001629 'section@1:offset': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001630 'section@1:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001631 'section@1:image-pos': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001632 'size': 40
1633 }, props)
1634
1635 def testUpdateFdtBad(self):
1636 """Test that we detect when ProcessFdt never completes"""
1637 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001638 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001639 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glass16287932020-04-17 18:09:03 -06001640 '[<binman.etype._testing.Entry__testing',
1641 str(e.exception))
Simon Glass5c890232018-07-06 10:27:19 -06001642
Simon Glass53af22a2018-07-17 13:25:32 -06001643 def testEntryArgs(self):
1644 """Test passing arguments to entries from the command line"""
1645 entry_args = {
1646 'test-str-arg': 'test1',
1647 'test-int-arg': '456',
1648 }
Simon Glass741f2d62018-10-01 12:22:30 -06001649 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001650 self.assertIn('image', control.images)
1651 entry = control.images['image'].GetEntries()['_testing']
1652 self.assertEqual('test0', entry.test_str_fdt)
1653 self.assertEqual('test1', entry.test_str_arg)
1654 self.assertEqual(123, entry.test_int_fdt)
1655 self.assertEqual(456, entry.test_int_arg)
1656
1657 def testEntryArgsMissing(self):
1658 """Test missing arguments and properties"""
1659 entry_args = {
1660 'test-int-arg': '456',
1661 }
Simon Glass741f2d62018-10-01 12:22:30 -06001662 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001663 entry = control.images['image'].GetEntries()['_testing']
1664 self.assertEqual('test0', entry.test_str_fdt)
1665 self.assertEqual(None, entry.test_str_arg)
1666 self.assertEqual(None, entry.test_int_fdt)
1667 self.assertEqual(456, entry.test_int_arg)
1668
1669 def testEntryArgsRequired(self):
1670 """Test missing arguments and properties"""
1671 entry_args = {
1672 'test-int-arg': '456',
1673 }
1674 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001675 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass3decfa32020-09-01 05:13:54 -06001676 self.assertIn("Node '/binman/_testing': "
1677 'Missing required properties/entry args: test-str-arg, '
1678 'test-int-fdt, test-int-arg',
Simon Glass53af22a2018-07-17 13:25:32 -06001679 str(e.exception))
1680
1681 def testEntryArgsInvalidFormat(self):
1682 """Test that an invalid entry-argument format is detected"""
Simon Glass53cd5d92019-07-08 14:25:29 -06001683 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1684 '-ano-value']
Simon Glass53af22a2018-07-17 13:25:32 -06001685 with self.assertRaises(ValueError) as e:
1686 self._DoBinman(*args)
1687 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1688
1689 def testEntryArgsInvalidInteger(self):
1690 """Test that an invalid entry-argument integer is detected"""
1691 entry_args = {
1692 'test-int-arg': 'abc',
1693 }
1694 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001695 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001696 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1697 "'test-int-arg' (value 'abc') to integer",
1698 str(e.exception))
1699
1700 def testEntryArgsInvalidDatatype(self):
1701 """Test that an invalid entry-argument datatype is detected
1702
1703 This test could be written in entry_test.py except that it needs
1704 access to control.entry_args, which seems more than that module should
1705 be able to see.
1706 """
1707 entry_args = {
1708 'test-bad-datatype-arg': '12',
1709 }
1710 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001711 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass53af22a2018-07-17 13:25:32 -06001712 entry_args=entry_args)
1713 self.assertIn('GetArg() internal error: Unknown data type ',
1714 str(e.exception))
1715
Simon Glassbb748372018-07-17 13:25:33 -06001716 def testText(self):
1717 """Test for a text entry type"""
1718 entry_args = {
1719 'test-id': TEXT_DATA,
1720 'test-id2': TEXT_DATA2,
1721 'test-id3': TEXT_DATA3,
1722 }
Simon Glass741f2d62018-10-01 12:22:30 -06001723 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glassbb748372018-07-17 13:25:33 -06001724 entry_args=entry_args)
Simon Glassc1aa66e2022-01-29 14:14:04 -07001725 expected = (tools.to_bytes(TEXT_DATA) +
1726 tools.get_bytes(0, 8 - len(TEXT_DATA)) +
1727 tools.to_bytes(TEXT_DATA2) + tools.to_bytes(TEXT_DATA3) +
Simon Glassaa88b502019-07-08 13:18:40 -06001728 b'some text' + b'more text')
Simon Glassbb748372018-07-17 13:25:33 -06001729 self.assertEqual(expected, data)
1730
Simon Glassfd8d1f72018-07-17 13:25:36 -06001731 def testEntryDocs(self):
1732 """Test for creation of entry documentation"""
1733 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass87d43322020-08-05 13:27:46 -06001734 control.WriteEntryDocs(control.GetEntryModules())
Simon Glassfd8d1f72018-07-17 13:25:36 -06001735 self.assertTrue(len(stdout.getvalue()) > 0)
1736
1737 def testEntryDocsMissing(self):
1738 """Test handling of missing entry documentation"""
1739 with self.assertRaises(ValueError) as e:
1740 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass87d43322020-08-05 13:27:46 -06001741 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glassfd8d1f72018-07-17 13:25:36 -06001742 self.assertIn('Documentation is missing for modules: u_boot',
1743 str(e.exception))
1744
Simon Glass11e36cc2018-07-17 13:25:38 -06001745 def testFmap(self):
1746 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001747 data = self._DoReadFile('067_fmap.dts')
Simon Glass11e36cc2018-07-17 13:25:38 -06001748 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc1aa66e2022-01-29 14:14:04 -07001749 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1750 U_BOOT_DATA + tools.get_bytes(ord('a'), 12))
Simon Glass11e36cc2018-07-17 13:25:38 -06001751 self.assertEqual(expected, data[:32])
Simon Glassc6c10e72019-05-17 22:00:46 -06001752 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass11e36cc2018-07-17 13:25:38 -06001753 self.assertEqual(1, fhdr.ver_major)
1754 self.assertEqual(0, fhdr.ver_minor)
1755 self.assertEqual(0, fhdr.base)
Simon Glass17365752021-04-03 11:05:10 +13001756 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 5
Simon Glassc7722e82021-04-03 11:05:09 +13001757 self.assertEqual(16 + 16 + expect_size, fhdr.image_size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001758 self.assertEqual(b'FMAP', fhdr.name)
Simon Glass17365752021-04-03 11:05:10 +13001759 self.assertEqual(5, fhdr.nareas)
Simon Glassc7722e82021-04-03 11:05:09 +13001760 fiter = iter(fentries)
Simon Glass11e36cc2018-07-17 13:25:38 -06001761
Simon Glassc7722e82021-04-03 11:05:09 +13001762 fentry = next(fiter)
Simon Glass17365752021-04-03 11:05:10 +13001763 self.assertEqual(b'SECTION0', fentry.name)
1764 self.assertEqual(0, fentry.offset)
1765 self.assertEqual(16, fentry.size)
Simon Glass9dbb02b2023-02-12 17:11:15 -07001766 self.assertEqual(fmap_util.FMAP_AREA_PRESERVE, fentry.flags)
Simon Glass17365752021-04-03 11:05:10 +13001767
1768 fentry = next(fiter)
Simon Glassc7722e82021-04-03 11:05:09 +13001769 self.assertEqual(b'RO_U_BOOT', fentry.name)
1770 self.assertEqual(0, fentry.offset)
1771 self.assertEqual(4, fentry.size)
1772 self.assertEqual(0, fentry.flags)
Simon Glass11e36cc2018-07-17 13:25:38 -06001773
Simon Glassc7722e82021-04-03 11:05:09 +13001774 fentry = next(fiter)
Simon Glass17365752021-04-03 11:05:10 +13001775 self.assertEqual(b'SECTION1', fentry.name)
1776 self.assertEqual(16, fentry.offset)
1777 self.assertEqual(16, fentry.size)
1778 self.assertEqual(0, fentry.flags)
1779
1780 fentry = next(fiter)
Simon Glassc7722e82021-04-03 11:05:09 +13001781 self.assertEqual(b'RW_U_BOOT', fentry.name)
1782 self.assertEqual(16, fentry.offset)
1783 self.assertEqual(4, fentry.size)
1784 self.assertEqual(0, fentry.flags)
Simon Glass11e36cc2018-07-17 13:25:38 -06001785
Simon Glassc7722e82021-04-03 11:05:09 +13001786 fentry = next(fiter)
1787 self.assertEqual(b'FMAP', fentry.name)
1788 self.assertEqual(32, fentry.offset)
1789 self.assertEqual(expect_size, fentry.size)
1790 self.assertEqual(0, fentry.flags)
Simon Glass11e36cc2018-07-17 13:25:38 -06001791
Simon Glassec127af2018-07-17 13:25:39 -06001792 def testBlobNamedByArg(self):
1793 """Test we can add a blob with the filename coming from an entry arg"""
1794 entry_args = {
1795 'cros-ec-rw-path': 'ecrw.bin',
1796 }
Simon Glass3decfa32020-09-01 05:13:54 -06001797 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassec127af2018-07-17 13:25:39 -06001798
Simon Glass3af8e492018-07-17 13:25:40 -06001799 def testFill(self):
1800 """Test for an fill entry type"""
Simon Glass741f2d62018-10-01 12:22:30 -06001801 data = self._DoReadFile('069_fill.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001802 expected = tools.get_bytes(0xff, 8) + tools.get_bytes(0, 8)
Simon Glass3af8e492018-07-17 13:25:40 -06001803 self.assertEqual(expected, data)
1804
1805 def testFillNoSize(self):
1806 """Test for an fill entry type with no size"""
1807 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001808 self._DoReadFile('070_fill_no_size.dts')
Simon Glasscdadada2022-08-13 11:40:44 -06001809 self.assertIn("'fill' entry is missing properties: size",
Simon Glass3af8e492018-07-17 13:25:40 -06001810 str(e.exception))
1811
Simon Glass0ef87aa2018-07-17 13:25:44 -06001812 def _HandleGbbCommand(self, pipe_list):
1813 """Fake calls to the futility utility"""
Simon Glassfe7e9242023-02-22 12:14:49 -07001814 if 'futility' in pipe_list[0][0]:
Simon Glass0ef87aa2018-07-17 13:25:44 -06001815 fname = pipe_list[0][-1]
1816 # Append our GBB data to the file, which will happen every time the
1817 # futility command is called.
Simon Glass1d0ebf72019-05-14 15:53:42 -06001818 with open(fname, 'ab') as fd:
Simon Glass0ef87aa2018-07-17 13:25:44 -06001819 fd.write(GBB_DATA)
1820 return command.CommandResult()
1821
1822 def testGbb(self):
1823 """Test for the Chromium OS Google Binary Block"""
1824 command.test_result = self._HandleGbbCommand
1825 entry_args = {
1826 'keydir': 'devkeys',
1827 'bmpblk': 'bmpblk.bin',
1828 }
Simon Glass741f2d62018-10-01 12:22:30 -06001829 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glass0ef87aa2018-07-17 13:25:44 -06001830
1831 # Since futility
Simon Glassc1aa66e2022-01-29 14:14:04 -07001832 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
1833 tools.get_bytes(0, 0x2180 - 16))
Simon Glass0ef87aa2018-07-17 13:25:44 -06001834 self.assertEqual(expected, data)
1835
1836 def testGbbTooSmall(self):
1837 """Test for the Chromium OS Google Binary Block being large enough"""
1838 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001839 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001840 self.assertIn("Node '/binman/gbb': GBB is too small",
1841 str(e.exception))
1842
1843 def testGbbNoSize(self):
1844 """Test for the Chromium OS Google Binary Block having a size"""
1845 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001846 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001847 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1848 str(e.exception))
1849
Simon Glass4f9ee832022-01-09 20:14:09 -07001850 def testGbbMissing(self):
1851 """Test that binman still produces an image if futility is missing"""
1852 entry_args = {
1853 'keydir': 'devkeys',
1854 }
1855 with test_util.capture_sys_output() as (_, stderr):
1856 self._DoTestFile('071_gbb.dts', force_missing_bintools='futility',
1857 entry_args=entry_args)
1858 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07001859 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass4f9ee832022-01-09 20:14:09 -07001860
Simon Glass24d0d3c2018-07-17 13:25:47 -06001861 def _HandleVblockCommand(self, pipe_list):
Simon Glass5af9ebc2021-01-06 21:35:17 -07001862 """Fake calls to the futility utility
1863
1864 The expected pipe is:
1865
1866 [('futility', 'vbutil_firmware', '--vblock',
1867 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1868 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1869 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1870 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1871
1872 This writes to the output file (here, 'vblock.vblock'). If
1873 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1874 of the input data (here, 'input.vblock').
1875 """
Simon Glassfe7e9242023-02-22 12:14:49 -07001876 if 'futility' in pipe_list[0][0]:
Simon Glass24d0d3c2018-07-17 13:25:47 -06001877 fname = pipe_list[0][3]
Simon Glassa326b492018-09-14 04:57:11 -06001878 with open(fname, 'wb') as fd:
Simon Glass5af9ebc2021-01-06 21:35:17 -07001879 if self._hash_data:
1880 infile = pipe_list[0][11]
1881 m = hashlib.sha256()
Simon Glassc1aa66e2022-01-29 14:14:04 -07001882 data = tools.read_file(infile)
Simon Glass5af9ebc2021-01-06 21:35:17 -07001883 m.update(data)
1884 fd.write(m.digest())
1885 else:
1886 fd.write(VBLOCK_DATA)
1887
Simon Glass24d0d3c2018-07-17 13:25:47 -06001888 return command.CommandResult()
1889
1890 def testVblock(self):
1891 """Test for the Chromium OS Verified Boot Block"""
Simon Glass5af9ebc2021-01-06 21:35:17 -07001892 self._hash_data = False
Simon Glass24d0d3c2018-07-17 13:25:47 -06001893 command.test_result = self._HandleVblockCommand
1894 entry_args = {
1895 'keydir': 'devkeys',
1896 }
Simon Glass741f2d62018-10-01 12:22:30 -06001897 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass24d0d3c2018-07-17 13:25:47 -06001898 entry_args=entry_args)
1899 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1900 self.assertEqual(expected, data)
1901
1902 def testVblockNoContent(self):
1903 """Test we detect a vblock which has no content to sign"""
1904 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001905 self._DoReadFile('075_vblock_no_content.dts')
Simon Glass189f2912021-03-21 18:24:31 +13001906 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
Simon Glass24d0d3c2018-07-17 13:25:47 -06001907 'property', str(e.exception))
1908
1909 def testVblockBadPhandle(self):
1910 """Test that we detect a vblock with an invalid phandle in contents"""
1911 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001912 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001913 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1914 '1000', str(e.exception))
1915
1916 def testVblockBadEntry(self):
1917 """Test that we detect an entry that points to a non-entry"""
1918 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001919 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001920 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1921 "'other'", str(e.exception))
1922
Simon Glass5af9ebc2021-01-06 21:35:17 -07001923 def testVblockContent(self):
1924 """Test that the vblock signs the right data"""
1925 self._hash_data = True
1926 command.test_result = self._HandleVblockCommand
1927 entry_args = {
1928 'keydir': 'devkeys',
1929 }
1930 data = self._DoReadFileDtb(
1931 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1932 entry_args=entry_args)[0]
1933 hashlen = 32 # SHA256 hash is 32 bytes
1934 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1935 hashval = data[-hashlen:]
1936 dtb = data[len(U_BOOT_DATA):-hashlen]
1937
1938 expected_data = U_BOOT_DATA + dtb
1939
1940 # The hashval should be a hash of the dtb
1941 m = hashlib.sha256()
1942 m.update(expected_data)
1943 expected_hashval = m.digest()
1944 self.assertEqual(expected_hashval, hashval)
1945
Simon Glass4f9ee832022-01-09 20:14:09 -07001946 def testVblockMissing(self):
1947 """Test that binman still produces an image if futility is missing"""
1948 entry_args = {
1949 'keydir': 'devkeys',
1950 }
1951 with test_util.capture_sys_output() as (_, stderr):
1952 self._DoTestFile('074_vblock.dts',
1953 force_missing_bintools='futility',
1954 entry_args=entry_args)
1955 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07001956 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass4f9ee832022-01-09 20:14:09 -07001957
Simon Glassb8ef5b62018-07-17 13:25:48 -06001958 def testTpl(self):
Simon Glass2090f1e2019-08-24 07:23:00 -06001959 """Test that an image with TPL and its device tree can be created"""
Simon Glassb8ef5b62018-07-17 13:25:48 -06001960 # ELF file with a '__bss_size' symbol
Simon Glass2090f1e2019-08-24 07:23:00 -06001961 self._SetupTplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001962 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glassb8ef5b62018-07-17 13:25:48 -06001963 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1964
Simon Glass15a587c2018-07-17 13:25:51 -06001965 def testUsesPos(self):
1966 """Test that the 'pos' property cannot be used anymore"""
1967 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001968 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass15a587c2018-07-17 13:25:51 -06001969 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1970 "'pos'", str(e.exception))
1971
Simon Glassd178eab2018-09-14 04:57:08 -06001972 def testFillZero(self):
1973 """Test for an fill entry type with a size of 0"""
Simon Glass741f2d62018-10-01 12:22:30 -06001974 data = self._DoReadFile('080_fill_empty.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001975 self.assertEqual(tools.get_bytes(0, 16), data)
Simon Glassd178eab2018-09-14 04:57:08 -06001976
Simon Glass0b489362018-09-14 04:57:09 -06001977 def testTextMissing(self):
1978 """Test for a text entry type where there is no text"""
1979 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001980 self._DoReadFileDtb('066_text.dts',)
Simon Glass0b489362018-09-14 04:57:09 -06001981 self.assertIn("Node '/binman/text': No value provided for text label "
1982 "'test-id'", str(e.exception))
1983
Simon Glass35b384c2018-09-14 04:57:10 -06001984 def testPackStart16Tpl(self):
1985 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001986 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glass35b384c2018-09-14 04:57:10 -06001987 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1988
Simon Glass0bfa7b02018-09-14 04:57:12 -06001989 def testSelectImage(self):
1990 """Test that we can select which images to build"""
Simon Glasseb833d82019-04-25 21:58:34 -06001991 expected = 'Skipping images: image1'
Simon Glass0bfa7b02018-09-14 04:57:12 -06001992
Simon Glasseb833d82019-04-25 21:58:34 -06001993 # We should only get the expected message in verbose mode
Simon Glassee0c9a72019-07-08 13:18:48 -06001994 for verbosity in (0, 2):
Simon Glasseb833d82019-04-25 21:58:34 -06001995 with test_util.capture_sys_output() as (stdout, stderr):
1996 retcode = self._DoTestFile('006_dual_image.dts',
1997 verbosity=verbosity,
1998 images=['image2'])
1999 self.assertEqual(0, retcode)
2000 if verbosity:
2001 self.assertIn(expected, stdout.getvalue())
2002 else:
2003 self.assertNotIn(expected, stdout.getvalue())
2004
Simon Glassc1aa66e2022-01-29 14:14:04 -07002005 self.assertFalse(os.path.exists(tools.get_output_filename('image1.bin')))
2006 self.assertTrue(os.path.exists(tools.get_output_filename('image2.bin')))
Simon Glassf86a7362019-07-20 12:24:10 -06002007 self._CleanupOutputDir()
Simon Glass0bfa7b02018-09-14 04:57:12 -06002008
Simon Glass6ed45ba2018-09-14 04:57:24 -06002009 def testUpdateFdtAll(self):
2010 """Test that all device trees are updated with offset/size info"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06002011 self._SetupSplElf()
2012 self._SetupTplElf()
Simon Glass3c081312019-07-08 14:25:26 -06002013 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glass6ed45ba2018-09-14 04:57:24 -06002014
2015 base_expected = {
Simon Glass6ed45ba2018-09-14 04:57:24 -06002016 'offset': 0,
Simon Glass6ad24522022-02-28 07:16:54 -07002017 'image-pos': 0,
2018 'size': 2320,
Simon Glass6ed45ba2018-09-14 04:57:24 -06002019 'section:offset': 0,
Simon Glass6ad24522022-02-28 07:16:54 -07002020 'section:image-pos': 0,
2021 'section:size': 565,
2022 'section/u-boot-dtb:offset': 0,
2023 'section/u-boot-dtb:image-pos': 0,
2024 'section/u-boot-dtb:size': 565,
2025 'u-boot-spl-dtb:offset': 565,
2026 'u-boot-spl-dtb:image-pos': 565,
2027 'u-boot-spl-dtb:size': 585,
2028 'u-boot-tpl-dtb:offset': 1150,
2029 'u-boot-tpl-dtb:image-pos': 1150,
2030 'u-boot-tpl-dtb:size': 585,
2031 'u-boot-vpl-dtb:image-pos': 1735,
2032 'u-boot-vpl-dtb:offset': 1735,
2033 'u-boot-vpl-dtb:size': 585,
Simon Glass6ed45ba2018-09-14 04:57:24 -06002034 }
2035
2036 # We expect three device-tree files in the output, one after the other.
2037 # Read them in sequence. We look for an 'spl' property in the SPL tree,
2038 # and 'tpl' in the TPL tree, to make sure they are distinct from the
2039 # main U-Boot tree. All three should have the same postions and offset.
2040 start = 0
Simon Glass6ad24522022-02-28 07:16:54 -07002041 self.maxDiff = None
2042 for item in ['', 'spl', 'tpl', 'vpl']:
Simon Glass6ed45ba2018-09-14 04:57:24 -06002043 dtb = fdt.Fdt.FromData(data[start:])
2044 dtb.Scan()
Simon Glass12bb1a92019-07-20 12:23:51 -06002045 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
Simon Glass6ad24522022-02-28 07:16:54 -07002046 ['spl', 'tpl', 'vpl'])
Simon Glass6ed45ba2018-09-14 04:57:24 -06002047 expected = dict(base_expected)
2048 if item:
2049 expected[item] = 0
2050 self.assertEqual(expected, props)
2051 start += dtb._fdt_obj.totalsize()
2052
2053 def testUpdateFdtOutput(self):
2054 """Test that output DTB files are updated"""
2055 try:
Simon Glass741f2d62018-10-01 12:22:30 -06002056 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glass6ed45ba2018-09-14 04:57:24 -06002057 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
2058
2059 # Unfortunately, compiling a source file always results in a file
2060 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass741f2d62018-10-01 12:22:30 -06002061 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glass6ed45ba2018-09-14 04:57:24 -06002062 # binman as a file called u-boot.dtb. To fix this, copy the file
2063 # over to the expected place.
Simon Glass6ed45ba2018-09-14 04:57:24 -06002064 start = 0
2065 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
Simon Glass6ad24522022-02-28 07:16:54 -07002066 'tpl/u-boot-tpl.dtb.out', 'vpl/u-boot-vpl.dtb.out']:
Simon Glass6ed45ba2018-09-14 04:57:24 -06002067 dtb = fdt.Fdt.FromData(data[start:])
2068 size = dtb._fdt_obj.totalsize()
Simon Glassc1aa66e2022-01-29 14:14:04 -07002069 pathname = tools.get_output_filename(os.path.split(fname)[1])
2070 outdata = tools.read_file(pathname)
Simon Glass6ed45ba2018-09-14 04:57:24 -06002071 name = os.path.split(fname)[0]
2072
2073 if name:
Simon Glass6ad24522022-02-28 07:16:54 -07002074 orig_indata = self._GetDtbContentsForSpls(dtb_data, name)
Simon Glass6ed45ba2018-09-14 04:57:24 -06002075 else:
2076 orig_indata = dtb_data
2077 self.assertNotEqual(outdata, orig_indata,
2078 "Expected output file '%s' be updated" % pathname)
2079 self.assertEqual(outdata, data[start:start + size],
2080 "Expected output file '%s' to match output image" %
2081 pathname)
2082 start += size
2083 finally:
2084 self._ResetDtbs()
2085
Simon Glass83d73c22018-09-14 04:57:26 -06002086 def _decompress(self, data):
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +02002087 bintool = self.comp_bintools['lz4']
2088 return bintool.decompress(data)
Simon Glass83d73c22018-09-14 04:57:26 -06002089
2090 def testCompress(self):
2091 """Test compression of blobs"""
Simon Glassac62fba2019-07-08 13:18:53 -06002092 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06002093 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass83d73c22018-09-14 04:57:26 -06002094 use_real_dtb=True, update_dtb=True)
2095 dtb = fdt.Fdt(out_dtb_fname)
2096 dtb.Scan()
2097 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2098 orig = self._decompress(data)
Brandon Maier357bfca2024-06-04 16:16:05 +00002099 self.assertEqual(COMPRESS_DATA, orig)
Simon Glass97c3e9a2020-10-26 17:40:15 -06002100
2101 # Do a sanity check on various fields
2102 image = control.images['image']
2103 entries = image.GetEntries()
2104 self.assertEqual(1, len(entries))
2105
2106 entry = entries['blob']
2107 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
2108 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
2109 orig = self._decompress(entry.data)
2110 self.assertEqual(orig, entry.uncomp_data)
2111
Simon Glass63e7ba62020-10-26 17:40:16 -06002112 self.assertEqual(image.data, entry.data)
2113
Simon Glass83d73c22018-09-14 04:57:26 -06002114 expected = {
2115 'blob:uncomp-size': len(COMPRESS_DATA),
2116 'blob:size': len(data),
2117 'size': len(data),
2118 }
2119 self.assertEqual(expected, props)
2120
Simon Glass0a98b282018-09-14 04:57:28 -06002121 def testFiles(self):
2122 """Test bringing in multiple files"""
Simon Glass741f2d62018-10-01 12:22:30 -06002123 data = self._DoReadFile('084_files.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06002124 self.assertEqual(FILES_DATA, data)
2125
2126 def testFilesCompress(self):
2127 """Test bringing in multiple files and compressing them"""
Simon Glassac62fba2019-07-08 13:18:53 -06002128 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06002129 data = self._DoReadFile('085_files_compress.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06002130
2131 image = control.images['image']
2132 entries = image.GetEntries()
2133 files = entries['files']
Simon Glass8beb11e2019-07-08 14:25:47 -06002134 entries = files._entries
Simon Glass0a98b282018-09-14 04:57:28 -06002135
Simon Glassc6c10e72019-05-17 22:00:46 -06002136 orig = b''
Simon Glass0a98b282018-09-14 04:57:28 -06002137 for i in range(1, 3):
2138 key = '%d.dat' % i
2139 start = entries[key].image_pos
2140 len = entries[key].size
2141 chunk = data[start:start + len]
2142 orig += self._decompress(chunk)
2143
2144 self.assertEqual(FILES_DATA, orig)
2145
2146 def testFilesMissing(self):
2147 """Test missing files"""
2148 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002149 data = self._DoReadFile('086_files_none.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06002150 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
2151 'no files', str(e.exception))
2152
2153 def testFilesNoPattern(self):
2154 """Test missing files"""
2155 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002156 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06002157 self.assertIn("Node '/binman/files': Missing 'pattern' property",
2158 str(e.exception))
2159
Simon Glass80a66ae2022-03-05 20:18:59 -07002160 def testExtendSize(self):
2161 """Test an extending entry"""
2162 data, _, map_data, _ = self._DoReadFileDtb('088_extend_size.dts',
Simon Glassba64a0b2018-09-14 04:57:29 -06002163 map=True)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002164 expect = (tools.get_bytes(ord('a'), 8) + U_BOOT_DATA +
2165 MRC_DATA + tools.get_bytes(ord('b'), 1) + U_BOOT_DATA +
2166 tools.get_bytes(ord('c'), 8) + U_BOOT_DATA +
2167 tools.get_bytes(ord('d'), 8))
Simon Glassba64a0b2018-09-14 04:57:29 -06002168 self.assertEqual(expect, data)
2169 self.assertEqual('''ImagePos Offset Size Name
Simon Glass193d3db2023-02-07 14:34:18 -0700217000000000 00000000 00000028 image
Simon Glassba64a0b2018-09-14 04:57:29 -0600217100000000 00000000 00000008 fill
217200000008 00000008 00000004 u-boot
21730000000c 0000000c 00000004 section
21740000000c 00000000 00000003 intel-mrc
217500000010 00000010 00000004 u-boot2
217600000014 00000014 0000000c section2
217700000014 00000000 00000008 fill
21780000001c 00000008 00000004 u-boot
217900000020 00000020 00000008 fill2
2180''', map_data)
2181
Simon Glass80a66ae2022-03-05 20:18:59 -07002182 def testExtendSizeBad(self):
2183 """Test an extending entry which fails to provide contents"""
Simon Glass163ed6c2018-09-14 04:57:36 -06002184 with test_util.capture_sys_output() as (stdout, stderr):
2185 with self.assertRaises(ValueError) as e:
Simon Glass80a66ae2022-03-05 20:18:59 -07002186 self._DoReadFileDtb('089_extend_size_bad.dts', map=True)
Simon Glassba64a0b2018-09-14 04:57:29 -06002187 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
2188 'expanding entry', str(e.exception))
2189
Simon Glasse0e5df92018-09-14 04:57:31 -06002190 def testHash(self):
2191 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06002192 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06002193 use_real_dtb=True, update_dtb=True)
2194 dtb = fdt.Fdt(out_dtb_fname)
2195 dtb.Scan()
2196 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
2197 m = hashlib.sha256()
2198 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06002199 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06002200
2201 def testHashNoAlgo(self):
2202 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002203 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06002204 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2205 'hash node', str(e.exception))
2206
2207 def testHashBadAlgo(self):
2208 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002209 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glass8db1f992022-02-08 10:59:44 -07002210 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm 'invalid'",
Simon Glasse0e5df92018-09-14 04:57:31 -06002211 str(e.exception))
2212
2213 def testHashSection(self):
2214 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06002215 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06002216 use_real_dtb=True, update_dtb=True)
2217 dtb = fdt.Fdt(out_dtb_fname)
2218 dtb.Scan()
2219 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2220 m = hashlib.sha256()
2221 m.update(U_BOOT_DATA)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002222 m.update(tools.get_bytes(ord('a'), 16))
Simon Glassc6c10e72019-05-17 22:00:46 -06002223 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06002224
Simon Glassf0253632018-09-14 04:57:32 -06002225 def testPackUBootTplMicrocode(self):
2226 """Test that x86 microcode can be handled correctly in TPL
2227
2228 We expect to see the following in the image, in order:
2229 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2230 place
2231 u-boot-tpl.dtb with the microcode removed
2232 the microcode
2233 """
Simon Glass2090f1e2019-08-24 07:23:00 -06002234 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass741f2d62018-10-01 12:22:30 -06002235 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glassf0253632018-09-14 04:57:32 -06002236 U_BOOT_TPL_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06002237 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2238 b'ter somewhere in here', first)
Simon Glassf0253632018-09-14 04:57:32 -06002239
Simon Glassf8f8df62018-09-14 04:57:34 -06002240 def testFmapX86(self):
2241 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06002242 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassf8f8df62018-09-14 04:57:34 -06002243 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc1aa66e2022-01-29 14:14:04 -07002244 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('a'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06002245 self.assertEqual(expected, data[:32])
2246 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2247
2248 self.assertEqual(0x100, fhdr.image_size)
2249
2250 self.assertEqual(0, fentries[0].offset)
2251 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06002252 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06002253
2254 self.assertEqual(4, fentries[1].offset)
2255 self.assertEqual(3, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06002256 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06002257
2258 self.assertEqual(32, fentries[2].offset)
2259 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2260 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06002261 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06002262
2263 def testFmapX86Section(self):
2264 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06002265 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002266 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('b'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06002267 self.assertEqual(expected, data[:32])
2268 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2269
Simon Glass17365752021-04-03 11:05:10 +13002270 self.assertEqual(0x180, fhdr.image_size)
2271 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
Simon Glassc7722e82021-04-03 11:05:09 +13002272 fiter = iter(fentries)
Simon Glassf8f8df62018-09-14 04:57:34 -06002273
Simon Glassc7722e82021-04-03 11:05:09 +13002274 fentry = next(fiter)
2275 self.assertEqual(b'U_BOOT', fentry.name)
2276 self.assertEqual(0, fentry.offset)
2277 self.assertEqual(4, fentry.size)
Simon Glassf8f8df62018-09-14 04:57:34 -06002278
Simon Glassc7722e82021-04-03 11:05:09 +13002279 fentry = next(fiter)
Simon Glass17365752021-04-03 11:05:10 +13002280 self.assertEqual(b'SECTION', fentry.name)
2281 self.assertEqual(4, fentry.offset)
2282 self.assertEqual(0x20 + expect_size, fentry.size)
2283
2284 fentry = next(fiter)
Simon Glassc7722e82021-04-03 11:05:09 +13002285 self.assertEqual(b'INTEL_MRC', fentry.name)
2286 self.assertEqual(4, fentry.offset)
2287 self.assertEqual(3, fentry.size)
Simon Glassf8f8df62018-09-14 04:57:34 -06002288
Simon Glassc7722e82021-04-03 11:05:09 +13002289 fentry = next(fiter)
2290 self.assertEqual(b'FMAP', fentry.name)
2291 self.assertEqual(36, fentry.offset)
2292 self.assertEqual(expect_size, fentry.size)
Simon Glassf8f8df62018-09-14 04:57:34 -06002293
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002294 def testElf(self):
2295 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06002296 self._SetupSplElf()
Simon Glass2090f1e2019-08-24 07:23:00 -06002297 self._SetupTplElf()
Simon Glass53e22bf2019-08-24 07:22:53 -06002298 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002299 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06002300 data = self._DoReadFile('096_elf.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002301
Simon Glass093d1682019-07-08 13:18:25 -06002302 def testElfStrip(self):
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002303 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06002304 self._SetupSplElf()
Simon Glass53e22bf2019-08-24 07:22:53 -06002305 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002306 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06002307 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002308
Simon Glass163ed6c2018-09-14 04:57:36 -06002309 def testPackOverlapMap(self):
2310 """Test that overlapping regions are detected"""
2311 with test_util.capture_sys_output() as (stdout, stderr):
2312 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002313 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002314 map_fname = tools.get_output_filename('image.map')
Simon Glass163ed6c2018-09-14 04:57:36 -06002315 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2316 stdout.getvalue())
2317
2318 # We should not get an inmage, but there should be a map file
Simon Glassc1aa66e2022-01-29 14:14:04 -07002319 self.assertFalse(os.path.exists(tools.get_output_filename('image.bin')))
Simon Glass163ed6c2018-09-14 04:57:36 -06002320 self.assertTrue(os.path.exists(map_fname))
Simon Glassc1aa66e2022-01-29 14:14:04 -07002321 map_data = tools.read_file(map_fname, binary=False)
Simon Glass163ed6c2018-09-14 04:57:36 -06002322 self.assertEqual('''ImagePos Offset Size Name
Simon Glass193d3db2023-02-07 14:34:18 -07002323<none> 00000000 00000008 image
Simon Glass163ed6c2018-09-14 04:57:36 -06002324<none> 00000000 00000004 u-boot
2325<none> 00000003 00000004 u-boot-align
2326''', map_data)
2327
Simon Glass093d1682019-07-08 13:18:25 -06002328 def testPackRefCode(self):
Simon Glass3ae192c2018-10-01 12:22:31 -06002329 """Test that an image with an Intel Reference code binary works"""
2330 data = self._DoReadFile('100_intel_refcode.dts')
2331 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2332
Simon Glass9481c802019-04-25 21:58:39 -06002333 def testSectionOffset(self):
2334 """Tests use of a section with an offset"""
2335 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2336 map=True)
2337 self.assertEqual('''ImagePos Offset Size Name
Simon Glass193d3db2023-02-07 14:34:18 -0700233800000000 00000000 00000038 image
Simon Glass9481c802019-04-25 21:58:39 -0600233900000004 00000004 00000010 section@0
234000000004 00000000 00000004 u-boot
234100000018 00000018 00000010 section@1
234200000018 00000000 00000004 u-boot
23430000002c 0000002c 00000004 section@2
23440000002c 00000000 00000004 u-boot
2345''', map_data)
2346 self.assertEqual(data,
Simon Glassc1aa66e2022-01-29 14:14:04 -07002347 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2348 tools.get_bytes(0x21, 12) +
2349 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2350 tools.get_bytes(0x61, 12) +
2351 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2352 tools.get_bytes(0x26, 8))
Simon Glass9481c802019-04-25 21:58:39 -06002353
Simon Glassac62fba2019-07-08 13:18:53 -06002354 def testCbfsRaw(self):
2355 """Test base handling of a Coreboot Filesystem (CBFS)
2356
2357 The exact contents of the CBFS is verified by similar tests in
2358 cbfs_util_test.py. The tests here merely check that the files added to
2359 the CBFS can be found in the final image.
2360 """
2361 data = self._DoReadFile('102_cbfs_raw.dts')
2362 size = 0xb0
2363
2364 cbfs = cbfs_util.CbfsReader(data)
2365 self.assertEqual(size, cbfs.rom_size)
2366
2367 self.assertIn('u-boot-dtb', cbfs.files)
2368 cfile = cbfs.files['u-boot-dtb']
2369 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2370
2371 def testCbfsArch(self):
2372 """Test on non-x86 architecture"""
2373 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2374 size = 0x100
2375
2376 cbfs = cbfs_util.CbfsReader(data)
2377 self.assertEqual(size, cbfs.rom_size)
2378
2379 self.assertIn('u-boot-dtb', cbfs.files)
2380 cfile = cbfs.files['u-boot-dtb']
2381 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2382
2383 def testCbfsStage(self):
2384 """Tests handling of a Coreboot Filesystem (CBFS)"""
2385 if not elf.ELF_TOOLS:
2386 self.skipTest('Python elftools not available')
2387 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2388 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2389 size = 0xb0
2390
2391 data = self._DoReadFile('104_cbfs_stage.dts')
2392 cbfs = cbfs_util.CbfsReader(data)
2393 self.assertEqual(size, cbfs.rom_size)
2394
2395 self.assertIn('u-boot', cbfs.files)
2396 cfile = cbfs.files['u-boot']
2397 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2398
2399 def testCbfsRawCompress(self):
2400 """Test handling of compressing raw files"""
2401 self._CheckLz4()
2402 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2403 size = 0x140
2404
2405 cbfs = cbfs_util.CbfsReader(data)
2406 self.assertIn('u-boot', cbfs.files)
2407 cfile = cbfs.files['u-boot']
2408 self.assertEqual(COMPRESS_DATA, cfile.data)
2409
2410 def testCbfsBadArch(self):
2411 """Test handling of a bad architecture"""
2412 with self.assertRaises(ValueError) as e:
2413 self._DoReadFile('106_cbfs_bad_arch.dts')
2414 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2415
2416 def testCbfsNoSize(self):
2417 """Test handling of a missing size property"""
2418 with self.assertRaises(ValueError) as e:
2419 self._DoReadFile('107_cbfs_no_size.dts')
2420 self.assertIn('entry must have a size property', str(e.exception))
2421
Simon Glasse2f04742021-11-23 11:03:54 -07002422 def testCbfsNoContents(self):
Simon Glassac62fba2019-07-08 13:18:53 -06002423 """Test handling of a CBFS entry which does not provide contentsy"""
2424 with self.assertRaises(ValueError) as e:
2425 self._DoReadFile('108_cbfs_no_contents.dts')
2426 self.assertIn('Could not complete processing of contents',
2427 str(e.exception))
2428
2429 def testCbfsBadCompress(self):
2430 """Test handling of a bad architecture"""
2431 with self.assertRaises(ValueError) as e:
2432 self._DoReadFile('109_cbfs_bad_compress.dts')
2433 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2434 str(e.exception))
2435
2436 def testCbfsNamedEntries(self):
2437 """Test handling of named entries"""
2438 data = self._DoReadFile('110_cbfs_name.dts')
2439
2440 cbfs = cbfs_util.CbfsReader(data)
2441 self.assertIn('FRED', cbfs.files)
2442 cfile1 = cbfs.files['FRED']
2443 self.assertEqual(U_BOOT_DATA, cfile1.data)
2444
2445 self.assertIn('hello', cbfs.files)
2446 cfile2 = cbfs.files['hello']
2447 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2448
Simon Glassc5ac1382019-07-08 13:18:54 -06002449 def _SetupIfwi(self, fname):
2450 """Set up to run an IFWI test
2451
2452 Args:
2453 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2454 """
2455 self._SetupSplElf()
Simon Glass2090f1e2019-08-24 07:23:00 -06002456 self._SetupTplElf()
Simon Glassc5ac1382019-07-08 13:18:54 -06002457
2458 # Intel Integrated Firmware Image (IFWI) file
2459 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2460 data = fd.read()
2461 TestFunctional._MakeInputFile(fname,data)
2462
2463 def _CheckIfwi(self, data):
2464 """Check that an image with an IFWI contains the correct output
2465
2466 Args:
2467 data: Conents of output file
2468 """
Simon Glassc1aa66e2022-01-29 14:14:04 -07002469 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glassc5ac1382019-07-08 13:18:54 -06002470 if data[:0x1000] != expected_desc:
2471 self.fail('Expected descriptor binary at start of image')
2472
2473 # We expect to find the TPL wil in subpart IBBP entry IBBL
Simon Glassc1aa66e2022-01-29 14:14:04 -07002474 image_fname = tools.get_output_filename('image.bin')
2475 tpl_fname = tools.get_output_filename('tpl.out')
Simon Glass532ae702022-01-09 20:14:01 -07002476 ifwitool = bintool.Bintool.create('ifwitool')
2477 ifwitool.extract(image_fname, 'IBBP', 'IBBL', tpl_fname)
Simon Glassc5ac1382019-07-08 13:18:54 -06002478
Simon Glassc1aa66e2022-01-29 14:14:04 -07002479 tpl_data = tools.read_file(tpl_fname)
Simon Glasse95be632019-08-24 07:22:51 -06002480 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glassc5ac1382019-07-08 13:18:54 -06002481
2482 def testPackX86RomIfwi(self):
2483 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2484 self._SetupIfwi('fitimage.bin')
Simon Glass9255f3c2019-08-24 07:23:01 -06002485 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002486 self._CheckIfwi(data)
2487
2488 def testPackX86RomIfwiNoDesc(self):
2489 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2490 self._SetupIfwi('ifwi.bin')
Simon Glass9255f3c2019-08-24 07:23:01 -06002491 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002492 self._CheckIfwi(data)
2493
2494 def testPackX86RomIfwiNoData(self):
2495 """Test that an x86 ROM with IFWI handles missing data"""
2496 self._SetupIfwi('ifwi.bin')
2497 with self.assertRaises(ValueError) as e:
Simon Glass9255f3c2019-08-24 07:23:01 -06002498 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002499 self.assertIn('Could not complete processing of contents',
2500 str(e.exception))
Simon Glass53af22a2018-07-17 13:25:32 -06002501
Simon Glass4f9ee832022-01-09 20:14:09 -07002502 def testIfwiMissing(self):
2503 """Test that binman still produces an image if ifwitool is missing"""
2504 self._SetupIfwi('fitimage.bin')
2505 with test_util.capture_sys_output() as (_, stderr):
2506 self._DoTestFile('111_x86_rom_ifwi.dts',
2507 force_missing_bintools='ifwitool')
2508 err = stderr.getvalue()
2509 self.assertRegex(err,
Simon Glass193d3db2023-02-07 14:34:18 -07002510 "Image 'image'.*missing bintools.*: ifwitool")
Simon Glass4f9ee832022-01-09 20:14:09 -07002511
Simon Glasse073d4e2019-07-08 13:18:56 -06002512 def testCbfsOffset(self):
2513 """Test a CBFS with files at particular offsets
2514
2515 Like all CFBS tests, this is just checking the logic that calls
2516 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2517 """
2518 data = self._DoReadFile('114_cbfs_offset.dts')
2519 size = 0x200
2520
2521 cbfs = cbfs_util.CbfsReader(data)
2522 self.assertEqual(size, cbfs.rom_size)
2523
2524 self.assertIn('u-boot', cbfs.files)
2525 cfile = cbfs.files['u-boot']
2526 self.assertEqual(U_BOOT_DATA, cfile.data)
2527 self.assertEqual(0x40, cfile.cbfs_offset)
2528
2529 self.assertIn('u-boot-dtb', cbfs.files)
2530 cfile2 = cbfs.files['u-boot-dtb']
2531 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2532 self.assertEqual(0x140, cfile2.cbfs_offset)
2533
Simon Glass086cec92019-07-08 14:25:27 -06002534 def testFdtmap(self):
2535 """Test an FDT map can be inserted in the image"""
2536 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2537 fdtmap_data = data[len(U_BOOT_DATA):]
2538 magic = fdtmap_data[:8]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002539 self.assertEqual(b'_FDTMAP_', magic)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002540 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass086cec92019-07-08 14:25:27 -06002541
2542 fdt_data = fdtmap_data[16:]
2543 dtb = fdt.Fdt.FromData(fdt_data)
2544 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002545 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass086cec92019-07-08 14:25:27 -06002546 self.assertEqual({
2547 'image-pos': 0,
2548 'offset': 0,
2549 'u-boot:offset': 0,
2550 'u-boot:size': len(U_BOOT_DATA),
2551 'u-boot:image-pos': 0,
2552 'fdtmap:image-pos': 4,
2553 'fdtmap:offset': 4,
2554 'fdtmap:size': len(fdtmap_data),
2555 'size': len(data),
2556 }, props)
2557
2558 def testFdtmapNoMatch(self):
2559 """Check handling of an FDT map when the section cannot be found"""
2560 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2561
2562 # Mangle the section name, which should cause a mismatch between the
2563 # correct FDT path and the one expected by the section
2564 image = control.images['image']
Simon Glasscf228942019-07-08 14:25:28 -06002565 image._node.path += '-suffix'
Simon Glass086cec92019-07-08 14:25:27 -06002566 entries = image.GetEntries()
2567 fdtmap = entries['fdtmap']
2568 with self.assertRaises(ValueError) as e:
2569 fdtmap._GetFdtmap()
2570 self.assertIn("Cannot locate node for path '/binman-suffix'",
2571 str(e.exception))
2572
Simon Glasscf228942019-07-08 14:25:28 -06002573 def testFdtmapHeader(self):
2574 """Test an FDT map and image header can be inserted in the image"""
2575 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2576 fdtmap_pos = len(U_BOOT_DATA)
2577 fdtmap_data = data[fdtmap_pos:]
2578 fdt_data = fdtmap_data[16:]
2579 dtb = fdt.Fdt.FromData(fdt_data)
2580 fdt_size = dtb.GetFdtObj().totalsize()
2581 hdr_data = data[-8:]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002582 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002583 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2584 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2585
2586 def testFdtmapHeaderStart(self):
2587 """Test an image header can be inserted at the image start"""
2588 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2589 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2590 hdr_data = data[:8]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002591 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002592 offset = struct.unpack('<I', hdr_data[4:])[0]
2593 self.assertEqual(fdtmap_pos, offset)
2594
2595 def testFdtmapHeaderPos(self):
2596 """Test an image header can be inserted at a chosen position"""
2597 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2598 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2599 hdr_data = data[0x80:0x88]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002600 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002601 offset = struct.unpack('<I', hdr_data[4:])[0]
2602 self.assertEqual(fdtmap_pos, offset)
2603
2604 def testHeaderMissingFdtmap(self):
2605 """Test an image header requires an fdtmap"""
2606 with self.assertRaises(ValueError) as e:
2607 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2608 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2609 str(e.exception))
2610
2611 def testHeaderNoLocation(self):
2612 """Test an image header with a no specified location is detected"""
2613 with self.assertRaises(ValueError) as e:
2614 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2615 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2616 str(e.exception))
2617
Simon Glassc52c9e72019-07-08 14:25:37 -06002618 def testEntryExpand(self):
Simon Glass80a66ae2022-03-05 20:18:59 -07002619 """Test extending an entry after it is packed"""
2620 data = self._DoReadFile('121_entry_extend.dts')
Simon Glass79d3c582019-07-20 12:23:57 -06002621 self.assertEqual(b'aaa', data[:3])
2622 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2623 self.assertEqual(b'aaa', data[-3:])
Simon Glassc52c9e72019-07-08 14:25:37 -06002624
Simon Glass80a66ae2022-03-05 20:18:59 -07002625 def testEntryExtendBad(self):
2626 """Test extending an entry after it is packed, twice"""
Simon Glassc52c9e72019-07-08 14:25:37 -06002627 with self.assertRaises(ValueError) as e:
Simon Glass80a66ae2022-03-05 20:18:59 -07002628 self._DoReadFile('122_entry_extend_twice.dts')
Simon Glass61ec04f2019-07-20 12:23:58 -06002629 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glassc52c9e72019-07-08 14:25:37 -06002630 str(e.exception))
2631
Simon Glass80a66ae2022-03-05 20:18:59 -07002632 def testEntryExtendSection(self):
2633 """Test extending an entry within a section after it is packed"""
2634 data = self._DoReadFile('123_entry_extend_section.dts')
Simon Glass79d3c582019-07-20 12:23:57 -06002635 self.assertEqual(b'aaa', data[:3])
2636 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2637 self.assertEqual(b'aaa', data[-3:])
Simon Glassc52c9e72019-07-08 14:25:37 -06002638
Simon Glass6c223fd2019-07-08 14:25:38 -06002639 def testCompressDtb(self):
2640 """Test that compress of device-tree files is supported"""
2641 self._CheckLz4()
2642 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2643 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2644 comp_data = data[len(U_BOOT_DATA):]
2645 orig = self._decompress(comp_data)
2646 dtb = fdt.Fdt.FromData(orig)
2647 dtb.Scan()
2648 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2649 expected = {
2650 'u-boot:size': len(U_BOOT_DATA),
2651 'u-boot-dtb:uncomp-size': len(orig),
2652 'u-boot-dtb:size': len(comp_data),
2653 'size': len(data),
2654 }
2655 self.assertEqual(expected, props)
2656
Simon Glass69f7cb32019-07-08 14:25:41 -06002657 def testCbfsUpdateFdt(self):
2658 """Test that we can update the device tree with CBFS offset/size info"""
2659 self._CheckLz4()
2660 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2661 update_dtb=True)
2662 dtb = fdt.Fdt(out_dtb_fname)
2663 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002664 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass69f7cb32019-07-08 14:25:41 -06002665 del props['cbfs/u-boot:size']
2666 self.assertEqual({
2667 'offset': 0,
2668 'size': len(data),
2669 'image-pos': 0,
2670 'cbfs:offset': 0,
2671 'cbfs:size': len(data),
2672 'cbfs:image-pos': 0,
Simon Glassab326012023-10-14 14:40:28 -06002673 'cbfs/u-boot:offset': 0x30,
Simon Glass69f7cb32019-07-08 14:25:41 -06002674 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
Simon Glassab326012023-10-14 14:40:28 -06002675 'cbfs/u-boot:image-pos': 0x30,
2676 'cbfs/u-boot-dtb:offset': 0xa4,
Simon Glass69f7cb32019-07-08 14:25:41 -06002677 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
Simon Glassab326012023-10-14 14:40:28 -06002678 'cbfs/u-boot-dtb:image-pos': 0xa4,
Simon Glass69f7cb32019-07-08 14:25:41 -06002679 }, props)
2680
Simon Glass8a1ad062019-07-08 14:25:42 -06002681 def testCbfsBadType(self):
2682 """Test an image header with a no specified location is detected"""
2683 with self.assertRaises(ValueError) as e:
2684 self._DoReadFile('126_cbfs_bad_type.dts')
2685 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2686
Simon Glass41b8ba02019-07-08 14:25:43 -06002687 def testList(self):
2688 """Test listing the files in an image"""
2689 self._CheckLz4()
2690 data = self._DoReadFile('127_list.dts')
2691 image = control.images['image']
2692 entries = image.BuildEntryList()
2693 self.assertEqual(7, len(entries))
2694
2695 ent = entries[0]
2696 self.assertEqual(0, ent.indent)
Simon Glass193d3db2023-02-07 14:34:18 -07002697 self.assertEqual('image', ent.name)
Simon Glass41b8ba02019-07-08 14:25:43 -06002698 self.assertEqual('section', ent.etype)
2699 self.assertEqual(len(data), ent.size)
2700 self.assertEqual(0, ent.image_pos)
2701 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002702 self.assertEqual(0, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002703
2704 ent = entries[1]
2705 self.assertEqual(1, ent.indent)
2706 self.assertEqual('u-boot', ent.name)
2707 self.assertEqual('u-boot', ent.etype)
2708 self.assertEqual(len(U_BOOT_DATA), ent.size)
2709 self.assertEqual(0, ent.image_pos)
2710 self.assertEqual(None, ent.uncomp_size)
2711 self.assertEqual(0, ent.offset)
2712
2713 ent = entries[2]
2714 self.assertEqual(1, ent.indent)
2715 self.assertEqual('section', ent.name)
2716 self.assertEqual('section', ent.etype)
2717 section_size = ent.size
2718 self.assertEqual(0x100, ent.image_pos)
2719 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002720 self.assertEqual(0x100, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002721
2722 ent = entries[3]
2723 self.assertEqual(2, ent.indent)
2724 self.assertEqual('cbfs', ent.name)
2725 self.assertEqual('cbfs', ent.etype)
2726 self.assertEqual(0x400, ent.size)
2727 self.assertEqual(0x100, ent.image_pos)
2728 self.assertEqual(None, ent.uncomp_size)
2729 self.assertEqual(0, ent.offset)
2730
2731 ent = entries[4]
2732 self.assertEqual(3, ent.indent)
2733 self.assertEqual('u-boot', ent.name)
2734 self.assertEqual('u-boot', ent.etype)
2735 self.assertEqual(len(U_BOOT_DATA), ent.size)
2736 self.assertEqual(0x138, ent.image_pos)
2737 self.assertEqual(None, ent.uncomp_size)
2738 self.assertEqual(0x38, ent.offset)
2739
2740 ent = entries[5]
2741 self.assertEqual(3, ent.indent)
2742 self.assertEqual('u-boot-dtb', ent.name)
2743 self.assertEqual('text', ent.etype)
2744 self.assertGreater(len(COMPRESS_DATA), ent.size)
2745 self.assertEqual(0x178, ent.image_pos)
2746 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2747 self.assertEqual(0x78, ent.offset)
2748
2749 ent = entries[6]
2750 self.assertEqual(2, ent.indent)
2751 self.assertEqual('u-boot-dtb', ent.name)
2752 self.assertEqual('u-boot-dtb', ent.etype)
2753 self.assertEqual(0x500, ent.image_pos)
2754 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2755 dtb_size = ent.size
2756 # Compressing this data expands it since headers are added
2757 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2758 self.assertEqual(0x400, ent.offset)
2759
2760 self.assertEqual(len(data), 0x100 + section_size)
2761 self.assertEqual(section_size, 0x400 + dtb_size)
2762
Simon Glasse1925fa2019-07-08 14:25:44 -06002763 def testFindFdtmap(self):
2764 """Test locating an FDT map in an image"""
2765 self._CheckLz4()
2766 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2767 image = control.images['image']
2768 entries = image.GetEntries()
2769 entry = entries['fdtmap']
2770 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2771
2772 def testFindFdtmapMissing(self):
2773 """Test failing to locate an FDP map"""
2774 data = self._DoReadFile('005_simple.dts')
2775 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2776
Simon Glass2d260032019-07-08 14:25:45 -06002777 def testFindImageHeader(self):
2778 """Test locating a image header"""
2779 self._CheckLz4()
Simon Glassffded752019-07-08 14:25:46 -06002780 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002781 image = control.images['image']
2782 entries = image.GetEntries()
2783 entry = entries['fdtmap']
2784 # The header should point to the FDT map
2785 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2786
2787 def testFindImageHeaderStart(self):
2788 """Test locating a image header located at the start of an image"""
Simon Glassffded752019-07-08 14:25:46 -06002789 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002790 image = control.images['image']
2791 entries = image.GetEntries()
2792 entry = entries['fdtmap']
2793 # The header should point to the FDT map
2794 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2795
2796 def testFindImageHeaderMissing(self):
2797 """Test failing to locate an image header"""
2798 data = self._DoReadFile('005_simple.dts')
2799 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2800
Simon Glassffded752019-07-08 14:25:46 -06002801 def testReadImage(self):
2802 """Test reading an image and accessing its FDT map"""
2803 self._CheckLz4()
2804 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002805 image_fname = tools.get_output_filename('image.bin')
Simon Glassffded752019-07-08 14:25:46 -06002806 orig_image = control.images['image']
2807 image = Image.FromFile(image_fname)
2808 self.assertEqual(orig_image.GetEntries().keys(),
2809 image.GetEntries().keys())
2810
2811 orig_entry = orig_image.GetEntries()['fdtmap']
2812 entry = image.GetEntries()['fdtmap']
Brandon Maier357bfca2024-06-04 16:16:05 +00002813 self.assertEqual(orig_entry.offset, entry.offset)
2814 self.assertEqual(orig_entry.size, entry.size)
2815 self.assertEqual(orig_entry.image_pos, entry.image_pos)
Simon Glassffded752019-07-08 14:25:46 -06002816
2817 def testReadImageNoHeader(self):
2818 """Test accessing an image's FDT map without an image header"""
2819 self._CheckLz4()
2820 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002821 image_fname = tools.get_output_filename('image.bin')
Simon Glassffded752019-07-08 14:25:46 -06002822 image = Image.FromFile(image_fname)
2823 self.assertTrue(isinstance(image, Image))
Simon Glass10f9d002019-07-20 12:23:50 -06002824 self.assertEqual('image', image.image_name[-5:])
Simon Glassffded752019-07-08 14:25:46 -06002825
2826 def testReadImageFail(self):
2827 """Test failing to read an image image's FDT map"""
2828 self._DoReadFile('005_simple.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002829 image_fname = tools.get_output_filename('image.bin')
Simon Glassffded752019-07-08 14:25:46 -06002830 with self.assertRaises(ValueError) as e:
2831 image = Image.FromFile(image_fname)
2832 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glasse073d4e2019-07-08 13:18:56 -06002833
Simon Glass61f564d2019-07-08 14:25:48 -06002834 def testListCmd(self):
2835 """Test listing the files in an image using an Fdtmap"""
2836 self._CheckLz4()
2837 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2838
2839 # lz4 compression size differs depending on the version
2840 image = control.images['image']
2841 entries = image.GetEntries()
2842 section_size = entries['section'].size
2843 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2844 fdtmap_offset = entries['fdtmap'].offset
2845
Heinrich Schuchardt69c37052023-12-16 00:26:04 +01002846 tmpdir = None
Simon Glassf86a7362019-07-20 12:24:10 -06002847 try:
2848 tmpdir, updated_fname = self._SetupImageInTmpdir()
2849 with test_util.capture_sys_output() as (stdout, stderr):
2850 self._DoBinman('ls', '-i', updated_fname)
2851 finally:
Heinrich Schuchardt69c37052023-12-16 00:26:04 +01002852 if tmpdir:
2853 shutil.rmtree(tmpdir)
Simon Glass61f564d2019-07-08 14:25:48 -06002854 lines = stdout.getvalue().splitlines()
2855 expected = [
2856'Name Image-pos Size Entry-type Offset Uncomp-size',
2857'----------------------------------------------------------------------',
Simon Glass193d3db2023-02-07 14:34:18 -07002858'image 0 c00 section 0',
Simon Glass61f564d2019-07-08 14:25:48 -06002859' u-boot 0 4 u-boot 0',
2860' section 100 %x section 100' % section_size,
2861' cbfs 100 400 cbfs 0',
Simon Glassab326012023-10-14 14:40:28 -06002862' u-boot 120 4 u-boot 20',
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002863' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glass61f564d2019-07-08 14:25:48 -06002864' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002865' fdtmap %x 3bd fdtmap %x' %
Simon Glass61f564d2019-07-08 14:25:48 -06002866 (fdtmap_offset, fdtmap_offset),
2867' image-header bf8 8 image-header bf8',
2868 ]
2869 self.assertEqual(expected, lines)
2870
2871 def testListCmdFail(self):
2872 """Test failing to list an image"""
2873 self._DoReadFile('005_simple.dts')
Heinrich Schuchardt69c37052023-12-16 00:26:04 +01002874 tmpdir = None
Simon Glassf86a7362019-07-20 12:24:10 -06002875 try:
2876 tmpdir, updated_fname = self._SetupImageInTmpdir()
2877 with self.assertRaises(ValueError) as e:
2878 self._DoBinman('ls', '-i', updated_fname)
2879 finally:
Heinrich Schuchardt69c37052023-12-16 00:26:04 +01002880 if tmpdir:
2881 shutil.rmtree(tmpdir)
Simon Glass61f564d2019-07-08 14:25:48 -06002882 self.assertIn("Cannot find FDT map in image", str(e.exception))
2883
2884 def _RunListCmd(self, paths, expected):
2885 """List out entries and check the result
2886
2887 Args:
2888 paths: List of paths to pass to the list command
2889 expected: Expected list of filenames to be returned, in order
2890 """
2891 self._CheckLz4()
2892 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002893 image_fname = tools.get_output_filename('image.bin')
Simon Glass61f564d2019-07-08 14:25:48 -06002894 image = Image.FromFile(image_fname)
2895 lines = image.GetListEntries(paths)[1]
2896 files = [line[0].strip() for line in lines[1:]]
2897 self.assertEqual(expected, files)
2898
2899 def testListCmdSection(self):
2900 """Test listing the files in a section"""
2901 self._RunListCmd(['section'],
2902 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2903
2904 def testListCmdFile(self):
2905 """Test listing a particular file"""
2906 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2907
2908 def testListCmdWildcard(self):
2909 """Test listing a wildcarded file"""
2910 self._RunListCmd(['*boot*'],
2911 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2912
2913 def testListCmdWildcardMulti(self):
2914 """Test listing a wildcarded file"""
2915 self._RunListCmd(['*cb*', '*head*'],
2916 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2917
2918 def testListCmdEmpty(self):
2919 """Test listing a wildcarded file"""
2920 self._RunListCmd(['nothing'], [])
2921
2922 def testListCmdPath(self):
2923 """Test listing the files in a sub-entry of a section"""
2924 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2925
Simon Glassf667e452019-07-08 14:25:50 -06002926 def _RunExtractCmd(self, entry_name, decomp=True):
2927 """Extract an entry from an image
2928
2929 Args:
2930 entry_name: Entry name to extract
2931 decomp: True to decompress the data if compressed, False to leave
2932 it in its raw uncompressed format
2933
2934 Returns:
2935 data from entry
2936 """
2937 self._CheckLz4()
2938 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002939 image_fname = tools.get_output_filename('image.bin')
Simon Glassf667e452019-07-08 14:25:50 -06002940 return control.ReadEntry(image_fname, entry_name, decomp)
2941
2942 def testExtractSimple(self):
2943 """Test extracting a single file"""
2944 data = self._RunExtractCmd('u-boot')
2945 self.assertEqual(U_BOOT_DATA, data)
2946
Simon Glass71ce0ba2019-07-08 14:25:52 -06002947 def testExtractSection(self):
2948 """Test extracting the files in a section"""
2949 data = self._RunExtractCmd('section')
2950 cbfs_data = data[:0x400]
2951 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002952 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass71ce0ba2019-07-08 14:25:52 -06002953 dtb_data = data[0x400:]
2954 dtb = self._decompress(dtb_data)
2955 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2956
2957 def testExtractCompressed(self):
2958 """Test extracting compressed data"""
2959 data = self._RunExtractCmd('section/u-boot-dtb')
2960 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2961
2962 def testExtractRaw(self):
2963 """Test extracting compressed data without decompressing it"""
2964 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2965 dtb = self._decompress(data)
2966 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2967
2968 def testExtractCbfs(self):
2969 """Test extracting CBFS data"""
2970 data = self._RunExtractCmd('section/cbfs/u-boot')
2971 self.assertEqual(U_BOOT_DATA, data)
2972
2973 def testExtractCbfsCompressed(self):
2974 """Test extracting CBFS compressed data"""
2975 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2976 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2977
2978 def testExtractCbfsRaw(self):
2979 """Test extracting CBFS compressed data without decompressing it"""
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +02002980 bintool = self.comp_bintools['lzma_alone']
2981 self._CheckBintool(bintool)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002982 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +02002983 dtb = bintool.decompress(data)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002984 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2985
Simon Glassf667e452019-07-08 14:25:50 -06002986 def testExtractBadEntry(self):
2987 """Test extracting a bad section path"""
2988 with self.assertRaises(ValueError) as e:
2989 self._RunExtractCmd('section/does-not-exist')
2990 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2991 str(e.exception))
2992
2993 def testExtractMissingFile(self):
2994 """Test extracting file that does not exist"""
2995 with self.assertRaises(IOError) as e:
2996 control.ReadEntry('missing-file', 'name')
2997
2998 def testExtractBadFile(self):
2999 """Test extracting an invalid file"""
3000 fname = os.path.join(self._indir, 'badfile')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003001 tools.write_file(fname, b'')
Simon Glassf667e452019-07-08 14:25:50 -06003002 with self.assertRaises(ValueError) as e:
3003 control.ReadEntry(fname, 'name')
3004
Simon Glass71ce0ba2019-07-08 14:25:52 -06003005 def testExtractCmd(self):
3006 """Test extracting a file fron an image on the command line"""
3007 self._CheckLz4()
3008 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass71ce0ba2019-07-08 14:25:52 -06003009 fname = os.path.join(self._indir, 'output.extact')
Heinrich Schuchardt69c37052023-12-16 00:26:04 +01003010 tmpdir = None
Simon Glassf86a7362019-07-20 12:24:10 -06003011 try:
3012 tmpdir, updated_fname = self._SetupImageInTmpdir()
3013 with test_util.capture_sys_output() as (stdout, stderr):
3014 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
3015 '-f', fname)
3016 finally:
Heinrich Schuchardt69c37052023-12-16 00:26:04 +01003017 if tmpdir:
3018 shutil.rmtree(tmpdir)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003019 data = tools.read_file(fname)
Simon Glass71ce0ba2019-07-08 14:25:52 -06003020 self.assertEqual(U_BOOT_DATA, data)
3021
3022 def testExtractOneEntry(self):
3023 """Test extracting a single entry fron an image """
3024 self._CheckLz4()
3025 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003026 image_fname = tools.get_output_filename('image.bin')
Simon Glass71ce0ba2019-07-08 14:25:52 -06003027 fname = os.path.join(self._indir, 'output.extact')
3028 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
Simon Glassc1aa66e2022-01-29 14:14:04 -07003029 data = tools.read_file(fname)
Simon Glass71ce0ba2019-07-08 14:25:52 -06003030 self.assertEqual(U_BOOT_DATA, data)
3031
3032 def _CheckExtractOutput(self, decomp):
3033 """Helper to test file output with and without decompression
3034
3035 Args:
3036 decomp: True to decompress entry data, False to output it raw
3037 """
3038 def _CheckPresent(entry_path, expect_data, expect_size=None):
3039 """Check and remove expected file
3040
3041 This checks the data/size of a file and removes the file both from
3042 the outfiles set and from the output directory. Once all files are
3043 processed, both the set and directory should be empty.
3044
3045 Args:
3046 entry_path: Entry path
3047 expect_data: Data to expect in file, or None to skip check
3048 expect_size: Size of data to expect in file, or None to skip
3049 """
3050 path = os.path.join(outdir, entry_path)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003051 data = tools.read_file(path)
Simon Glass71ce0ba2019-07-08 14:25:52 -06003052 os.remove(path)
3053 if expect_data:
3054 self.assertEqual(expect_data, data)
3055 elif expect_size:
3056 self.assertEqual(expect_size, len(data))
3057 outfiles.remove(path)
3058
3059 def _CheckDirPresent(name):
3060 """Remove expected directory
3061
3062 This gives an error if the directory does not exist as expected
3063
3064 Args:
3065 name: Name of directory to remove
3066 """
3067 path = os.path.join(outdir, name)
3068 os.rmdir(path)
3069
3070 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003071 image_fname = tools.get_output_filename('image.bin')
Simon Glass71ce0ba2019-07-08 14:25:52 -06003072 outdir = os.path.join(self._indir, 'extract')
3073 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
3074
3075 # Create a set of all file that were output (should be 9)
3076 outfiles = set()
3077 for root, dirs, files in os.walk(outdir):
3078 outfiles |= set([os.path.join(root, fname) for fname in files])
3079 self.assertEqual(9, len(outfiles))
3080 self.assertEqual(9, len(einfos))
3081
3082 image = control.images['image']
3083 entries = image.GetEntries()
3084
3085 # Check the 9 files in various ways
3086 section = entries['section']
3087 section_entries = section.GetEntries()
3088 cbfs_entries = section_entries['cbfs'].GetEntries()
3089 _CheckPresent('u-boot', U_BOOT_DATA)
3090 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
3091 dtb_len = EXTRACT_DTB_SIZE
3092 if not decomp:
3093 dtb_len = cbfs_entries['u-boot-dtb'].size
3094 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
3095 if not decomp:
3096 dtb_len = section_entries['u-boot-dtb'].size
3097 _CheckPresent('section/u-boot-dtb', None, dtb_len)
3098
3099 fdtmap = entries['fdtmap']
3100 _CheckPresent('fdtmap', fdtmap.data)
3101 hdr = entries['image-header']
3102 _CheckPresent('image-header', hdr.data)
3103
3104 _CheckPresent('section/root', section.data)
3105 cbfs = section_entries['cbfs']
3106 _CheckPresent('section/cbfs/root', cbfs.data)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003107 data = tools.read_file(image_fname)
Simon Glass71ce0ba2019-07-08 14:25:52 -06003108 _CheckPresent('root', data)
3109
3110 # There should be no files left. Remove all the directories to check.
3111 # If there are any files/dirs remaining, one of these checks will fail.
3112 self.assertEqual(0, len(outfiles))
3113 _CheckDirPresent('section/cbfs')
3114 _CheckDirPresent('section')
3115 _CheckDirPresent('')
3116 self.assertFalse(os.path.exists(outdir))
3117
3118 def testExtractAllEntries(self):
3119 """Test extracting all entries"""
3120 self._CheckLz4()
3121 self._CheckExtractOutput(decomp=True)
3122
3123 def testExtractAllEntriesRaw(self):
3124 """Test extracting all entries without decompressing them"""
3125 self._CheckLz4()
3126 self._CheckExtractOutput(decomp=False)
3127
3128 def testExtractSelectedEntries(self):
3129 """Test extracting some entries"""
3130 self._CheckLz4()
3131 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003132 image_fname = tools.get_output_filename('image.bin')
Simon Glass71ce0ba2019-07-08 14:25:52 -06003133 outdir = os.path.join(self._indir, 'extract')
3134 einfos = control.ExtractEntries(image_fname, None, outdir,
3135 ['*cb*', '*head*'])
3136
3137 # File output is tested by testExtractAllEntries(), so just check that
3138 # the expected entries are selected
3139 names = [einfo.name for einfo in einfos]
3140 self.assertEqual(names,
3141 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
3142
3143 def testExtractNoEntryPaths(self):
3144 """Test extracting some entries"""
3145 self._CheckLz4()
3146 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003147 image_fname = tools.get_output_filename('image.bin')
Simon Glass71ce0ba2019-07-08 14:25:52 -06003148 with self.assertRaises(ValueError) as e:
3149 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassbb5edc12019-07-20 12:24:14 -06003150 self.assertIn('Must specify an entry path to write with -f',
Simon Glass71ce0ba2019-07-08 14:25:52 -06003151 str(e.exception))
3152
3153 def testExtractTooManyEntryPaths(self):
3154 """Test extracting some entries"""
3155 self._CheckLz4()
3156 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003157 image_fname = tools.get_output_filename('image.bin')
Simon Glass71ce0ba2019-07-08 14:25:52 -06003158 with self.assertRaises(ValueError) as e:
3159 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassbb5edc12019-07-20 12:24:14 -06003160 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass71ce0ba2019-07-08 14:25:52 -06003161 str(e.exception))
3162
Simon Glasse2705fa2019-07-08 14:25:53 -06003163 def testPackAlignSection(self):
3164 """Test that sections can have alignment"""
3165 self._DoReadFile('131_pack_align_section.dts')
3166
3167 self.assertIn('image', control.images)
3168 image = control.images['image']
3169 entries = image.GetEntries()
3170 self.assertEqual(3, len(entries))
3171
3172 # First u-boot
3173 self.assertIn('u-boot', entries)
3174 entry = entries['u-boot']
3175 self.assertEqual(0, entry.offset)
3176 self.assertEqual(0, entry.image_pos)
3177 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3178 self.assertEqual(len(U_BOOT_DATA), entry.size)
3179
3180 # Section0
3181 self.assertIn('section0', entries)
3182 section0 = entries['section0']
3183 self.assertEqual(0x10, section0.offset)
3184 self.assertEqual(0x10, section0.image_pos)
3185 self.assertEqual(len(U_BOOT_DATA), section0.size)
3186
3187 # Second u-boot
3188 section_entries = section0.GetEntries()
3189 self.assertIn('u-boot', section_entries)
3190 entry = section_entries['u-boot']
3191 self.assertEqual(0, entry.offset)
3192 self.assertEqual(0x10, entry.image_pos)
3193 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3194 self.assertEqual(len(U_BOOT_DATA), entry.size)
3195
3196 # Section1
3197 self.assertIn('section1', entries)
3198 section1 = entries['section1']
3199 self.assertEqual(0x14, section1.offset)
3200 self.assertEqual(0x14, section1.image_pos)
3201 self.assertEqual(0x20, section1.size)
3202
3203 # Second u-boot
3204 section_entries = section1.GetEntries()
3205 self.assertIn('u-boot', section_entries)
3206 entry = section_entries['u-boot']
3207 self.assertEqual(0, entry.offset)
3208 self.assertEqual(0x14, entry.image_pos)
3209 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3210 self.assertEqual(len(U_BOOT_DATA), entry.size)
3211
3212 # Section2
3213 self.assertIn('section2', section_entries)
3214 section2 = section_entries['section2']
3215 self.assertEqual(0x4, section2.offset)
3216 self.assertEqual(0x18, section2.image_pos)
3217 self.assertEqual(4, section2.size)
3218
3219 # Third u-boot
3220 section_entries = section2.GetEntries()
3221 self.assertIn('u-boot', section_entries)
3222 entry = section_entries['u-boot']
3223 self.assertEqual(0, entry.offset)
3224 self.assertEqual(0x18, entry.image_pos)
3225 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3226 self.assertEqual(len(U_BOOT_DATA), entry.size)
3227
Simon Glass51014aa2019-07-20 12:23:56 -06003228 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3229 dts='132_replace.dts'):
Simon Glass10f9d002019-07-20 12:23:50 -06003230 """Replace an entry in an image
3231
3232 This writes the entry data to update it, then opens the updated file and
3233 returns the value that it now finds there.
3234
3235 Args:
3236 entry_name: Entry name to replace
3237 data: Data to replace it with
3238 decomp: True to compress the data if needed, False if data is
3239 already compressed so should be used as is
Simon Glass51014aa2019-07-20 12:23:56 -06003240 allow_resize: True to allow entries to change size, False to raise
3241 an exception
Simon Glass10f9d002019-07-20 12:23:50 -06003242
3243 Returns:
3244 Tuple:
3245 data from entry
3246 data from fdtmap (excluding header)
Simon Glass51014aa2019-07-20 12:23:56 -06003247 Image object that was modified
Simon Glass10f9d002019-07-20 12:23:50 -06003248 """
Simon Glass51014aa2019-07-20 12:23:56 -06003249 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass10f9d002019-07-20 12:23:50 -06003250 update_dtb=True)[1]
3251
3252 self.assertIn('image', control.images)
3253 image = control.images['image']
3254 entries = image.GetEntries()
3255 orig_dtb_data = entries['u-boot-dtb'].data
3256 orig_fdtmap_data = entries['fdtmap'].data
3257
Simon Glassc1aa66e2022-01-29 14:14:04 -07003258 image_fname = tools.get_output_filename('image.bin')
3259 updated_fname = tools.get_output_filename('image-updated.bin')
3260 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glass51014aa2019-07-20 12:23:56 -06003261 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3262 allow_resize)
Simon Glass10f9d002019-07-20 12:23:50 -06003263 data = control.ReadEntry(updated_fname, entry_name, decomp)
3264
Simon Glass51014aa2019-07-20 12:23:56 -06003265 # The DT data should not change unless resized:
3266 if not allow_resize:
3267 new_dtb_data = entries['u-boot-dtb'].data
3268 self.assertEqual(new_dtb_data, orig_dtb_data)
3269 new_fdtmap_data = entries['fdtmap'].data
3270 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass10f9d002019-07-20 12:23:50 -06003271
Simon Glass51014aa2019-07-20 12:23:56 -06003272 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass10f9d002019-07-20 12:23:50 -06003273
3274 def testReplaceSimple(self):
3275 """Test replacing a single file"""
3276 expected = b'x' * len(U_BOOT_DATA)
Simon Glass51014aa2019-07-20 12:23:56 -06003277 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3278 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06003279 self.assertEqual(expected, data)
3280
3281 # Test that the state looks right. There should be an FDT for the fdtmap
3282 # that we jsut read back in, and it should match what we find in the
3283 # 'control' tables. Checking for an FDT that does not exist should
3284 # return None.
3285 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glass51014aa2019-07-20 12:23:56 -06003286 self.assertIsNotNone(path)
Simon Glass10f9d002019-07-20 12:23:50 -06003287 self.assertEqual(expected_fdtmap, fdtmap)
3288
3289 dtb = state.GetFdtForEtype('fdtmap')
3290 self.assertEqual(dtb.GetContents(), fdtmap)
3291
3292 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3293 self.assertIsNone(missing_path)
3294 self.assertIsNone(missing_fdtmap)
3295
3296 missing_dtb = state.GetFdtForEtype('missing')
3297 self.assertIsNone(missing_dtb)
3298
3299 self.assertEqual('/binman', state.fdt_path_prefix)
3300
3301 def testReplaceResizeFail(self):
3302 """Test replacing a file by something larger"""
3303 expected = U_BOOT_DATA + b'x'
3304 with self.assertRaises(ValueError) as e:
Simon Glass51014aa2019-07-20 12:23:56 -06003305 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3306 dts='139_replace_repack.dts')
Simon Glass10f9d002019-07-20 12:23:50 -06003307 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3308 str(e.exception))
3309
3310 def testReplaceMulti(self):
3311 """Test replacing entry data where multiple images are generated"""
3312 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3313 update_dtb=True)[0]
3314 expected = b'x' * len(U_BOOT_DATA)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003315 updated_fname = tools.get_output_filename('image-updated.bin')
3316 tools.write_file(updated_fname, data)
Simon Glass10f9d002019-07-20 12:23:50 -06003317 entry_name = 'u-boot'
Simon Glass51014aa2019-07-20 12:23:56 -06003318 control.WriteEntry(updated_fname, entry_name, expected,
3319 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06003320 data = control.ReadEntry(updated_fname, entry_name)
3321 self.assertEqual(expected, data)
3322
3323 # Check the state looks right.
3324 self.assertEqual('/binman/image', state.fdt_path_prefix)
3325
3326 # Now check we can write the first image
Simon Glassc1aa66e2022-01-29 14:14:04 -07003327 image_fname = tools.get_output_filename('first-image.bin')
3328 updated_fname = tools.get_output_filename('first-updated.bin')
3329 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glass10f9d002019-07-20 12:23:50 -06003330 entry_name = 'u-boot'
Simon Glass51014aa2019-07-20 12:23:56 -06003331 control.WriteEntry(updated_fname, entry_name, expected,
3332 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06003333 data = control.ReadEntry(updated_fname, entry_name)
3334 self.assertEqual(expected, data)
3335
3336 # Check the state looks right.
3337 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass8beb11e2019-07-08 14:25:47 -06003338
Simon Glass12bb1a92019-07-20 12:23:51 -06003339 def testUpdateFdtAllRepack(self):
3340 """Test that all device trees are updated with offset/size info"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06003341 self._SetupSplElf()
3342 self._SetupTplElf()
Simon Glass12bb1a92019-07-20 12:23:51 -06003343 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3344 SECTION_SIZE = 0x300
3345 DTB_SIZE = 602
3346 FDTMAP_SIZE = 608
3347 base_expected = {
3348 'offset': 0,
3349 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3350 'image-pos': 0,
3351 'section:offset': 0,
3352 'section:size': SECTION_SIZE,
3353 'section:image-pos': 0,
3354 'section/u-boot-dtb:offset': 4,
3355 'section/u-boot-dtb:size': 636,
3356 'section/u-boot-dtb:image-pos': 4,
3357 'u-boot-spl-dtb:offset': SECTION_SIZE,
3358 'u-boot-spl-dtb:size': DTB_SIZE,
3359 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3360 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3361 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3362 'u-boot-tpl-dtb:size': DTB_SIZE,
3363 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3364 'fdtmap:size': FDTMAP_SIZE,
3365 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3366 }
3367 main_expected = {
3368 'section:orig-size': SECTION_SIZE,
3369 'section/u-boot-dtb:orig-offset': 4,
3370 }
3371
3372 # We expect three device-tree files in the output, with the first one
3373 # within a fixed-size section.
3374 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3375 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3376 # main U-Boot tree. All three should have the same positions and offset
3377 # except that the main tree should include the main_expected properties
3378 start = 4
3379 for item in ['', 'spl', 'tpl', None]:
3380 if item is None:
3381 start += 16 # Move past fdtmap header
3382 dtb = fdt.Fdt.FromData(data[start:])
3383 dtb.Scan()
3384 props = self._GetPropTree(dtb,
3385 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3386 prefix='/' if item is None else '/binman/')
3387 expected = dict(base_expected)
3388 if item:
3389 expected[item] = 0
3390 else:
3391 # Main DTB and fdtdec should include the 'orig-' properties
3392 expected.update(main_expected)
3393 # Helpful for debugging:
3394 #for prop in sorted(props):
3395 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3396 self.assertEqual(expected, props)
3397 if item == '':
3398 start = SECTION_SIZE
3399 else:
3400 start += dtb._fdt_obj.totalsize()
3401
Simon Glasseba1f0c2019-07-20 12:23:55 -06003402 def testFdtmapHeaderMiddle(self):
3403 """Test an FDT map in the middle of an image when it should be at end"""
3404 with self.assertRaises(ValueError) as e:
3405 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3406 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3407 str(e.exception))
3408
3409 def testFdtmapHeaderStartBad(self):
3410 """Test an FDT map in middle of an image when it should be at start"""
3411 with self.assertRaises(ValueError) as e:
3412 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3413 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3414 str(e.exception))
3415
3416 def testFdtmapHeaderEndBad(self):
3417 """Test an FDT map at the start of an image when it should be at end"""
3418 with self.assertRaises(ValueError) as e:
3419 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3420 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3421 str(e.exception))
3422
3423 def testFdtmapHeaderNoSize(self):
3424 """Test an image header at the end of an image with undefined size"""
3425 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3426
Simon Glass51014aa2019-07-20 12:23:56 -06003427 def testReplaceResize(self):
3428 """Test replacing a single file in an entry with a larger file"""
3429 expected = U_BOOT_DATA + b'x'
3430 data, _, image = self._RunReplaceCmd('u-boot', expected,
3431 dts='139_replace_repack.dts')
3432 self.assertEqual(expected, data)
3433
3434 entries = image.GetEntries()
3435 dtb_data = entries['u-boot-dtb'].data
3436 dtb = fdt.Fdt.FromData(dtb_data)
3437 dtb.Scan()
3438
3439 # The u-boot section should now be larger in the dtb
3440 node = dtb.GetNode('/binman/u-boot')
3441 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3442
3443 # Same for the fdtmap
3444 fdata = entries['fdtmap'].data
3445 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3446 fdtb.Scan()
3447 fnode = fdtb.GetNode('/u-boot')
3448 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3449
3450 def testReplaceResizeNoRepack(self):
3451 """Test replacing an entry with a larger file when not allowed"""
3452 expected = U_BOOT_DATA + b'x'
3453 with self.assertRaises(ValueError) as e:
3454 self._RunReplaceCmd('u-boot', expected)
3455 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3456 str(e.exception))
3457
Simon Glass61ec04f2019-07-20 12:23:58 -06003458 def testEntryShrink(self):
3459 """Test contracting an entry after it is packed"""
3460 try:
3461 state.SetAllowEntryContraction(True)
3462 data = self._DoReadFileDtb('140_entry_shrink.dts',
3463 update_dtb=True)[0]
3464 finally:
3465 state.SetAllowEntryContraction(False)
3466 self.assertEqual(b'a', data[:1])
3467 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3468 self.assertEqual(b'a', data[-1:])
3469
3470 def testEntryShrinkFail(self):
3471 """Test not being allowed to contract an entry after it is packed"""
3472 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3473
3474 # In this case there is a spare byte at the end of the data. The size of
3475 # the contents is only 1 byte but we still have the size before it
3476 # shrunk.
3477 self.assertEqual(b'a\0', data[:2])
3478 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3479 self.assertEqual(b'a\0', data[-2:])
3480
Simon Glass27145fd2019-07-20 12:24:01 -06003481 def testDescriptorOffset(self):
3482 """Test that the Intel descriptor is always placed at at the start"""
3483 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3484 image = control.images['image']
3485 entries = image.GetEntries()
3486 desc = entries['intel-descriptor']
3487 self.assertEqual(0xff800000, desc.offset);
3488 self.assertEqual(0xff800000, desc.image_pos);
3489
Simon Glasseb0f4a42019-07-20 12:24:06 -06003490 def testReplaceCbfs(self):
3491 """Test replacing a single file in CBFS without changing the size"""
3492 self._CheckLz4()
3493 expected = b'x' * len(U_BOOT_DATA)
3494 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003495 updated_fname = tools.get_output_filename('image-updated.bin')
3496 tools.write_file(updated_fname, data)
Simon Glasseb0f4a42019-07-20 12:24:06 -06003497 entry_name = 'section/cbfs/u-boot'
3498 control.WriteEntry(updated_fname, entry_name, expected,
3499 allow_resize=True)
3500 data = control.ReadEntry(updated_fname, entry_name)
3501 self.assertEqual(expected, data)
3502
3503 def testReplaceResizeCbfs(self):
3504 """Test replacing a single file in CBFS with one of a different size"""
3505 self._CheckLz4()
3506 expected = U_BOOT_DATA + b'x'
3507 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003508 updated_fname = tools.get_output_filename('image-updated.bin')
3509 tools.write_file(updated_fname, data)
Simon Glasseb0f4a42019-07-20 12:24:06 -06003510 entry_name = 'section/cbfs/u-boot'
3511 control.WriteEntry(updated_fname, entry_name, expected,
3512 allow_resize=True)
3513 data = control.ReadEntry(updated_fname, entry_name)
3514 self.assertEqual(expected, data)
3515
Simon Glassa6cb9952019-07-20 12:24:15 -06003516 def _SetupForReplace(self):
3517 """Set up some files to use to replace entries
3518
3519 This generates an image, copies it to a new file, extracts all the files
3520 in it and updates some of them
3521
3522 Returns:
3523 List
3524 Image filename
3525 Output directory
3526 Expected values for updated entries, each a string
3527 """
3528 data = self._DoReadFileRealDtb('143_replace_all.dts')
3529
Simon Glassc1aa66e2022-01-29 14:14:04 -07003530 updated_fname = tools.get_output_filename('image-updated.bin')
3531 tools.write_file(updated_fname, data)
Simon Glassa6cb9952019-07-20 12:24:15 -06003532
3533 outdir = os.path.join(self._indir, 'extract')
3534 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3535
3536 expected1 = b'x' + U_BOOT_DATA + b'y'
3537 u_boot_fname1 = os.path.join(outdir, 'u-boot')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003538 tools.write_file(u_boot_fname1, expected1)
Simon Glassa6cb9952019-07-20 12:24:15 -06003539
3540 expected2 = b'a' + U_BOOT_DATA + b'b'
3541 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003542 tools.write_file(u_boot_fname2, expected2)
Simon Glassa6cb9952019-07-20 12:24:15 -06003543
3544 expected_text = b'not the same text'
3545 text_fname = os.path.join(outdir, 'text')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003546 tools.write_file(text_fname, expected_text)
Simon Glassa6cb9952019-07-20 12:24:15 -06003547
3548 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3549 dtb = fdt.FdtScan(dtb_fname)
3550 node = dtb.GetNode('/binman/text')
3551 node.AddString('my-property', 'the value')
3552 dtb.Sync(auto_resize=True)
3553 dtb.Flush()
3554
3555 return updated_fname, outdir, expected1, expected2, expected_text
3556
3557 def _CheckReplaceMultiple(self, entry_paths):
3558 """Handle replacing the contents of multiple entries
3559
3560 Args:
3561 entry_paths: List of entry paths to replace
3562
3563 Returns:
3564 List
3565 Dict of entries in the image:
3566 key: Entry name
3567 Value: Entry object
3568 Expected values for updated entries, each a string
3569 """
3570 updated_fname, outdir, expected1, expected2, expected_text = (
3571 self._SetupForReplace())
3572 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3573
3574 image = Image.FromFile(updated_fname)
3575 image.LoadData()
3576 return image.GetEntries(), expected1, expected2, expected_text
3577
3578 def testReplaceAll(self):
3579 """Test replacing the contents of all entries"""
3580 entries, expected1, expected2, expected_text = (
3581 self._CheckReplaceMultiple([]))
3582 data = entries['u-boot'].data
3583 self.assertEqual(expected1, data)
3584
3585 data = entries['u-boot2'].data
3586 self.assertEqual(expected2, data)
3587
3588 data = entries['text'].data
3589 self.assertEqual(expected_text, data)
3590
3591 # Check that the device tree is updated
3592 data = entries['u-boot-dtb'].data
3593 dtb = fdt.Fdt.FromData(data)
3594 dtb.Scan()
3595 node = dtb.GetNode('/binman/text')
3596 self.assertEqual('the value', node.props['my-property'].value)
3597
3598 def testReplaceSome(self):
3599 """Test replacing the contents of a few entries"""
3600 entries, expected1, expected2, expected_text = (
3601 self._CheckReplaceMultiple(['u-boot2', 'text']))
3602
3603 # This one should not change
3604 data = entries['u-boot'].data
3605 self.assertEqual(U_BOOT_DATA, data)
3606
3607 data = entries['u-boot2'].data
3608 self.assertEqual(expected2, data)
3609
3610 data = entries['text'].data
3611 self.assertEqual(expected_text, data)
3612
3613 def testReplaceCmd(self):
3614 """Test replacing a file fron an image on the command line"""
3615 self._DoReadFileRealDtb('143_replace_all.dts')
3616
3617 try:
3618 tmpdir, updated_fname = self._SetupImageInTmpdir()
3619
3620 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3621 expected = b'x' * len(U_BOOT_DATA)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003622 tools.write_file(fname, expected)
Simon Glassa6cb9952019-07-20 12:24:15 -06003623
3624 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003625 data = tools.read_file(updated_fname)
Simon Glassa6cb9952019-07-20 12:24:15 -06003626 self.assertEqual(expected, data[:len(expected)])
3627 map_fname = os.path.join(tmpdir, 'image-updated.map')
3628 self.assertFalse(os.path.exists(map_fname))
3629 finally:
3630 shutil.rmtree(tmpdir)
3631
3632 def testReplaceCmdSome(self):
3633 """Test replacing some files fron an image on the command line"""
3634 updated_fname, outdir, expected1, expected2, expected_text = (
3635 self._SetupForReplace())
3636
3637 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3638 'u-boot2', 'text')
3639
Simon Glassc1aa66e2022-01-29 14:14:04 -07003640 tools.prepare_output_dir(None)
Simon Glassa6cb9952019-07-20 12:24:15 -06003641 image = Image.FromFile(updated_fname)
3642 image.LoadData()
3643 entries = image.GetEntries()
3644
3645 # This one should not change
3646 data = entries['u-boot'].data
3647 self.assertEqual(U_BOOT_DATA, data)
3648
3649 data = entries['u-boot2'].data
3650 self.assertEqual(expected2, data)
3651
3652 data = entries['text'].data
3653 self.assertEqual(expected_text, data)
3654
3655 def testReplaceMissing(self):
3656 """Test replacing entries where the file is missing"""
3657 updated_fname, outdir, expected1, expected2, expected_text = (
3658 self._SetupForReplace())
3659
3660 # Remove one of the files, to generate a warning
3661 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3662 os.remove(u_boot_fname1)
3663
3664 with test_util.capture_sys_output() as (stdout, stderr):
3665 control.ReplaceEntries(updated_fname, None, outdir, [])
3666 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass38fdb4c2020-07-09 18:39:39 -06003667 stderr.getvalue())
Simon Glassa6cb9952019-07-20 12:24:15 -06003668
3669 def testReplaceCmdMap(self):
3670 """Test replacing a file fron an image on the command line"""
3671 self._DoReadFileRealDtb('143_replace_all.dts')
3672
3673 try:
3674 tmpdir, updated_fname = self._SetupImageInTmpdir()
3675
3676 fname = os.path.join(self._indir, 'update-u-boot.bin')
3677 expected = b'x' * len(U_BOOT_DATA)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003678 tools.write_file(fname, expected)
Simon Glassa6cb9952019-07-20 12:24:15 -06003679
3680 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3681 '-f', fname, '-m')
3682 map_fname = os.path.join(tmpdir, 'image-updated.map')
3683 self.assertTrue(os.path.exists(map_fname))
3684 finally:
3685 shutil.rmtree(tmpdir)
3686
3687 def testReplaceNoEntryPaths(self):
3688 """Test replacing an entry without an entry path"""
3689 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003690 image_fname = tools.get_output_filename('image.bin')
Simon Glassa6cb9952019-07-20 12:24:15 -06003691 with self.assertRaises(ValueError) as e:
3692 control.ReplaceEntries(image_fname, 'fname', None, [])
3693 self.assertIn('Must specify an entry path to read with -f',
3694 str(e.exception))
3695
3696 def testReplaceTooManyEntryPaths(self):
3697 """Test extracting some entries"""
3698 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003699 image_fname = tools.get_output_filename('image.bin')
Simon Glassa6cb9952019-07-20 12:24:15 -06003700 with self.assertRaises(ValueError) as e:
3701 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3702 self.assertIn('Must specify exactly one entry path to write with -f',
3703 str(e.exception))
3704
Simon Glass2250ee62019-08-24 07:22:48 -06003705 def testPackReset16(self):
3706 """Test that an image with an x86 reset16 region can be created"""
3707 data = self._DoReadFile('144_x86_reset16.dts')
3708 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3709
3710 def testPackReset16Spl(self):
3711 """Test that an image with an x86 reset16-spl region can be created"""
3712 data = self._DoReadFile('145_x86_reset16_spl.dts')
3713 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3714
3715 def testPackReset16Tpl(self):
3716 """Test that an image with an x86 reset16-tpl region can be created"""
3717 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3718 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3719
Simon Glass5af12072019-08-24 07:22:50 -06003720 def testPackIntelFit(self):
3721 """Test that an image with an Intel FIT and pointer can be created"""
3722 data = self._DoReadFile('147_intel_fit.dts')
3723 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3724 fit = data[16:32];
3725 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3726 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3727
3728 image = control.images['image']
3729 entries = image.GetEntries()
3730 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3731 self.assertEqual(expected_ptr, ptr)
3732
3733 def testPackIntelFitMissing(self):
3734 """Test detection of a FIT pointer with not FIT region"""
3735 with self.assertRaises(ValueError) as e:
3736 self._DoReadFile('148_intel_fit_missing.dts')
3737 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3738 str(e.exception))
3739
Simon Glass7c150132019-11-06 17:22:44 -07003740 def _CheckSymbolsTplSection(self, dts, expected_vals):
3741 data = self._DoReadFile(dts)
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003742 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE, *expected_vals)
Simon Glass2090f1e2019-08-24 07:23:00 -06003743 upto1 = 4 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003744 expected1 = tools.get_bytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass2090f1e2019-08-24 07:23:00 -06003745 self.assertEqual(expected1, data[:upto1])
3746
3747 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003748 expected2 = tools.get_bytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass2090f1e2019-08-24 07:23:00 -06003749 self.assertEqual(expected2, data[upto1:upto2])
3750
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003751 upto3 = 0x3c + len(U_BOOT_DATA)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003752 expected3 = tools.get_bytes(0xff, 1) + U_BOOT_DATA
Simon Glass2090f1e2019-08-24 07:23:00 -06003753 self.assertEqual(expected3, data[upto2:upto3])
3754
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003755 expected4 = sym_values + U_BOOT_TPL_DATA[24:]
Simon Glass7c150132019-11-06 17:22:44 -07003756 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3757
3758 def testSymbolsTplSection(self):
3759 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3760 self._SetupSplElf('u_boot_binman_syms')
3761 self._SetupTplElf('u_boot_binman_syms')
3762 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003763 [0x04, 0x20, 0x10 + 0x3c, 0x04])
Simon Glass7c150132019-11-06 17:22:44 -07003764
3765 def testSymbolsTplSectionX86(self):
3766 """Test binman can assign symbols in a section with end-at-4gb"""
3767 self._SetupSplElf('u_boot_binman_syms_x86')
3768 self._SetupTplElf('u_boot_binman_syms_x86')
3769 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003770 [0xffffff04, 0xffffff20, 0xffffff3c,
Simon Glass7c150132019-11-06 17:22:44 -07003771 0x04])
Simon Glass2090f1e2019-08-24 07:23:00 -06003772
Simon Glassbf4d0e22019-08-24 07:23:03 -06003773 def testPackX86RomIfwiSectiom(self):
3774 """Test that a section can be placed in an IFWI region"""
3775 self._SetupIfwi('fitimage.bin')
3776 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3777 self._CheckIfwi(data)
3778
Simon Glassea0fff92019-08-24 07:23:07 -06003779 def testPackFspM(self):
3780 """Test that an image with a FSP memory-init binary can be created"""
3781 data = self._DoReadFile('152_intel_fsp_m.dts')
3782 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3783
Simon Glassbc6a88f2019-10-20 21:31:35 -06003784 def testPackFspS(self):
3785 """Test that an image with a FSP silicon-init binary can be created"""
3786 data = self._DoReadFile('153_intel_fsp_s.dts')
3787 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassea0fff92019-08-24 07:23:07 -06003788
Simon Glass998d1482019-10-20 21:31:36 -06003789 def testPackFspT(self):
3790 """Test that an image with a FSP temp-ram-init binary can be created"""
3791 data = self._DoReadFile('154_intel_fsp_t.dts')
3792 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3793
Simon Glass0dc706f2020-07-09 18:39:31 -06003794 def testMkimage(self):
3795 """Test using mkimage to build an image"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06003796 self._SetupSplElf()
Simon Glass0dc706f2020-07-09 18:39:31 -06003797 data = self._DoReadFile('156_mkimage.dts')
3798
3799 # Just check that the data appears in the file somewhere
3800 self.assertIn(U_BOOT_SPL_DATA, data)
3801
Simon Glass4f9ee832022-01-09 20:14:09 -07003802 def testMkimageMissing(self):
3803 """Test that binman still produces an image if mkimage is missing"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06003804 self._SetupSplElf()
Simon Glass4f9ee832022-01-09 20:14:09 -07003805 with test_util.capture_sys_output() as (_, stderr):
3806 self._DoTestFile('156_mkimage.dts',
3807 force_missing_bintools='mkimage')
3808 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07003809 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass4f9ee832022-01-09 20:14:09 -07003810
Simon Glassce867ad2020-07-09 18:39:36 -06003811 def testExtblob(self):
3812 """Test an image with an external blob"""
3813 data = self._DoReadFile('157_blob_ext.dts')
3814 self.assertEqual(REFCODE_DATA, data)
3815
3816 def testExtblobMissing(self):
3817 """Test an image with a missing external blob"""
3818 with self.assertRaises(ValueError) as e:
3819 self._DoReadFile('158_blob_ext_missing.dts')
3820 self.assertIn("Filename 'missing-file' not found in input path",
3821 str(e.exception))
3822
Simon Glass4f9f1052020-07-09 18:39:38 -06003823 def testExtblobMissingOk(self):
3824 """Test an image with an missing external blob that is allowed"""
Simon Glassb1cca952020-07-09 18:39:40 -06003825 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glassb38da152022-11-09 19:14:42 -07003826 ret = self._DoTestFile('158_blob_ext_missing.dts',
3827 allow_missing=True)
3828 self.assertEqual(103, ret)
Simon Glassb1cca952020-07-09 18:39:40 -06003829 err = stderr.getvalue()
Jonas Karlman8f452bc2023-07-18 20:34:39 +00003830 self.assertIn('(missing-file)', err)
Simon Glass193d3db2023-02-07 14:34:18 -07003831 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glassb38da152022-11-09 19:14:42 -07003832 self.assertIn('Some images are invalid', err)
3833
3834 def testExtblobMissingOkFlag(self):
3835 """Test an image with an missing external blob allowed with -W"""
3836 with test_util.capture_sys_output() as (stdout, stderr):
3837 ret = self._DoTestFile('158_blob_ext_missing.dts',
3838 allow_missing=True, ignore_missing=True)
3839 self.assertEqual(0, ret)
3840 err = stderr.getvalue()
Jonas Karlman8f452bc2023-07-18 20:34:39 +00003841 self.assertIn('(missing-file)', err)
Simon Glass193d3db2023-02-07 14:34:18 -07003842 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glassb38da152022-11-09 19:14:42 -07003843 self.assertIn('Some images are invalid', err)
Simon Glassb1cca952020-07-09 18:39:40 -06003844
3845 def testExtblobMissingOkSect(self):
3846 """Test an image with an missing external blob that is allowed"""
3847 with test_util.capture_sys_output() as (stdout, stderr):
3848 self._DoTestFile('159_blob_ext_missing_sect.dts',
3849 allow_missing=True)
3850 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07003851 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext blob-ext2")
Simon Glass4f9f1052020-07-09 18:39:38 -06003852
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003853 def testPackX86RomMeMissingDesc(self):
3854 """Test that an missing Intel descriptor entry is allowed"""
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003855 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass52b10dd2020-07-25 15:11:19 -06003856 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003857 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07003858 self.assertRegex(err, "Image 'image'.*missing.*: intel-descriptor")
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003859
3860 def testPackX86RomMissingIfwi(self):
3861 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3862 self._SetupIfwi('fitimage.bin')
3863 pathname = os.path.join(self._indir, 'fitimage.bin')
3864 os.remove(pathname)
3865 with test_util.capture_sys_output() as (stdout, stderr):
3866 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3867 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07003868 self.assertRegex(err, "Image 'image'.*missing.*: intel-ifwi")
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003869
Simon Glass8d2ef3e2022-02-11 13:23:21 -07003870 def testPackOverlapZero(self):
Simon Glassb3295fd2020-07-09 18:39:42 -06003871 """Test that zero-size overlapping regions are ignored"""
3872 self._DoTestFile('160_pack_overlap_zero.dts')
3873
Alper Nebi Yasak21353312022-02-08 01:08:04 +03003874 def _CheckSimpleFitData(self, fit_data, kernel_data, fdt1_data):
Simon Glassfdc34362020-07-09 18:39:45 -06003875 # The data should be inside the FIT
3876 dtb = fdt.Fdt.FromData(fit_data)
3877 dtb.Scan()
3878 fnode = dtb.GetNode('/images/kernel')
3879 self.assertIn('data', fnode.props)
3880
3881 fname = os.path.join(self._indir, 'fit_data.fit')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003882 tools.write_file(fname, fit_data)
3883 out = tools.run('dumpimage', '-l', fname)
Simon Glassfdc34362020-07-09 18:39:45 -06003884
3885 # Check a few features to make sure the plumbing works. We don't need
3886 # to test the operation of mkimage or dumpimage here. First convert the
3887 # output into a dict where the keys are the fields printed by dumpimage
3888 # and the values are a list of values for each field
3889 lines = out.splitlines()
3890
3891 # Converts "Compression: gzip compressed" into two groups:
3892 # 'Compression' and 'gzip compressed'
3893 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3894 vals = collections.defaultdict(list)
3895 for line in lines:
3896 mat = re_line.match(line)
3897 vals[mat.group(1)].append(mat.group(2))
3898
Brandon Maier357bfca2024-06-04 16:16:05 +00003899 self.assertEqual('FIT description: test-desc', lines[0])
Simon Glassfdc34362020-07-09 18:39:45 -06003900 self.assertIn('Created:', lines[1])
3901 self.assertIn('Image 0 (kernel)', vals)
3902 self.assertIn('Hash value', vals)
3903 data_sizes = vals.get('Data Size')
3904 self.assertIsNotNone(data_sizes)
3905 self.assertEqual(2, len(data_sizes))
3906 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
Alper Nebi Yasak21353312022-02-08 01:08:04 +03003907 self.assertEqual(len(kernel_data), int(data_sizes[0].split()[0]))
3908 self.assertEqual(len(fdt1_data), int(data_sizes[1].split()[0]))
3909
Alper Nebi Yasake7368782022-03-27 18:31:47 +03003910 # Check if entry listing correctly omits /images/
3911 image = control.images['image']
3912 fit_entry = image.GetEntries()['fit']
3913 subentries = list(fit_entry.GetEntries().keys())
3914 expected = ['kernel', 'fdt-1']
3915 self.assertEqual(expected, subentries)
3916
Alper Nebi Yasak21353312022-02-08 01:08:04 +03003917 def testSimpleFit(self):
3918 """Test an image with a FIT inside"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06003919 self._SetupSplElf()
Alper Nebi Yasak21353312022-02-08 01:08:04 +03003920 data = self._DoReadFile('161_fit.dts')
3921 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3922 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3923 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3924
3925 self._CheckSimpleFitData(fit_data, U_BOOT_DATA, U_BOOT_SPL_DTB_DATA)
3926
3927 def testSimpleFitExpandsSubentries(self):
3928 """Test that FIT images expand their subentries"""
3929 data = self._DoReadFileDtb('161_fit.dts', use_expanded=True)[0]
3930 self.assertEqual(U_BOOT_EXP_DATA, data[:len(U_BOOT_EXP_DATA)])
3931 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3932 fit_data = data[len(U_BOOT_EXP_DATA):-len(U_BOOT_NODTB_DATA)]
3933
3934 self._CheckSimpleFitData(fit_data, U_BOOT_EXP_DATA, U_BOOT_SPL_DTB_DATA)
Simon Glassfdc34362020-07-09 18:39:45 -06003935
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003936 def testSimpleFitImagePos(self):
3937 """Test that we have correct image-pos for FIT subentries"""
3938 data, _, _, out_dtb_fname = self._DoReadFileDtb('161_fit.dts',
3939 update_dtb=True)
3940 dtb = fdt.Fdt(out_dtb_fname)
3941 dtb.Scan()
3942 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3943
Simon Glass38397d02022-03-05 20:19:01 -07003944 self.maxDiff = None
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003945 self.assertEqual({
3946 'image-pos': 0,
3947 'offset': 0,
3948 'size': 1890,
3949
3950 'u-boot:image-pos': 0,
3951 'u-boot:offset': 0,
3952 'u-boot:size': 4,
3953
3954 'fit:image-pos': 4,
3955 'fit:offset': 4,
3956 'fit:size': 1840,
3957
Simon Glass38397d02022-03-05 20:19:01 -07003958 'fit/images/kernel:image-pos': 304,
3959 'fit/images/kernel:offset': 300,
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003960 'fit/images/kernel:size': 4,
3961
Simon Glass38397d02022-03-05 20:19:01 -07003962 'fit/images/kernel/u-boot:image-pos': 304,
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003963 'fit/images/kernel/u-boot:offset': 0,
3964 'fit/images/kernel/u-boot:size': 4,
3965
Simon Glass38397d02022-03-05 20:19:01 -07003966 'fit/images/fdt-1:image-pos': 552,
3967 'fit/images/fdt-1:offset': 548,
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003968 'fit/images/fdt-1:size': 6,
3969
Simon Glass38397d02022-03-05 20:19:01 -07003970 'fit/images/fdt-1/u-boot-spl-dtb:image-pos': 552,
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003971 'fit/images/fdt-1/u-boot-spl-dtb:offset': 0,
3972 'fit/images/fdt-1/u-boot-spl-dtb:size': 6,
3973
3974 'u-boot-nodtb:image-pos': 1844,
3975 'u-boot-nodtb:offset': 1844,
3976 'u-boot-nodtb:size': 46,
3977 }, props)
3978
3979 # Actually check the data is where we think it is
3980 for node, expected in [
3981 ("u-boot", U_BOOT_DATA),
3982 ("fit/images/kernel", U_BOOT_DATA),
3983 ("fit/images/kernel/u-boot", U_BOOT_DATA),
3984 ("fit/images/fdt-1", U_BOOT_SPL_DTB_DATA),
3985 ("fit/images/fdt-1/u-boot-spl-dtb", U_BOOT_SPL_DTB_DATA),
3986 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
3987 ]:
3988 image_pos = props[f"{node}:image-pos"]
3989 size = props[f"{node}:size"]
3990 self.assertEqual(len(expected), size)
3991 self.assertEqual(expected, data[image_pos:image_pos+size])
3992
Simon Glassfdc34362020-07-09 18:39:45 -06003993 def testFitExternal(self):
Simon Glasse9d336d2020-09-01 05:13:55 -06003994 """Test an image with an FIT with external images"""
Simon Glassfdc34362020-07-09 18:39:45 -06003995 data = self._DoReadFile('162_fit_external.dts')
3996 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3997
Simon Glass8bc78b72022-01-09 20:13:39 -07003998 # Size of the external-data region as set up by mkimage
3999 external_data_size = len(U_BOOT_DATA) + 2
4000 expected_size = (len(U_BOOT_DATA) + 0x400 +
Simon Glassc1aa66e2022-01-29 14:14:04 -07004001 tools.align(external_data_size, 4) +
Simon Glass8bc78b72022-01-09 20:13:39 -07004002 len(U_BOOT_NODTB_DATA))
4003
Simon Glassfdc34362020-07-09 18:39:45 -06004004 # The data should be outside the FIT
4005 dtb = fdt.Fdt.FromData(fit_data)
4006 dtb.Scan()
4007 fnode = dtb.GetNode('/images/kernel')
4008 self.assertNotIn('data', fnode.props)
Simon Glass8bc78b72022-01-09 20:13:39 -07004009 self.assertEqual(len(U_BOOT_DATA),
4010 fdt_util.fdt32_to_cpu(fnode.props['data-size'].value))
4011 fit_pos = 0x400;
4012 self.assertEqual(
4013 fit_pos,
4014 fdt_util.fdt32_to_cpu(fnode.props['data-position'].value))
4015
Brandon Maier357bfca2024-06-04 16:16:05 +00004016 self.assertEqual(expected_size, len(data))
Simon Glass8bc78b72022-01-09 20:13:39 -07004017 actual_pos = len(U_BOOT_DATA) + fit_pos
4018 self.assertEqual(U_BOOT_DATA + b'aa',
4019 data[actual_pos:actual_pos + external_data_size])
Simon Glass12bb1a92019-07-20 12:23:51 -06004020
Alper Nebi Yasak73092222022-02-08 01:08:08 +03004021 def testFitExternalImagePos(self):
4022 """Test that we have correct image-pos for external FIT subentries"""
4023 data, _, _, out_dtb_fname = self._DoReadFileDtb('162_fit_external.dts',
4024 update_dtb=True)
4025 dtb = fdt.Fdt(out_dtb_fname)
4026 dtb.Scan()
4027 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4028
4029 self.assertEqual({
4030 'image-pos': 0,
4031 'offset': 0,
4032 'size': 1082,
4033
4034 'u-boot:image-pos': 0,
4035 'u-boot:offset': 0,
4036 'u-boot:size': 4,
4037
4038 'fit:size': 1032,
4039 'fit:offset': 4,
4040 'fit:image-pos': 4,
4041
4042 'fit/images/kernel:size': 4,
4043 'fit/images/kernel:offset': 1024,
4044 'fit/images/kernel:image-pos': 1028,
4045
4046 'fit/images/kernel/u-boot:size': 4,
4047 'fit/images/kernel/u-boot:offset': 0,
4048 'fit/images/kernel/u-boot:image-pos': 1028,
4049
4050 'fit/images/fdt-1:size': 2,
4051 'fit/images/fdt-1:offset': 1028,
4052 'fit/images/fdt-1:image-pos': 1032,
4053
4054 'fit/images/fdt-1/_testing:size': 2,
4055 'fit/images/fdt-1/_testing:offset': 0,
4056 'fit/images/fdt-1/_testing:image-pos': 1032,
4057
4058 'u-boot-nodtb:image-pos': 1036,
4059 'u-boot-nodtb:offset': 1036,
4060 'u-boot-nodtb:size': 46,
4061 }, props)
4062
4063 # Actually check the data is where we think it is
4064 for node, expected in [
4065 ("u-boot", U_BOOT_DATA),
4066 ("fit/images/kernel", U_BOOT_DATA),
4067 ("fit/images/kernel/u-boot", U_BOOT_DATA),
4068 ("fit/images/fdt-1", b'aa'),
4069 ("fit/images/fdt-1/_testing", b'aa'),
4070 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
4071 ]:
4072 image_pos = props[f"{node}:image-pos"]
4073 size = props[f"{node}:size"]
4074 self.assertEqual(len(expected), size)
4075 self.assertEqual(expected, data[image_pos:image_pos+size])
4076
Simon Glass4f9ee832022-01-09 20:14:09 -07004077 def testFitMissing(self):
Simon Glass033828c2023-03-02 17:02:43 -07004078 """Test that binman complains if mkimage is missing"""
4079 with self.assertRaises(ValueError) as e:
4080 self._DoTestFile('162_fit_external.dts',
4081 force_missing_bintools='mkimage')
4082 self.assertIn("Node '/binman/fit': Missing tool: 'mkimage'",
4083 str(e.exception))
4084
4085 def testFitMissingOK(self):
Simon Glass4f9ee832022-01-09 20:14:09 -07004086 """Test that binman still produces a FIT image if mkimage is missing"""
4087 with test_util.capture_sys_output() as (_, stderr):
Simon Glass033828c2023-03-02 17:02:43 -07004088 self._DoTestFile('162_fit_external.dts', allow_missing=True,
Simon Glass4f9ee832022-01-09 20:14:09 -07004089 force_missing_bintools='mkimage')
4090 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07004091 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass4f9ee832022-01-09 20:14:09 -07004092
Alper Nebi Yasak8001d0b2020-08-31 12:58:18 +03004093 def testSectionIgnoreHashSignature(self):
4094 """Test that sections ignore hash, signature nodes for its data"""
4095 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
4096 expected = (U_BOOT_DATA + U_BOOT_DATA)
4097 self.assertEqual(expected, data)
4098
Alper Nebi Yasak3fdeb142020-08-31 12:58:19 +03004099 def testPadInSections(self):
4100 """Test pad-before, pad-after for entries in sections"""
Simon Glassf90d9062020-10-26 17:40:09 -06004101 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4102 '166_pad_in_sections.dts', update_dtb=True)
Simon Glassc1aa66e2022-01-29 14:14:04 -07004103 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4104 U_BOOT_DATA + tools.get_bytes(ord('!'), 6) +
Alper Nebi Yasak3fdeb142020-08-31 12:58:19 +03004105 U_BOOT_DATA)
4106 self.assertEqual(expected, data)
4107
Simon Glassf90d9062020-10-26 17:40:09 -06004108 dtb = fdt.Fdt(out_dtb_fname)
4109 dtb.Scan()
4110 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
4111 expected = {
4112 'image-pos': 0,
4113 'offset': 0,
4114 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
4115
4116 'section:image-pos': 0,
4117 'section:offset': 0,
4118 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
4119
4120 'section/before:image-pos': 0,
4121 'section/before:offset': 0,
4122 'section/before:size': len(U_BOOT_DATA),
4123
4124 'section/u-boot:image-pos': 4,
4125 'section/u-boot:offset': 4,
4126 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
4127
4128 'section/after:image-pos': 26,
4129 'section/after:offset': 26,
4130 'section/after:size': len(U_BOOT_DATA),
4131 }
4132 self.assertEqual(expected, props)
4133
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03004134 def testFitImageSubentryAlignment(self):
4135 """Test relative alignability of FIT image subentries"""
Alper Nebi Yasakf3078d42022-02-08 01:08:07 +03004136 self._SetupSplElf()
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03004137 entry_args = {
4138 'test-id': TEXT_DATA,
4139 }
4140 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
4141 entry_args=entry_args)
4142 dtb = fdt.Fdt.FromData(data)
4143 dtb.Scan()
4144
4145 node = dtb.GetNode('/images/kernel')
4146 data = dtb.GetProps(node)["data"].bytes
4147 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
Simon Glassc1aa66e2022-01-29 14:14:04 -07004148 expected = (tools.get_bytes(0, 0x20) + U_BOOT_SPL_DATA +
4149 tools.get_bytes(0, align_pad) + U_BOOT_DATA)
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03004150 self.assertEqual(expected, data)
4151
4152 node = dtb.GetNode('/images/fdt-1')
4153 data = dtb.GetProps(node)["data"].bytes
Simon Glassc1aa66e2022-01-29 14:14:04 -07004154 expected = (U_BOOT_SPL_DTB_DATA + tools.get_bytes(0, 20) +
4155 tools.to_bytes(TEXT_DATA) + tools.get_bytes(0, 30) +
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03004156 U_BOOT_DTB_DATA)
4157 self.assertEqual(expected, data)
4158
4159 def testFitExtblobMissingOk(self):
4160 """Test a FIT with a missing external blob that is allowed"""
4161 with test_util.capture_sys_output() as (stdout, stderr):
4162 self._DoTestFile('168_fit_missing_blob.dts',
4163 allow_missing=True)
4164 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07004165 self.assertRegex(err, "Image 'image'.*missing.*: atf-bl31")
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03004166
Simon Glass3decfa32020-09-01 05:13:54 -06004167 def testBlobNamedByArgMissing(self):
4168 """Test handling of a missing entry arg"""
4169 with self.assertRaises(ValueError) as e:
4170 self._DoReadFile('068_blob_named_by_arg.dts')
4171 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
4172 str(e.exception))
4173
Simon Glassdc2f81a2020-09-01 05:13:58 -06004174 def testPackBl31(self):
4175 """Test that an image with an ATF BL31 binary can be created"""
4176 data = self._DoReadFile('169_atf_bl31.dts')
4177 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
4178
Samuel Holland18bd4552020-10-21 21:12:15 -05004179 def testPackScp(self):
4180 """Test that an image with an SCP binary can be created"""
4181 data = self._DoReadFile('172_scp.dts')
4182 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
4183
Simon Glass9db7a3a2024-07-20 11:49:46 +01004184 def CheckFitFdt(self, dts='170_fit_fdt.dts', use_fdt_list=True):
4185 """Check an image with an FIT with multiple FDT images"""
Simon Glass6cf99532020-09-01 05:13:59 -06004186 def _CheckFdt(seq, expected_data):
4187 """Check the FDT nodes
4188
4189 Args:
4190 seq: Sequence number to check (0 or 1)
4191 expected_data: Expected contents of 'data' property
4192 """
4193 name = 'fdt-%d' % seq
4194 fnode = dtb.GetNode('/images/%s' % name)
4195 self.assertIsNotNone(fnode)
4196 self.assertEqual({'description','type', 'compression', 'data'},
4197 set(fnode.props.keys()))
4198 self.assertEqual(expected_data, fnode.props['data'].bytes)
4199 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
4200 fnode.props['description'].value)
Jan Kiszkab2106612022-02-28 17:06:20 +01004201 self.assertEqual(fnode.subnodes[0].name, 'hash')
Simon Glass6cf99532020-09-01 05:13:59 -06004202
4203 def _CheckConfig(seq, expected_data):
4204 """Check the configuration nodes
4205
4206 Args:
4207 seq: Sequence number to check (0 or 1)
4208 expected_data: Expected contents of 'data' property
4209 """
4210 cnode = dtb.GetNode('/configurations')
4211 self.assertIn('default', cnode.props)
Simon Glassc0f1ebe2020-09-06 10:39:08 -06004212 self.assertEqual('config-2', cnode.props['default'].value)
Simon Glass6cf99532020-09-01 05:13:59 -06004213
4214 name = 'config-%d' % seq
4215 fnode = dtb.GetNode('/configurations/%s' % name)
4216 self.assertIsNotNone(fnode)
4217 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
4218 set(fnode.props.keys()))
4219 self.assertEqual('conf-test-fdt%d.dtb' % seq,
4220 fnode.props['description'].value)
4221 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
4222
4223 entry_args = {
Simon Glassc0f1ebe2020-09-06 10:39:08 -06004224 'default-dt': 'test-fdt2',
Simon Glass6cf99532020-09-01 05:13:59 -06004225 }
Simon Glass9db7a3a2024-07-20 11:49:46 +01004226 if use_fdt_list:
4227 entry_args['of-list'] = 'test-fdt1 test-fdt2'
Simon Glass6cf99532020-09-01 05:13:59 -06004228 data = self._DoReadFileDtb(
Simon Glass9db7a3a2024-07-20 11:49:46 +01004229 dts,
Simon Glass6cf99532020-09-01 05:13:59 -06004230 entry_args=entry_args,
4231 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4232 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4233 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4234
4235 dtb = fdt.Fdt.FromData(fit_data)
4236 dtb.Scan()
4237 fnode = dtb.GetNode('/images/kernel')
4238 self.assertIn('data', fnode.props)
4239
4240 # Check all the properties in fdt-1 and fdt-2
4241 _CheckFdt(1, TEST_FDT1_DATA)
4242 _CheckFdt(2, TEST_FDT2_DATA)
4243
4244 # Check configurations
4245 _CheckConfig(1, TEST_FDT1_DATA)
4246 _CheckConfig(2, TEST_FDT2_DATA)
4247
Simon Glass9db7a3a2024-07-20 11:49:46 +01004248 def testFitFdt(self):
4249 """Test an image with an FIT with multiple FDT images"""
4250 self.CheckFitFdt()
4251
Simon Glass6cf99532020-09-01 05:13:59 -06004252 def testFitFdtMissingList(self):
4253 """Test handling of a missing 'of-list' entry arg"""
4254 with self.assertRaises(ValueError) as e:
Bin Mengaa75ce92021-05-10 20:23:32 +08004255 self._DoReadFile('170_fit_fdt.dts')
Simon Glass6cf99532020-09-01 05:13:59 -06004256 self.assertIn("Generator node requires 'of-list' entry argument",
4257 str(e.exception))
4258
4259 def testFitFdtEmptyList(self):
4260 """Test handling of an empty 'of-list' entry arg"""
4261 entry_args = {
4262 'of-list': '',
4263 }
4264 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
4265
4266 def testFitFdtMissingProp(self):
4267 """Test handling of a missing 'fit,fdt-list' property"""
4268 with self.assertRaises(ValueError) as e:
4269 self._DoReadFile('171_fit_fdt_missing_prop.dts')
4270 self.assertIn("Generator node requires 'fit,fdt-list' property",
4271 str(e.exception))
Simon Glassdc2f81a2020-09-01 05:13:58 -06004272
Simon Glassc0f1ebe2020-09-06 10:39:08 -06004273 def testFitFdtMissing(self):
4274 """Test handling of a missing 'default-dt' entry arg"""
4275 entry_args = {
4276 'of-list': 'test-fdt1 test-fdt2',
4277 }
4278 with self.assertRaises(ValueError) as e:
4279 self._DoReadFileDtb(
Bin Mengaa75ce92021-05-10 20:23:32 +08004280 '170_fit_fdt.dts',
Simon Glassc0f1ebe2020-09-06 10:39:08 -06004281 entry_args=entry_args,
4282 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4283 self.assertIn("Generated 'default' node requires default-dt entry argument",
4284 str(e.exception))
4285
4286 def testFitFdtNotInList(self):
4287 """Test handling of a default-dt that is not in the of-list"""
4288 entry_args = {
4289 'of-list': 'test-fdt1 test-fdt2',
4290 'default-dt': 'test-fdt3',
4291 }
4292 with self.assertRaises(ValueError) as e:
4293 self._DoReadFileDtb(
Bin Mengaa75ce92021-05-10 20:23:32 +08004294 '170_fit_fdt.dts',
Simon Glassc0f1ebe2020-09-06 10:39:08 -06004295 entry_args=entry_args,
4296 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4297 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
4298 str(e.exception))
4299
Simon Glassb2381432020-09-06 10:39:09 -06004300 def testFitExtblobMissingHelp(self):
4301 """Test display of help messages when an external blob is missing"""
4302 control.missing_blob_help = control._ReadMissingBlobHelp()
4303 control.missing_blob_help['wibble'] = 'Wibble test'
4304 control.missing_blob_help['another'] = 'Another test'
4305 with test_util.capture_sys_output() as (stdout, stderr):
4306 self._DoTestFile('168_fit_missing_blob.dts',
4307 allow_missing=True)
4308 err = stderr.getvalue()
4309
4310 # We can get the tag from the name, the type or the missing-msg
4311 # property. Check all three.
4312 self.assertIn('You may need to build ARM Trusted', err)
4313 self.assertIn('Wibble test', err)
4314 self.assertIn('Another test', err)
4315
Simon Glass204aa782020-09-06 10:35:32 -06004316 def testMissingBlob(self):
4317 """Test handling of a blob containing a missing file"""
4318 with self.assertRaises(ValueError) as e:
4319 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
4320 self.assertIn("Filename 'missing' not found in input path",
4321 str(e.exception))
4322
Simon Glassfb91d562020-09-06 10:35:33 -06004323 def testEnvironment(self):
4324 """Test adding a U-Boot environment"""
4325 data = self._DoReadFile('174_env.dts')
4326 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
4327 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4328 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4329 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
4330 env)
4331
4332 def testEnvironmentNoSize(self):
4333 """Test that a missing 'size' property is detected"""
4334 with self.assertRaises(ValueError) as e:
Simon Glassa4dfe3e2020-10-26 17:40:00 -06004335 self._DoTestFile('175_env_no_size.dts')
Simon Glassfb91d562020-09-06 10:35:33 -06004336 self.assertIn("'u-boot-env' entry must have a size property",
4337 str(e.exception))
4338
4339 def testEnvironmentTooSmall(self):
4340 """Test handling of an environment that does not fit"""
4341 with self.assertRaises(ValueError) as e:
Simon Glassa4dfe3e2020-10-26 17:40:00 -06004342 self._DoTestFile('176_env_too_small.dts')
Simon Glassfb91d562020-09-06 10:35:33 -06004343
4344 # checksum, start byte, environment with \0 terminator, final \0
4345 need = 4 + 1 + len(ENV_DATA) + 1 + 1
4346 short = need - 0x8
4347 self.assertIn("too small to hold data (need %#x more bytes)" % short,
4348 str(e.exception))
4349
Simon Glassf2c0dd82020-10-26 17:40:01 -06004350 def testSkipAtStart(self):
4351 """Test handling of skip-at-start section"""
4352 data = self._DoReadFile('177_skip_at_start.dts')
4353 self.assertEqual(U_BOOT_DATA, data)
4354
4355 image = control.images['image']
4356 entries = image.GetEntries()
4357 section = entries['section']
4358 self.assertEqual(0, section.offset)
4359 self.assertEqual(len(U_BOOT_DATA), section.size)
4360 self.assertEqual(U_BOOT_DATA, section.GetData())
4361
4362 entry = section.GetEntries()['u-boot']
4363 self.assertEqual(16, entry.offset)
4364 self.assertEqual(len(U_BOOT_DATA), entry.size)
4365 self.assertEqual(U_BOOT_DATA, entry.data)
4366
4367 def testSkipAtStartPad(self):
4368 """Test handling of skip-at-start section with padded entry"""
4369 data = self._DoReadFile('178_skip_at_start_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004370 before = tools.get_bytes(0, 8)
4371 after = tools.get_bytes(0, 4)
Simon Glassf2c0dd82020-10-26 17:40:01 -06004372 all = before + U_BOOT_DATA + after
4373 self.assertEqual(all, data)
4374
4375 image = control.images['image']
4376 entries = image.GetEntries()
4377 section = entries['section']
4378 self.assertEqual(0, section.offset)
4379 self.assertEqual(len(all), section.size)
4380 self.assertEqual(all, section.GetData())
4381
4382 entry = section.GetEntries()['u-boot']
4383 self.assertEqual(16, entry.offset)
4384 self.assertEqual(len(all), entry.size)
4385 self.assertEqual(U_BOOT_DATA, entry.data)
4386
4387 def testSkipAtStartSectionPad(self):
4388 """Test handling of skip-at-start section with padding"""
4389 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004390 before = tools.get_bytes(0, 8)
4391 after = tools.get_bytes(0, 4)
Simon Glassf2c0dd82020-10-26 17:40:01 -06004392 all = before + U_BOOT_DATA + after
Simon Glassd1d3ad72020-10-26 17:40:13 -06004393 self.assertEqual(all, data)
Simon Glassf2c0dd82020-10-26 17:40:01 -06004394
4395 image = control.images['image']
4396 entries = image.GetEntries()
4397 section = entries['section']
4398 self.assertEqual(0, section.offset)
4399 self.assertEqual(len(all), section.size)
Simon Glass63e7ba62020-10-26 17:40:16 -06004400 self.assertEqual(U_BOOT_DATA, section.data)
Simon Glassd1d3ad72020-10-26 17:40:13 -06004401 self.assertEqual(all, section.GetPaddedData())
Simon Glassf2c0dd82020-10-26 17:40:01 -06004402
4403 entry = section.GetEntries()['u-boot']
4404 self.assertEqual(16, entry.offset)
4405 self.assertEqual(len(U_BOOT_DATA), entry.size)
4406 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassfb91d562020-09-06 10:35:33 -06004407
Simon Glass7d398bb2020-10-26 17:40:14 -06004408 def testSectionPad(self):
4409 """Testing padding with sections"""
4410 data = self._DoReadFile('180_section_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004411 expected = (tools.get_bytes(ord('&'), 3) +
4412 tools.get_bytes(ord('!'), 5) +
Simon Glass7d398bb2020-10-26 17:40:14 -06004413 U_BOOT_DATA +
Simon Glassc1aa66e2022-01-29 14:14:04 -07004414 tools.get_bytes(ord('!'), 1) +
4415 tools.get_bytes(ord('&'), 2))
Simon Glass7d398bb2020-10-26 17:40:14 -06004416 self.assertEqual(expected, data)
4417
4418 def testSectionAlign(self):
4419 """Testing alignment with sections"""
4420 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4421 expected = (b'\0' + # fill section
Simon Glassc1aa66e2022-01-29 14:14:04 -07004422 tools.get_bytes(ord('&'), 1) + # padding to section align
Simon Glass7d398bb2020-10-26 17:40:14 -06004423 b'\0' + # fill section
Simon Glassc1aa66e2022-01-29 14:14:04 -07004424 tools.get_bytes(ord('!'), 3) + # padding to u-boot align
Simon Glass7d398bb2020-10-26 17:40:14 -06004425 U_BOOT_DATA +
Simon Glassc1aa66e2022-01-29 14:14:04 -07004426 tools.get_bytes(ord('!'), 4) + # padding to u-boot size
4427 tools.get_bytes(ord('!'), 4)) # padding to section size
Simon Glass7d398bb2020-10-26 17:40:14 -06004428 self.assertEqual(expected, data)
4429
Simon Glass8f5ef892020-10-26 17:40:25 -06004430 def testCompressImage(self):
4431 """Test compression of the entire image"""
4432 self._CheckLz4()
4433 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4434 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4435 dtb = fdt.Fdt(out_dtb_fname)
4436 dtb.Scan()
4437 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4438 'uncomp-size'])
4439 orig = self._decompress(data)
Brandon Maier357bfca2024-06-04 16:16:05 +00004440 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glass8f5ef892020-10-26 17:40:25 -06004441
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, entry.data)
4449 self.assertEqual(len(COMPRESS_DATA), 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 + U_BOOT_DATA, image.uncomp_data)
4457 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4458 orig = self._decompress(image.data)
4459 self.assertEqual(orig, image.uncomp_data)
4460
4461 expected = {
4462 'blob:offset': 0,
4463 'blob:size': len(COMPRESS_DATA),
4464 'u-boot:offset': len(COMPRESS_DATA),
4465 'u-boot:size': len(U_BOOT_DATA),
4466 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4467 'offset': 0,
4468 'image-pos': 0,
4469 'size': len(data),
4470 }
4471 self.assertEqual(expected, props)
4472
4473 def testCompressImageLess(self):
4474 """Test compression where compression reduces the image size"""
4475 self._CheckLz4()
4476 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4477 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4478 dtb = fdt.Fdt(out_dtb_fname)
4479 dtb.Scan()
4480 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4481 'uncomp-size'])
4482 orig = self._decompress(data)
4483
Brandon Maier357bfca2024-06-04 16:16:05 +00004484 self.assertEqual(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glass8f5ef892020-10-26 17:40:25 -06004485
4486 # Do a sanity check on various fields
4487 image = control.images['image']
4488 entries = image.GetEntries()
4489 self.assertEqual(2, len(entries))
4490
4491 entry = entries['blob']
4492 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4493 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4494
4495 entry = entries['u-boot']
4496 self.assertEqual(U_BOOT_DATA, entry.data)
4497 self.assertEqual(len(U_BOOT_DATA), entry.size)
4498
4499 self.assertEqual(len(data), image.size)
4500 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4501 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4502 image.uncomp_size)
4503 orig = self._decompress(image.data)
4504 self.assertEqual(orig, image.uncomp_data)
4505
4506 expected = {
4507 'blob:offset': 0,
4508 'blob:size': len(COMPRESS_DATA_BIG),
4509 'u-boot:offset': len(COMPRESS_DATA_BIG),
4510 'u-boot:size': len(U_BOOT_DATA),
4511 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4512 'offset': 0,
4513 'image-pos': 0,
4514 'size': len(data),
4515 }
4516 self.assertEqual(expected, props)
4517
4518 def testCompressSectionSize(self):
4519 """Test compression of a section with a fixed size"""
4520 self._CheckLz4()
4521 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4522 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4523 dtb = fdt.Fdt(out_dtb_fname)
4524 dtb.Scan()
4525 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4526 'uncomp-size'])
4527 orig = self._decompress(data)
Brandon Maier357bfca2024-06-04 16:16:05 +00004528 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glass8f5ef892020-10-26 17:40:25 -06004529 expected = {
4530 'section/blob:offset': 0,
4531 'section/blob:size': len(COMPRESS_DATA),
4532 'section/u-boot:offset': len(COMPRESS_DATA),
4533 'section/u-boot:size': len(U_BOOT_DATA),
4534 'section:offset': 0,
4535 'section:image-pos': 0,
4536 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4537 'section:size': 0x30,
4538 'offset': 0,
4539 'image-pos': 0,
4540 'size': 0x30,
4541 }
4542 self.assertEqual(expected, props)
4543
4544 def testCompressSection(self):
4545 """Test compression of a section with no fixed size"""
4546 self._CheckLz4()
4547 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4548 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4549 dtb = fdt.Fdt(out_dtb_fname)
4550 dtb.Scan()
4551 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4552 'uncomp-size'])
4553 orig = self._decompress(data)
Brandon Maier357bfca2024-06-04 16:16:05 +00004554 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glass8f5ef892020-10-26 17:40:25 -06004555 expected = {
4556 'section/blob:offset': 0,
4557 'section/blob:size': len(COMPRESS_DATA),
4558 'section/u-boot:offset': len(COMPRESS_DATA),
4559 'section/u-boot:size': len(U_BOOT_DATA),
4560 'section:offset': 0,
4561 'section:image-pos': 0,
4562 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4563 'section:size': len(data),
4564 'offset': 0,
4565 'image-pos': 0,
4566 'size': len(data),
4567 }
4568 self.assertEqual(expected, props)
4569
Stefan Herbrechtsmeierc3665a82022-08-19 16:25:31 +02004570 def testLz4Missing(self):
4571 """Test that binman still produces an image if lz4 is missing"""
4572 with test_util.capture_sys_output() as (_, stderr):
4573 self._DoTestFile('185_compress_section.dts',
4574 force_missing_bintools='lz4')
4575 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07004576 self.assertRegex(err, "Image 'image'.*missing bintools.*: lz4")
Stefan Herbrechtsmeierc3665a82022-08-19 16:25:31 +02004577
Simon Glass8f5ef892020-10-26 17:40:25 -06004578 def testCompressExtra(self):
4579 """Test compression of a section with no fixed size"""
4580 self._CheckLz4()
4581 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4582 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4583 dtb = fdt.Fdt(out_dtb_fname)
4584 dtb.Scan()
4585 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4586 'uncomp-size'])
4587
4588 base = data[len(U_BOOT_DATA):]
Brandon Maier357bfca2024-06-04 16:16:05 +00004589 self.assertEqual(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
Simon Glass8f5ef892020-10-26 17:40:25 -06004590 rest = base[len(U_BOOT_DATA):]
4591
4592 # Check compressed data
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +02004593 bintool = self.comp_bintools['lz4']
4594 expect1 = bintool.compress(COMPRESS_DATA + U_BOOT_DATA)
Stefan Herbrechtsmeierfa24f552022-08-19 16:25:23 +02004595 data1 = rest[:len(expect1)]
4596 section1 = self._decompress(data1)
Brandon Maier357bfca2024-06-04 16:16:05 +00004597 self.assertEqual(expect1, data1)
4598 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, section1)
Simon Glass8f5ef892020-10-26 17:40:25 -06004599 rest1 = rest[len(expect1):]
4600
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +02004601 expect2 = bintool.compress(COMPRESS_DATA + COMPRESS_DATA)
Stefan Herbrechtsmeierfa24f552022-08-19 16:25:23 +02004602 data2 = rest1[:len(expect2)]
4603 section2 = self._decompress(data2)
Brandon Maier357bfca2024-06-04 16:16:05 +00004604 self.assertEqual(expect2, data2)
4605 self.assertEqual(COMPRESS_DATA + COMPRESS_DATA, section2)
Simon Glass8f5ef892020-10-26 17:40:25 -06004606 rest2 = rest1[len(expect2):]
4607
4608 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4609 len(expect2) + len(U_BOOT_DATA))
Brandon Maier357bfca2024-06-04 16:16:05 +00004610 #self.assertEqual(expect_size, len(data))
Simon Glass8f5ef892020-10-26 17:40:25 -06004611
Brandon Maier357bfca2024-06-04 16:16:05 +00004612 #self.assertEqual(U_BOOT_DATA, rest2)
Simon Glass8f5ef892020-10-26 17:40:25 -06004613
4614 self.maxDiff = None
4615 expected = {
4616 'u-boot:offset': 0,
4617 'u-boot:image-pos': 0,
4618 'u-boot:size': len(U_BOOT_DATA),
4619
4620 'base:offset': len(U_BOOT_DATA),
4621 'base:image-pos': len(U_BOOT_DATA),
4622 'base:size': len(data) - len(U_BOOT_DATA),
4623 'base/u-boot:offset': 0,
4624 'base/u-boot:image-pos': len(U_BOOT_DATA),
4625 'base/u-boot:size': len(U_BOOT_DATA),
4626 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4627 len(expect2),
4628 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4629 len(expect2),
4630 'base/u-boot2:size': len(U_BOOT_DATA),
4631
4632 'base/section:offset': len(U_BOOT_DATA),
4633 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4634 'base/section:size': len(expect1),
4635 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4636 'base/section/blob:offset': 0,
4637 'base/section/blob:size': len(COMPRESS_DATA),
4638 'base/section/u-boot:offset': len(COMPRESS_DATA),
4639 'base/section/u-boot:size': len(U_BOOT_DATA),
4640
4641 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4642 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4643 'base/section2:size': len(expect2),
4644 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4645 'base/section2/blob:offset': 0,
4646 'base/section2/blob:size': len(COMPRESS_DATA),
4647 'base/section2/blob2:offset': len(COMPRESS_DATA),
4648 'base/section2/blob2:size': len(COMPRESS_DATA),
4649
4650 'offset': 0,
4651 'image-pos': 0,
4652 'size': len(data),
4653 }
4654 self.assertEqual(expected, props)
4655
Simon Glass870a9ea2021-01-06 21:35:15 -07004656 def testSymbolsSubsection(self):
4657 """Test binman can assign symbols from a subsection"""
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03004658 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glass870a9ea2021-01-06 21:35:15 -07004659
Simon Glass939d1062021-01-06 21:35:16 -07004660 def testReadImageEntryArg(self):
4661 """Test reading an image that would need an entry arg to generate"""
4662 entry_args = {
4663 'cros-ec-rw-path': 'ecrw.bin',
4664 }
4665 data = self.data = self._DoReadFileDtb(
4666 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4667 entry_args=entry_args)
4668
Simon Glassc1aa66e2022-01-29 14:14:04 -07004669 image_fname = tools.get_output_filename('image.bin')
Simon Glass939d1062021-01-06 21:35:16 -07004670 orig_image = control.images['image']
4671
4672 # This should not generate an error about the missing 'cros-ec-rw-path'
4673 # since we are reading the image from a file. Compare with
4674 # testEntryArgsRequired()
4675 image = Image.FromFile(image_fname)
4676 self.assertEqual(orig_image.GetEntries().keys(),
4677 image.GetEntries().keys())
4678
Simon Glass6eb99322021-01-06 21:35:18 -07004679 def testFilesAlign(self):
4680 """Test alignment with files"""
4681 data = self._DoReadFile('190_files_align.dts')
4682
4683 # The first string is 15 bytes so will align to 16
4684 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4685 self.assertEqual(expect, data)
4686
Simon Glass5c6ba712021-01-06 21:35:19 -07004687 def testReadImageSkip(self):
4688 """Test reading an image and accessing its FDT map"""
4689 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004690 image_fname = tools.get_output_filename('image.bin')
Simon Glass5c6ba712021-01-06 21:35:19 -07004691 orig_image = control.images['image']
4692 image = Image.FromFile(image_fname)
4693 self.assertEqual(orig_image.GetEntries().keys(),
4694 image.GetEntries().keys())
4695
4696 orig_entry = orig_image.GetEntries()['fdtmap']
4697 entry = image.GetEntries()['fdtmap']
4698 self.assertEqual(orig_entry.offset, entry.offset)
4699 self.assertEqual(orig_entry.size, entry.size)
4700 self.assertEqual(16, entry.image_pos)
4701
4702 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4703
Brandon Maier357bfca2024-06-04 16:16:05 +00004704 self.assertEqual(U_BOOT_DATA, u_boot.ReadData())
Simon Glass5c6ba712021-01-06 21:35:19 -07004705
Simon Glass77a64e02021-03-18 20:24:57 +13004706 def testTplNoDtb(self):
4707 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
Simon Glass0fe44dc2021-04-25 08:39:32 +12004708 self._SetupTplElf()
Simon Glass77a64e02021-03-18 20:24:57 +13004709 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4710 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4711 data[:len(U_BOOT_TPL_NODTB_DATA)])
4712
Simon Glassd26efc82021-03-18 20:24:58 +13004713 def testTplBssPad(self):
4714 """Test that we can pad TPL's BSS with zeros"""
4715 # ELF file with a '__bss_size' symbol
4716 self._SetupTplElf()
4717 data = self._DoReadFile('193_tpl_bss_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004718 self.assertEqual(U_BOOT_TPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glassd26efc82021-03-18 20:24:58 +13004719 data)
4720
4721 def testTplBssPadMissing(self):
4722 """Test that a missing symbol is detected"""
4723 self._SetupTplElf('u_boot_ucode_ptr')
4724 with self.assertRaises(ValueError) as e:
4725 self._DoReadFile('193_tpl_bss_pad.dts')
4726 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4727 str(e.exception))
4728
Simon Glass06684922021-03-18 20:25:07 +13004729 def checkDtbSizes(self, data, pad_len, start):
4730 """Check the size arguments in a dtb embedded in an image
4731
4732 Args:
4733 data: The image data
4734 pad_len: Length of the pad section in the image, in bytes
4735 start: Start offset of the devicetree to examine, within the image
4736
4737 Returns:
4738 Size of the devicetree in bytes
4739 """
4740 dtb_data = data[start:]
4741 dtb = fdt.Fdt.FromData(dtb_data)
4742 fdt_size = dtb.GetFdtObj().totalsize()
4743 dtb.Scan()
4744 props = self._GetPropTree(dtb, 'size')
4745 self.assertEqual({
4746 'size': len(data),
4747 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4748 'u-boot-spl/u-boot-spl-dtb:size': 801,
4749 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4750 'u-boot-spl:size': 860,
4751 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4752 'u-boot/u-boot-dtb:size': 781,
4753 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4754 'u-boot:size': 827,
4755 }, props)
4756 return fdt_size
4757
4758 def testExpanded(self):
4759 """Test that an expanded entry type is selected when needed"""
4760 self._SetupSplElf()
4761 self._SetupTplElf()
4762
4763 # SPL has a devicetree, TPL does not
4764 entry_args = {
4765 'spl-dtb': '1',
4766 'spl-bss-pad': 'y',
4767 'tpl-dtb': '',
4768 }
4769 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4770 entry_args=entry_args)
4771 image = control.images['image']
4772 entries = image.GetEntries()
4773 self.assertEqual(3, len(entries))
4774
4775 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4776 self.assertIn('u-boot', entries)
4777 entry = entries['u-boot']
4778 self.assertEqual('u-boot-expanded', entry.etype)
4779 subent = entry.GetEntries()
4780 self.assertEqual(2, len(subent))
4781 self.assertIn('u-boot-nodtb', subent)
4782 self.assertIn('u-boot-dtb', subent)
4783
4784 # Second, u-boot-spl, which should be expanded into three parts
4785 self.assertIn('u-boot-spl', entries)
4786 entry = entries['u-boot-spl']
4787 self.assertEqual('u-boot-spl-expanded', entry.etype)
4788 subent = entry.GetEntries()
4789 self.assertEqual(3, len(subent))
4790 self.assertIn('u-boot-spl-nodtb', subent)
4791 self.assertIn('u-boot-spl-bss-pad', subent)
4792 self.assertIn('u-boot-spl-dtb', subent)
4793
4794 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4795 # devicetree
4796 self.assertIn('u-boot-tpl', entries)
4797 entry = entries['u-boot-tpl']
4798 self.assertEqual('u-boot-tpl', entry.etype)
4799 self.assertEqual(None, entry.GetEntries())
4800
4801 def testExpandedTpl(self):
4802 """Test that an expanded entry type is selected for TPL when needed"""
4803 self._SetupTplElf()
4804
4805 entry_args = {
4806 'tpl-bss-pad': 'y',
4807 'tpl-dtb': 'y',
4808 }
4809 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4810 entry_args=entry_args)
4811 image = control.images['image']
4812 entries = image.GetEntries()
4813 self.assertEqual(1, len(entries))
4814
4815 # We only have u-boot-tpl, which be expanded
4816 self.assertIn('u-boot-tpl', entries)
4817 entry = entries['u-boot-tpl']
4818 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4819 subent = entry.GetEntries()
4820 self.assertEqual(3, len(subent))
4821 self.assertIn('u-boot-tpl-nodtb', subent)
4822 self.assertIn('u-boot-tpl-bss-pad', subent)
4823 self.assertIn('u-boot-tpl-dtb', subent)
4824
4825 def testExpandedNoPad(self):
4826 """Test an expanded entry without BSS pad enabled"""
4827 self._SetupSplElf()
4828 self._SetupTplElf()
4829
4830 # SPL has a devicetree, TPL does not
4831 entry_args = {
4832 'spl-dtb': 'something',
4833 'spl-bss-pad': 'n',
4834 'tpl-dtb': '',
4835 }
4836 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4837 entry_args=entry_args)
4838 image = control.images['image']
4839 entries = image.GetEntries()
4840
4841 # Just check u-boot-spl, which should be expanded into two parts
4842 self.assertIn('u-boot-spl', entries)
4843 entry = entries['u-boot-spl']
4844 self.assertEqual('u-boot-spl-expanded', entry.etype)
4845 subent = entry.GetEntries()
4846 self.assertEqual(2, len(subent))
4847 self.assertIn('u-boot-spl-nodtb', subent)
4848 self.assertIn('u-boot-spl-dtb', subent)
4849
4850 def testExpandedTplNoPad(self):
4851 """Test that an expanded entry type with padding disabled in TPL"""
4852 self._SetupTplElf()
4853
4854 entry_args = {
4855 'tpl-bss-pad': '',
4856 'tpl-dtb': 'y',
4857 }
4858 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4859 entry_args=entry_args)
4860 image = control.images['image']
4861 entries = image.GetEntries()
4862 self.assertEqual(1, len(entries))
4863
4864 # We only have u-boot-tpl, which be expanded
4865 self.assertIn('u-boot-tpl', entries)
4866 entry = entries['u-boot-tpl']
4867 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4868 subent = entry.GetEntries()
4869 self.assertEqual(2, len(subent))
4870 self.assertIn('u-boot-tpl-nodtb', subent)
4871 self.assertIn('u-boot-tpl-dtb', subent)
4872
4873 def testFdtInclude(self):
4874 """Test that an Fdt is update within all binaries"""
4875 self._SetupSplElf()
4876 self._SetupTplElf()
4877
4878 # SPL has a devicetree, TPL does not
4879 self.maxDiff = None
4880 entry_args = {
4881 'spl-dtb': '1',
4882 'spl-bss-pad': 'y',
4883 'tpl-dtb': '',
4884 }
4885 # Build the image. It includes two separate devicetree binaries, each
4886 # with their own contents, but all contain the binman definition.
4887 data = self._DoReadFileDtb(
4888 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4889 update_dtb=True, entry_args=entry_args)[0]
4890 pad_len = 10
4891
4892 # Check the U-Boot dtb
4893 start = len(U_BOOT_NODTB_DATA)
4894 fdt_size = self.checkDtbSizes(data, pad_len, start)
4895
4896 # Now check SPL
4897 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4898 fdt_size = self.checkDtbSizes(data, pad_len, start)
4899
4900 # TPL has no devicetree
4901 start += fdt_size + len(U_BOOT_TPL_DATA)
4902 self.assertEqual(len(data), start)
Simon Glass7d398bb2020-10-26 17:40:14 -06004903
Simon Glass3d433382021-03-21 18:24:30 +13004904 def testSymbolsExpanded(self):
4905 """Test binman can assign symbols in expanded entries"""
4906 entry_args = {
4907 'spl-dtb': '1',
4908 }
4909 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4910 U_BOOT_SPL_DTB_DATA, 0x38,
4911 entry_args=entry_args, use_expanded=True)
4912
Simon Glass189f2912021-03-21 18:24:31 +13004913 def testCollection(self):
4914 """Test a collection"""
4915 data = self._DoReadFile('198_collection.dts')
4916 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
Simon Glassc1aa66e2022-01-29 14:14:04 -07004917 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
4918 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
Simon Glass189f2912021-03-21 18:24:31 +13004919 data)
4920
Simon Glass631f7522021-03-21 18:24:32 +13004921 def testCollectionSection(self):
4922 """Test a collection where a section must be built first"""
4923 # Sections never have their contents when GetData() is called, but when
Simon Glassd34bcdd2021-11-23 11:03:47 -07004924 # BuildSectionData() is called with required=True, a section will force
Simon Glass631f7522021-03-21 18:24:32 +13004925 # building the contents, producing an error is anything is still
4926 # missing.
4927 data = self._DoReadFile('199_collection_section.dts')
4928 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
Simon Glassc1aa66e2022-01-29 14:14:04 -07004929 self.assertEqual(section + U_BOOT_DATA + tools.get_bytes(0xff, 2) +
4930 section + tools.get_bytes(0xfe, 3) + U_BOOT_DATA,
Simon Glass631f7522021-03-21 18:24:32 +13004931 data)
4932
Simon Glass5ff9fed2021-03-21 18:24:33 +13004933 def testAlignDefault(self):
4934 """Test that default alignment works on sections"""
4935 data = self._DoReadFile('200_align_default.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004936 expected = (U_BOOT_DATA + tools.get_bytes(0, 8 - len(U_BOOT_DATA)) +
Simon Glass5ff9fed2021-03-21 18:24:33 +13004937 U_BOOT_DATA)
4938 # Special alignment for section
Simon Glassc1aa66e2022-01-29 14:14:04 -07004939 expected += tools.get_bytes(0, 32 - len(expected))
Simon Glass5ff9fed2021-03-21 18:24:33 +13004940 # No alignment within the nested section
4941 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
4942 # Now the final piece, which should be default-aligned
Simon Glassc1aa66e2022-01-29 14:14:04 -07004943 expected += tools.get_bytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
Simon Glass5ff9fed2021-03-21 18:24:33 +13004944 self.assertEqual(expected, data)
Simon Glass631f7522021-03-21 18:24:32 +13004945
Bin Meng4c4d6072021-05-10 20:23:33 +08004946 def testPackOpenSBI(self):
4947 """Test that an image with an OpenSBI binary can be created"""
4948 data = self._DoReadFile('201_opensbi.dts')
4949 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
4950
Simon Glassc69d19c2021-07-06 10:36:37 -06004951 def testSectionsSingleThread(self):
4952 """Test sections without multithreading"""
4953 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
Simon Glassc1aa66e2022-01-29 14:14:04 -07004954 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4955 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
4956 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glassc69d19c2021-07-06 10:36:37 -06004957 self.assertEqual(expected, data)
4958
4959 def testThreadTimeout(self):
4960 """Test handling a thread that takes too long"""
4961 with self.assertRaises(ValueError) as e:
4962 self._DoTestFile('202_section_timeout.dts',
4963 test_section_timeout=True)
Simon Glassb2dfe832021-10-18 12:13:15 -06004964 self.assertIn("Timed out obtaining contents", str(e.exception))
Simon Glassc69d19c2021-07-06 10:36:37 -06004965
Simon Glass03ebc202021-07-06 10:36:41 -06004966 def testTiming(self):
4967 """Test output of timing information"""
4968 data = self._DoReadFile('055_sections.dts')
4969 with test_util.capture_sys_output() as (stdout, stderr):
4970 state.TimingShow()
4971 self.assertIn('read:', stdout.getvalue())
4972 self.assertIn('compress:', stdout.getvalue())
4973
Simon Glass0427bed2021-11-03 21:09:18 -06004974 def testUpdateFdtInElf(self):
4975 """Test that we can update the devicetree in an ELF file"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02004976 if not elf.ELF_TOOLS:
4977 self.skipTest('Python elftools not available')
Simon Glass0427bed2021-11-03 21:09:18 -06004978 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4979 outfile = os.path.join(self._indir, 'u-boot.out')
4980 begin_sym = 'dtb_embed_begin'
4981 end_sym = 'dtb_embed_end'
4982 retcode = self._DoTestFile(
4983 '060_fdt_update.dts', update_dtb=True,
4984 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4985 self.assertEqual(0, retcode)
4986
4987 # Check that the output file does in fact contact a dtb with the binman
4988 # definition in the correct place
4989 syms = elf.GetSymbolFileOffset(infile,
4990 ['dtb_embed_begin', 'dtb_embed_end'])
Simon Glassc1aa66e2022-01-29 14:14:04 -07004991 data = tools.read_file(outfile)
Simon Glass0427bed2021-11-03 21:09:18 -06004992 dtb_data = data[syms['dtb_embed_begin'].offset:
4993 syms['dtb_embed_end'].offset]
4994
4995 dtb = fdt.Fdt.FromData(dtb_data)
4996 dtb.Scan()
4997 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4998 self.assertEqual({
4999 'image-pos': 0,
5000 'offset': 0,
5001 '_testing:offset': 32,
5002 '_testing:size': 2,
5003 '_testing:image-pos': 32,
5004 'section@0/u-boot:offset': 0,
5005 'section@0/u-boot:size': len(U_BOOT_DATA),
5006 'section@0/u-boot:image-pos': 0,
5007 'section@0:offset': 0,
5008 'section@0:size': 16,
5009 'section@0:image-pos': 0,
5010
5011 'section@1/u-boot:offset': 0,
5012 'section@1/u-boot:size': len(U_BOOT_DATA),
5013 'section@1/u-boot:image-pos': 16,
5014 'section@1:offset': 16,
5015 'section@1:size': 16,
5016 'section@1:image-pos': 16,
5017 'size': 40
5018 }, props)
5019
5020 def testUpdateFdtInElfInvalid(self):
5021 """Test that invalid args are detected with --update-fdt-in-elf"""
5022 with self.assertRaises(ValueError) as e:
5023 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
5024 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
5025 str(e.exception))
5026
5027 def testUpdateFdtInElfNoSyms(self):
5028 """Test that missing symbols are detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02005029 if not elf.ELF_TOOLS:
5030 self.skipTest('Python elftools not available')
Simon Glass0427bed2021-11-03 21:09:18 -06005031 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
5032 outfile = ''
5033 begin_sym = 'wrong_begin'
5034 end_sym = 'wrong_end'
5035 with self.assertRaises(ValueError) as e:
5036 self._DoTestFile(
5037 '060_fdt_update.dts',
5038 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5039 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
5040 str(e.exception))
5041
5042 def testUpdateFdtInElfTooSmall(self):
5043 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02005044 if not elf.ELF_TOOLS:
5045 self.skipTest('Python elftools not available')
Simon Glass0427bed2021-11-03 21:09:18 -06005046 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
5047 outfile = os.path.join(self._indir, 'u-boot.out')
5048 begin_sym = 'dtb_embed_begin'
5049 end_sym = 'dtb_embed_end'
5050 with self.assertRaises(ValueError) as e:
5051 self._DoTestFile(
5052 '060_fdt_update.dts', update_dtb=True,
5053 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5054 self.assertRegex(
5055 str(e.exception),
5056 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
5057
Simon Glassc475dec2021-11-23 11:03:42 -07005058 def testVersion(self):
5059 """Test we can get the binman version"""
5060 version = '(unreleased)'
5061 self.assertEqual(version, state.GetVersion(self._indir))
5062
5063 with self.assertRaises(SystemExit):
5064 with test_util.capture_sys_output() as (_, stderr):
5065 self._DoBinman('-V')
5066 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
5067
5068 # Try running the tool too, just to be safe
5069 result = self._RunBinman('-V')
5070 self.assertEqual('Binman %s\n' % version, result.stderr)
5071
5072 # Set up a version file to make sure that works
5073 version = 'v2025.01-rc2'
Simon Glassc1aa66e2022-01-29 14:14:04 -07005074 tools.write_file(os.path.join(self._indir, 'version'), version,
Simon Glassc475dec2021-11-23 11:03:42 -07005075 binary=False)
5076 self.assertEqual(version, state.GetVersion(self._indir))
5077
Simon Glass943bf782021-11-23 21:09:50 -07005078 def testAltFormat(self):
5079 """Test that alternative formats can be used to extract"""
5080 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
5081
5082 try:
5083 tmpdir, updated_fname = self._SetupImageInTmpdir()
5084 with test_util.capture_sys_output() as (stdout, _):
5085 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
5086 self.assertEqual(
5087 '''Flag (-F) Entry type Description
5088fdt fdtmap Extract the devicetree blob from the fdtmap
5089''',
5090 stdout.getvalue())
5091
5092 dtb = os.path.join(tmpdir, 'fdt.dtb')
5093 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
5094 dtb, 'fdtmap')
5095
5096 # Check that we can read it and it can be scanning, meaning it does
5097 # not have a 16-byte fdtmap header
Simon Glassc1aa66e2022-01-29 14:14:04 -07005098 data = tools.read_file(dtb)
Simon Glass943bf782021-11-23 21:09:50 -07005099 dtb = fdt.Fdt.FromData(data)
5100 dtb.Scan()
5101
5102 # Now check u-boot which has no alt_format
5103 fname = os.path.join(tmpdir, 'fdt.dtb')
5104 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
5105 '-f', fname, 'u-boot')
Simon Glassc1aa66e2022-01-29 14:14:04 -07005106 data = tools.read_file(fname)
Simon Glass943bf782021-11-23 21:09:50 -07005107 self.assertEqual(U_BOOT_DATA, data)
5108
5109 finally:
5110 shutil.rmtree(tmpdir)
5111
Simon Glasscc2c5002021-11-23 21:09:52 -07005112 def testExtblobList(self):
5113 """Test an image with an external blob list"""
5114 data = self._DoReadFile('215_blob_ext_list.dts')
5115 self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
5116
5117 def testExtblobListMissing(self):
5118 """Test an image with a missing external blob"""
5119 with self.assertRaises(ValueError) as e:
5120 self._DoReadFile('216_blob_ext_list_missing.dts')
5121 self.assertIn("Filename 'missing-file' not found in input path",
5122 str(e.exception))
5123
5124 def testExtblobListMissingOk(self):
5125 """Test an image with an missing external blob that is allowed"""
5126 with test_util.capture_sys_output() as (stdout, stderr):
5127 self._DoTestFile('216_blob_ext_list_missing.dts',
5128 allow_missing=True)
5129 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07005130 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glasscc2c5002021-11-23 21:09:52 -07005131
Simon Glass75989722021-11-23 21:08:59 -07005132 def testFip(self):
5133 """Basic test of generation of an ARM Firmware Image Package (FIP)"""
5134 data = self._DoReadFile('203_fip.dts')
5135 hdr, fents = fip_util.decode_fip(data)
5136 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5137 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5138 self.assertEqual(0x123, hdr.flags)
5139
5140 self.assertEqual(2, len(fents))
5141
5142 fent = fents[0]
5143 self.assertEqual(
5144 bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
5145 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
5146 self.assertEqual('soc-fw', fent.fip_type)
5147 self.assertEqual(0x88, fent.offset)
5148 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5149 self.assertEqual(0x123456789abcdef, fent.flags)
5150 self.assertEqual(ATF_BL31_DATA, fent.data)
5151 self.assertEqual(True, fent.valid)
5152
5153 fent = fents[1]
5154 self.assertEqual(
5155 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
5156 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
5157 self.assertEqual('scp-fwu-cfg', fent.fip_type)
5158 self.assertEqual(0x8c, fent.offset)
5159 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5160 self.assertEqual(0, fent.flags)
5161 self.assertEqual(ATF_BL2U_DATA, fent.data)
5162 self.assertEqual(True, fent.valid)
5163
5164 def testFipOther(self):
5165 """Basic FIP with something that isn't a external blob"""
5166 data = self._DoReadFile('204_fip_other.dts')
5167 hdr, fents = fip_util.decode_fip(data)
5168
5169 self.assertEqual(2, len(fents))
5170 fent = fents[1]
5171 self.assertEqual('rot-cert', fent.fip_type)
5172 self.assertEqual(b'aa', fent.data)
5173
Simon Glass75989722021-11-23 21:08:59 -07005174 def testFipNoType(self):
5175 """FIP with an entry of an unknown type"""
5176 with self.assertRaises(ValueError) as e:
5177 self._DoReadFile('205_fip_no_type.dts')
5178 self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
5179 str(e.exception))
5180
5181 def testFipUuid(self):
5182 """Basic FIP with a manual uuid"""
5183 data = self._DoReadFile('206_fip_uuid.dts')
5184 hdr, fents = fip_util.decode_fip(data)
5185
5186 self.assertEqual(2, len(fents))
5187 fent = fents[1]
5188 self.assertEqual(None, fent.fip_type)
5189 self.assertEqual(
5190 bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
5191 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
5192 fent.uuid)
5193 self.assertEqual(U_BOOT_DATA, fent.data)
5194
5195 def testFipLs(self):
5196 """Test listing a FIP"""
5197 data = self._DoReadFileRealDtb('207_fip_ls.dts')
5198 hdr, fents = fip_util.decode_fip(data)
5199
Heinrich Schuchardt69c37052023-12-16 00:26:04 +01005200 tmpdir = None
Simon Glass75989722021-11-23 21:08:59 -07005201 try:
5202 tmpdir, updated_fname = self._SetupImageInTmpdir()
5203 with test_util.capture_sys_output() as (stdout, stderr):
5204 self._DoBinman('ls', '-i', updated_fname)
5205 finally:
Heinrich Schuchardt69c37052023-12-16 00:26:04 +01005206 if tmpdir:
5207 shutil.rmtree(tmpdir)
Simon Glass75989722021-11-23 21:08:59 -07005208 lines = stdout.getvalue().splitlines()
5209 expected = [
Simon Glass193d3db2023-02-07 14:34:18 -07005210'Name Image-pos Size Entry-type Offset Uncomp-size',
5211'--------------------------------------------------------------',
5212'image 0 2d3 section 0',
5213' atf-fip 0 90 atf-fip 0',
5214' soc-fw 88 4 blob-ext 88',
5215' u-boot 8c 4 u-boot 8c',
5216' fdtmap 90 243 fdtmap 90',
Simon Glass75989722021-11-23 21:08:59 -07005217]
5218 self.assertEqual(expected, lines)
5219
5220 image = control.images['image']
5221 entries = image.GetEntries()
5222 fdtmap = entries['fdtmap']
5223
5224 fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
5225 magic = fdtmap_data[:8]
5226 self.assertEqual(b'_FDTMAP_', magic)
Simon Glassc1aa66e2022-01-29 14:14:04 -07005227 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass75989722021-11-23 21:08:59 -07005228
5229 fdt_data = fdtmap_data[16:]
5230 dtb = fdt.Fdt.FromData(fdt_data)
5231 dtb.Scan()
5232 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
5233 self.assertEqual({
5234 'atf-fip/soc-fw:image-pos': 136,
5235 'atf-fip/soc-fw:offset': 136,
5236 'atf-fip/soc-fw:size': 4,
5237 'atf-fip/u-boot:image-pos': 140,
5238 'atf-fip/u-boot:offset': 140,
5239 'atf-fip/u-boot:size': 4,
5240 'atf-fip:image-pos': 0,
5241 'atf-fip:offset': 0,
5242 'atf-fip:size': 144,
5243 'image-pos': 0,
5244 'offset': 0,
5245 'fdtmap:image-pos': fdtmap.image_pos,
5246 'fdtmap:offset': fdtmap.offset,
5247 'fdtmap:size': len(fdtmap_data),
5248 'size': len(data),
5249 }, props)
5250
5251 def testFipExtractOneEntry(self):
5252 """Test extracting a single entry fron an FIP"""
5253 self._DoReadFileRealDtb('207_fip_ls.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07005254 image_fname = tools.get_output_filename('image.bin')
Simon Glass75989722021-11-23 21:08:59 -07005255 fname = os.path.join(self._indir, 'output.extact')
5256 control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
Simon Glassc1aa66e2022-01-29 14:14:04 -07005257 data = tools.read_file(fname)
Simon Glass75989722021-11-23 21:08:59 -07005258 self.assertEqual(U_BOOT_DATA, data)
5259
5260 def testFipReplace(self):
5261 """Test replacing a single file in a FIP"""
Simon Glassc1aa66e2022-01-29 14:14:04 -07005262 expected = U_BOOT_DATA + tools.get_bytes(0x78, 50)
Simon Glass75989722021-11-23 21:08:59 -07005263 data = self._DoReadFileRealDtb('208_fip_replace.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07005264 updated_fname = tools.get_output_filename('image-updated.bin')
5265 tools.write_file(updated_fname, data)
Simon Glass75989722021-11-23 21:08:59 -07005266 entry_name = 'atf-fip/u-boot'
5267 control.WriteEntry(updated_fname, entry_name, expected,
5268 allow_resize=True)
5269 actual = control.ReadEntry(updated_fname, entry_name)
5270 self.assertEqual(expected, actual)
5271
Simon Glassc1aa66e2022-01-29 14:14:04 -07005272 new_data = tools.read_file(updated_fname)
Simon Glass75989722021-11-23 21:08:59 -07005273 hdr, fents = fip_util.decode_fip(new_data)
5274
5275 self.assertEqual(2, len(fents))
5276
5277 # Check that the FIP entry is updated
5278 fent = fents[1]
5279 self.assertEqual(0x8c, fent.offset)
5280 self.assertEqual(len(expected), fent.size)
5281 self.assertEqual(0, fent.flags)
5282 self.assertEqual(expected, fent.data)
5283 self.assertEqual(True, fent.valid)
5284
5285 def testFipMissing(self):
5286 with test_util.capture_sys_output() as (stdout, stderr):
5287 self._DoTestFile('209_fip_missing.dts', allow_missing=True)
5288 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07005289 self.assertRegex(err, "Image 'image'.*missing.*: rmm-fw")
Simon Glass75989722021-11-23 21:08:59 -07005290
5291 def testFipSize(self):
5292 """Test a FIP with a size property"""
5293 data = self._DoReadFile('210_fip_size.dts')
5294 self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
5295 hdr, fents = fip_util.decode_fip(data)
5296 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5297 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5298
5299 self.assertEqual(1, len(fents))
5300
5301 fent = fents[0]
5302 self.assertEqual('soc-fw', fent.fip_type)
5303 self.assertEqual(0x60, fent.offset)
5304 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5305 self.assertEqual(ATF_BL31_DATA, fent.data)
5306 self.assertEqual(True, fent.valid)
5307
5308 rest = data[0x60 + len(ATF_BL31_DATA):0x100]
Simon Glassc1aa66e2022-01-29 14:14:04 -07005309 self.assertEqual(tools.get_bytes(0xff, len(rest)), rest)
Simon Glass75989722021-11-23 21:08:59 -07005310
5311 def testFipBadAlign(self):
5312 """Test that an invalid alignment value in a FIP is detected"""
5313 with self.assertRaises(ValueError) as e:
5314 self._DoTestFile('211_fip_bad_align.dts')
5315 self.assertIn(
5316 "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
5317 str(e.exception))
5318
5319 def testFipCollection(self):
5320 """Test using a FIP in a collection"""
5321 data = self._DoReadFile('212_fip_collection.dts')
5322 entry1 = control.images['image'].GetEntries()['collection']
5323 data1 = data[:entry1.size]
5324 hdr1, fents2 = fip_util.decode_fip(data1)
5325
5326 entry2 = control.images['image'].GetEntries()['atf-fip']
5327 data2 = data[entry2.offset:entry2.offset + entry2.size]
5328 hdr1, fents2 = fip_util.decode_fip(data2)
5329
5330 # The 'collection' entry should have U-Boot included at the end
5331 self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
5332 self.assertEqual(data1, data2 + U_BOOT_DATA)
5333 self.assertEqual(U_BOOT_DATA, data1[-4:])
5334
5335 # There should be a U-Boot after the final FIP
5336 self.assertEqual(U_BOOT_DATA, data[-4:])
Simon Glassc69d19c2021-07-06 10:36:37 -06005337
Simon Glass32d4f102022-01-12 13:10:35 -07005338 def testFakeBlob(self):
5339 """Test handling of faking an external blob"""
5340 with test_util.capture_sys_output() as (stdout, stderr):
5341 self._DoTestFile('217_fake_blob.dts', allow_missing=True,
5342 allow_fake_blobs=True)
5343 err = stderr.getvalue()
5344 self.assertRegex(
5345 err,
5346 "Image '.*' has faked external blobs and is non-functional: .*")
Simon Glass32d4f102022-01-12 13:10:35 -07005347
Simon Glassf4590e02022-01-09 20:13:46 -07005348 def testExtblobListFaked(self):
5349 """Test an extblob with missing external blob that are faked"""
5350 with test_util.capture_sys_output() as (stdout, stderr):
5351 self._DoTestFile('216_blob_ext_list_missing.dts',
5352 allow_fake_blobs=True)
5353 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07005354 self.assertRegex(err, "Image 'image'.*faked.*: blob-ext-list")
Simon Glassf4590e02022-01-09 20:13:46 -07005355
Simon Glass56ee85e2022-01-09 20:13:57 -07005356 def testListBintools(self):
5357 args = ['tool', '--list']
5358 with test_util.capture_sys_output() as (stdout, _):
5359 self._DoBinman(*args)
5360 out = stdout.getvalue().splitlines()
5361 self.assertTrue(len(out) >= 2)
5362
5363 def testFetchBintools(self):
5364 def fail_download(url):
Simon Glassc1aa66e2022-01-29 14:14:04 -07005365 """Take the tools.download() function by raising an exception"""
Simon Glass56ee85e2022-01-09 20:13:57 -07005366 raise urllib.error.URLError('my error')
5367
5368 args = ['tool']
5369 with self.assertRaises(ValueError) as e:
5370 self._DoBinman(*args)
5371 self.assertIn("Invalid arguments to 'tool' subcommand",
5372 str(e.exception))
5373
5374 args = ['tool', '--fetch']
5375 with self.assertRaises(ValueError) as e:
5376 self._DoBinman(*args)
5377 self.assertIn('Please specify bintools to fetch', str(e.exception))
5378
5379 args = ['tool', '--fetch', '_testing']
Simon Glassc1aa66e2022-01-29 14:14:04 -07005380 with unittest.mock.patch.object(tools, 'download',
Simon Glass56ee85e2022-01-09 20:13:57 -07005381 side_effect=fail_download):
5382 with test_util.capture_sys_output() as (stdout, _):
5383 self._DoBinman(*args)
5384 self.assertIn('failed to fetch with all methods', stdout.getvalue())
5385
Simon Glassbc570642022-01-09 20:14:11 -07005386 def testBintoolDocs(self):
5387 """Test for creation of bintool documentation"""
5388 with test_util.capture_sys_output() as (stdout, stderr):
5389 control.write_bintool_docs(control.bintool.Bintool.get_tool_list())
5390 self.assertTrue(len(stdout.getvalue()) > 0)
5391
5392 def testBintoolDocsMissing(self):
5393 """Test handling of missing bintool documentation"""
5394 with self.assertRaises(ValueError) as e:
5395 with test_util.capture_sys_output() as (stdout, stderr):
5396 control.write_bintool_docs(
5397 control.bintool.Bintool.get_tool_list(), 'mkimage')
5398 self.assertIn('Documentation is missing for modules: mkimage',
5399 str(e.exception))
5400
Jan Kiszkafcc87ef2022-01-28 20:37:53 +01005401 def testListWithGenNode(self):
5402 """Check handling of an FDT map when the section cannot be found"""
5403 entry_args = {
5404 'of-list': 'test-fdt1 test-fdt2',
5405 }
5406 data = self._DoReadFileDtb(
5407 '219_fit_gennode.dts',
5408 entry_args=entry_args,
5409 use_real_dtb=True,
5410 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])
5411
Heinrich Schuchardt69c37052023-12-16 00:26:04 +01005412 tmpdir = None
Jan Kiszkafcc87ef2022-01-28 20:37:53 +01005413 try:
5414 tmpdir, updated_fname = self._SetupImageInTmpdir()
5415 with test_util.capture_sys_output() as (stdout, stderr):
5416 self._RunBinman('ls', '-i', updated_fname)
5417 finally:
Heinrich Schuchardt69c37052023-12-16 00:26:04 +01005418 if tmpdir:
5419 shutil.rmtree(tmpdir)
Jan Kiszkafcc87ef2022-01-28 20:37:53 +01005420
Alper Nebi Yasaked293c32022-02-08 01:08:05 +03005421 def testFitSubentryUsesBintool(self):
5422 """Test that binman FIT subentries can use bintools"""
5423 command.test_result = self._HandleGbbCommand
5424 entry_args = {
5425 'keydir': 'devkeys',
5426 'bmpblk': 'bmpblk.bin',
5427 }
5428 data, _, _, _ = self._DoReadFileDtb('220_fit_subentry_bintool.dts',
5429 entry_args=entry_args)
5430
Alper Nebi Yasakf3078d42022-02-08 01:08:07 +03005431 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
5432 tools.get_bytes(0, 0x2180 - 16))
Alper Nebi Yasaked293c32022-02-08 01:08:05 +03005433 self.assertIn(expected, data)
5434
5435 def testFitSubentryMissingBintool(self):
5436 """Test that binman reports missing bintools for FIT subentries"""
5437 entry_args = {
5438 'keydir': 'devkeys',
5439 }
5440 with test_util.capture_sys_output() as (_, stderr):
5441 self._DoTestFile('220_fit_subentry_bintool.dts',
5442 force_missing_bintools='futility', entry_args=entry_args)
5443 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07005444 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass32d4f102022-01-12 13:10:35 -07005445
Alper Nebi Yasakee813c82022-02-09 22:02:35 +03005446 def testFitSubentryHashSubnode(self):
5447 """Test an image with a FIT inside"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06005448 self._SetupSplElf()
Alper Nebi Yasakee813c82022-02-09 22:02:35 +03005449 data, _, _, out_dtb_name = self._DoReadFileDtb(
5450 '221_fit_subentry_hash.dts', use_real_dtb=True, update_dtb=True)
5451
5452 mkimage_dtb = fdt.Fdt.FromData(data)
5453 mkimage_dtb.Scan()
5454 binman_dtb = fdt.Fdt(out_dtb_name)
5455 binman_dtb.Scan()
5456
5457 # Check that binman didn't add hash values
5458 fnode = binman_dtb.GetNode('/binman/fit/images/kernel/hash')
5459 self.assertNotIn('value', fnode.props)
5460
5461 fnode = binman_dtb.GetNode('/binman/fit/images/fdt-1/hash')
5462 self.assertNotIn('value', fnode.props)
5463
5464 # Check that mkimage added hash values
5465 fnode = mkimage_dtb.GetNode('/images/kernel/hash')
5466 self.assertIn('value', fnode.props)
5467
5468 fnode = mkimage_dtb.GetNode('/images/fdt-1/hash')
5469 self.assertIn('value', fnode.props)
5470
Roger Quadros47f420a2022-02-19 20:50:04 +02005471 def testPackTeeOs(self):
5472 """Test that an image with an TEE binary can be created"""
5473 data = self._DoReadFile('222_tee_os.dts')
5474 self.assertEqual(TEE_OS_DATA, data[:len(TEE_OS_DATA)])
5475
Neha Malcom Francis23d2ef92023-12-05 15:12:18 +05305476 def testPackTiDm(self):
5477 """Test that an image with a TI DM binary can be created"""
5478 data = self._DoReadFile('225_ti_dm.dts')
5479 self.assertEqual(TI_DM_DATA, data[:len(TI_DM_DATA)])
5480
Simon Glass6a0b5f82022-02-08 11:50:03 -07005481 def testFitFdtOper(self):
5482 """Check handling of a specified FIT operation"""
5483 entry_args = {
5484 'of-list': 'test-fdt1 test-fdt2',
5485 'default-dt': 'test-fdt2',
5486 }
5487 self._DoReadFileDtb(
5488 '223_fit_fdt_oper.dts',
5489 entry_args=entry_args,
5490 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
5491
5492 def testFitFdtBadOper(self):
5493 """Check handling of an FDT map when the section cannot be found"""
5494 with self.assertRaises(ValueError) as exc:
5495 self._DoReadFileDtb('224_fit_bad_oper.dts')
Simon Glassce4e4022022-03-05 20:19:09 -07005496 self.assertIn("Node '/binman/fit': subnode 'images/@fdt-SEQ': Unknown operation 'unknown'",
Simon Glass6a0b5f82022-02-08 11:50:03 -07005497 str(exc.exception))
5498
Simon Glass80a66ae2022-03-05 20:18:59 -07005499 def test_uses_expand_size(self):
5500 """Test that the 'expand-size' property cannot be used anymore"""
5501 with self.assertRaises(ValueError) as e:
5502 data = self._DoReadFile('225_expand_size_bad.dts')
5503 self.assertIn(
5504 "Node '/binman/u-boot': Please use 'extend-size' instead of 'expand-size'",
5505 str(e.exception))
5506
Simon Glass40c8bdd2022-03-05 20:19:12 -07005507 def testFitSplitElf(self):
5508 """Test an image with an FIT with an split-elf operation"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02005509 if not elf.ELF_TOOLS:
5510 self.skipTest('Python elftools not available')
Simon Glass40c8bdd2022-03-05 20:19:12 -07005511 entry_args = {
5512 'of-list': 'test-fdt1 test-fdt2',
5513 'default-dt': 'test-fdt2',
5514 'atf-bl31-path': 'bl31.elf',
5515 'tee-os-path': 'tee.elf',
5516 }
5517 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5518 data = self._DoReadFileDtb(
5519 '226_fit_split_elf.dts',
5520 entry_args=entry_args,
5521 extra_indirs=[test_subdir])[0]
5522
5523 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
5524 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
5525
5526 base_keys = {'description', 'type', 'arch', 'os', 'compression',
5527 'data', 'load'}
5528 dtb = fdt.Fdt.FromData(fit_data)
5529 dtb.Scan()
5530
5531 elf_data = tools.read_file(os.path.join(self._indir, 'bl31.elf'))
5532 segments, entry = elf.read_loadable_segments(elf_data)
5533
5534 # We assume there are two segments
Brandon Maier357bfca2024-06-04 16:16:05 +00005535 self.assertEqual(2, len(segments))
Simon Glass40c8bdd2022-03-05 20:19:12 -07005536
5537 atf1 = dtb.GetNode('/images/atf-1')
5538 _, start, data = segments[0]
5539 self.assertEqual(base_keys | {'entry'}, atf1.props.keys())
5540 self.assertEqual(entry,
5541 fdt_util.fdt32_to_cpu(atf1.props['entry'].value))
5542 self.assertEqual(start,
5543 fdt_util.fdt32_to_cpu(atf1.props['load'].value))
5544 self.assertEqual(data, atf1.props['data'].bytes)
5545
Jonas Karlman00b3d532023-01-21 19:01:48 +00005546 hash_node = atf1.FindNode('hash')
5547 self.assertIsNotNone(hash_node)
5548 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5549
Simon Glass40c8bdd2022-03-05 20:19:12 -07005550 atf2 = dtb.GetNode('/images/atf-2')
5551 self.assertEqual(base_keys, atf2.props.keys())
5552 _, start, data = segments[1]
5553 self.assertEqual(start,
5554 fdt_util.fdt32_to_cpu(atf2.props['load'].value))
5555 self.assertEqual(data, atf2.props['data'].bytes)
5556
Jonas Karlman00b3d532023-01-21 19:01:48 +00005557 hash_node = atf2.FindNode('hash')
5558 self.assertIsNotNone(hash_node)
5559 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5560
5561 hash_node = dtb.GetNode('/images/tee-1/hash-1')
5562 self.assertIsNotNone(hash_node)
5563 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5564
Simon Glass40c8bdd2022-03-05 20:19:12 -07005565 conf = dtb.GetNode('/configurations')
5566 self.assertEqual({'default'}, conf.props.keys())
5567
5568 for subnode in conf.subnodes:
5569 self.assertEqual({'description', 'fdt', 'loadables'},
5570 subnode.props.keys())
5571 self.assertEqual(
5572 ['atf-1', 'atf-2', 'tee-1', 'tee-2'],
5573 fdt_util.GetStringList(subnode, 'loadables'))
5574
5575 def _check_bad_fit(self, dts):
5576 """Check a bad FIT
5577
5578 This runs with the given dts and returns the assertion raised
5579
5580 Args:
5581 dts (str): dts filename to use
5582
5583 Returns:
5584 str: Assertion string raised
5585 """
5586 entry_args = {
5587 'of-list': 'test-fdt1 test-fdt2',
5588 'default-dt': 'test-fdt2',
5589 'atf-bl31-path': 'bl31.elf',
5590 'tee-os-path': 'tee.elf',
5591 }
5592 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5593 with self.assertRaises(ValueError) as exc:
5594 self._DoReadFileDtb(dts, entry_args=entry_args,
5595 extra_indirs=[test_subdir])[0]
5596 return str(exc.exception)
5597
5598 def testFitSplitElfBadElf(self):
5599 """Test a FIT split-elf operation with an invalid ELF file"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02005600 if not elf.ELF_TOOLS:
5601 self.skipTest('Python elftools not available')
Simon Glass40c8bdd2022-03-05 20:19:12 -07005602 TestFunctional._MakeInputFile('bad.elf', tools.get_bytes(100, 100))
5603 entry_args = {
5604 'of-list': 'test-fdt1 test-fdt2',
5605 'default-dt': 'test-fdt2',
5606 'atf-bl31-path': 'bad.elf',
5607 'tee-os-path': 'tee.elf',
5608 }
5609 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5610 with self.assertRaises(ValueError) as exc:
5611 self._DoReadFileDtb(
5612 '226_fit_split_elf.dts',
5613 entry_args=entry_args,
5614 extra_indirs=[test_subdir])[0]
5615 self.assertIn(
5616 "Node '/binman/fit': subnode 'images/@atf-SEQ': Failed to read ELF file: Magic number does not match",
5617 str(exc.exception))
5618
Simon Glass40c8bdd2022-03-05 20:19:12 -07005619 def checkFitSplitElf(self, **kwargs):
Simon Glass7960a0a2022-08-07 09:46:46 -06005620 """Test an split-elf FIT with a missing ELF file
5621
5622 Args:
5623 kwargs (dict of str): Arguments to pass to _DoTestFile()
5624
5625 Returns:
5626 tuple:
5627 str: stdout result
5628 str: stderr result
5629 """
Simon Glass40c8bdd2022-03-05 20:19:12 -07005630 entry_args = {
5631 'of-list': 'test-fdt1 test-fdt2',
5632 'default-dt': 'test-fdt2',
5633 'atf-bl31-path': 'bl31.elf',
5634 'tee-os-path': 'missing.elf',
5635 }
5636 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5637 with test_util.capture_sys_output() as (stdout, stderr):
5638 self._DoTestFile(
5639 '226_fit_split_elf.dts', entry_args=entry_args,
Simon Glass7960a0a2022-08-07 09:46:46 -06005640 extra_indirs=[test_subdir], verbosity=3, **kwargs)
5641 out = stdout.getvalue()
5642 err = stderr.getvalue()
5643 return out, err
Simon Glass40c8bdd2022-03-05 20:19:12 -07005644
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005645 def testFitSplitElfBadDirective(self):
5646 """Test a FIT split-elf invalid fit,xxx directive in an image node"""
5647 if not elf.ELF_TOOLS:
5648 self.skipTest('Python elftools not available')
5649 err = self._check_bad_fit('227_fit_bad_dir.dts')
5650 self.assertIn(
5651 "Node '/binman/fit': subnode 'images/@atf-SEQ': Unknown directive 'fit,something'",
5652 err)
5653
5654 def testFitSplitElfBadDirectiveConfig(self):
5655 """Test a FIT split-elf with invalid fit,xxx directive in config"""
5656 if not elf.ELF_TOOLS:
5657 self.skipTest('Python elftools not available')
5658 err = self._check_bad_fit('228_fit_bad_dir_config.dts')
5659 self.assertEqual(
5660 "Node '/binman/fit': subnode 'configurations/@config-SEQ': Unknown directive 'fit,config'",
5661 err)
5662
5663
Simon Glass40c8bdd2022-03-05 20:19:12 -07005664 def testFitSplitElfMissing(self):
5665 """Test an split-elf FIT with a missing ELF file"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02005666 if not elf.ELF_TOOLS:
5667 self.skipTest('Python elftools not available')
Simon Glass7960a0a2022-08-07 09:46:46 -06005668 out, err = self.checkFitSplitElf(allow_missing=True)
Simon Glass40c8bdd2022-03-05 20:19:12 -07005669 self.assertRegex(
5670 err,
5671 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7960a0a2022-08-07 09:46:46 -06005672 self.assertNotRegex(out, '.*Faked blob.*')
5673 fname = tools.get_output_filename('binman-fake/missing.elf')
5674 self.assertFalse(os.path.exists(fname))
Simon Glass40c8bdd2022-03-05 20:19:12 -07005675
5676 def testFitSplitElfFaked(self):
5677 """Test an split-elf FIT with faked ELF file"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02005678 if not elf.ELF_TOOLS:
5679 self.skipTest('Python elftools not available')
Simon Glass7960a0a2022-08-07 09:46:46 -06005680 out, err = self.checkFitSplitElf(allow_missing=True, allow_fake_blobs=True)
Simon Glass40c8bdd2022-03-05 20:19:12 -07005681 self.assertRegex(
5682 err,
5683 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7960a0a2022-08-07 09:46:46 -06005684 self.assertRegex(
5685 out,
5686 "Entry '/binman/fit/images/@tee-SEQ/tee-os': Faked blob '.*binman-fake/missing.elf")
5687 fname = tools.get_output_filename('binman-fake/missing.elf')
5688 self.assertTrue(os.path.exists(fname))
Simon Glass40c8bdd2022-03-05 20:19:12 -07005689
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005690 def testMkimageMissingBlob(self):
5691 """Test using mkimage to build an image"""
5692 with test_util.capture_sys_output() as (stdout, stderr):
5693 self._DoTestFile('229_mkimage_missing.dts', allow_missing=True,
5694 allow_fake_blobs=True)
5695 err = stderr.getvalue()
5696 self.assertRegex(
5697 err,
5698 "Image '.*' has faked external blobs and is non-functional: .*")
5699
Philippe Reynesb1c50932022-03-28 22:57:04 +02005700 def testPreLoad(self):
5701 """Test an image with a pre-load header"""
5702 entry_args = {
Simon Glassefda8ab2023-07-24 09:19:57 -06005703 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
Philippe Reynesb1c50932022-03-28 22:57:04 +02005704 }
Simon Glassefda8ab2023-07-24 09:19:57 -06005705 data = self._DoReadFileDtb(
5706 '230_pre_load.dts', entry_args=entry_args,
5707 extra_indirs=[os.path.join(self._binman_dir, 'test')])[0]
Philippe Reynesb1c50932022-03-28 22:57:04 +02005708 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5709 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5710 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5711
Simon Glassefda8ab2023-07-24 09:19:57 -06005712 def testPreLoadNoKey(self):
5713 """Test an image with a pre-load heade0r with missing key"""
5714 with self.assertRaises(FileNotFoundError) as exc:
5715 self._DoReadFile('230_pre_load.dts')
5716 self.assertIn("No such file or directory: 'dev.key'",
5717 str(exc.exception))
5718
Philippe Reynesb1c50932022-03-28 22:57:04 +02005719 def testPreLoadPkcs(self):
5720 """Test an image with a pre-load header with padding pkcs"""
Simon Glassefda8ab2023-07-24 09:19:57 -06005721 entry_args = {
5722 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5723 }
5724 data = self._DoReadFileDtb('231_pre_load_pkcs.dts',
5725 entry_args=entry_args)[0]
Philippe Reynesb1c50932022-03-28 22:57:04 +02005726 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5727 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5728 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5729
5730 def testPreLoadPss(self):
5731 """Test an image with a pre-load header with padding pss"""
Simon Glassefda8ab2023-07-24 09:19:57 -06005732 entry_args = {
5733 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5734 }
5735 data = self._DoReadFileDtb('232_pre_load_pss.dts',
5736 entry_args=entry_args)[0]
Philippe Reynesb1c50932022-03-28 22:57:04 +02005737 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5738 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5739 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5740
5741 def testPreLoadInvalidPadding(self):
5742 """Test an image with a pre-load header with an invalid padding"""
Simon Glassefda8ab2023-07-24 09:19:57 -06005743 entry_args = {
5744 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5745 }
Philippe Reynesb1c50932022-03-28 22:57:04 +02005746 with self.assertRaises(ValueError) as e:
Simon Glassefda8ab2023-07-24 09:19:57 -06005747 self._DoReadFileDtb('233_pre_load_invalid_padding.dts',
5748 entry_args=entry_args)
Philippe Reynesb1c50932022-03-28 22:57:04 +02005749
5750 def testPreLoadInvalidSha(self):
5751 """Test an image with a pre-load header with an invalid hash"""
Simon Glassefda8ab2023-07-24 09:19:57 -06005752 entry_args = {
5753 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5754 }
Philippe Reynesb1c50932022-03-28 22:57:04 +02005755 with self.assertRaises(ValueError) as e:
Simon Glassefda8ab2023-07-24 09:19:57 -06005756 self._DoReadFileDtb('234_pre_load_invalid_sha.dts',
5757 entry_args=entry_args)
Philippe Reynesb1c50932022-03-28 22:57:04 +02005758
5759 def testPreLoadInvalidAlgo(self):
5760 """Test an image with a pre-load header with an invalid algo"""
5761 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005762 data = self._DoReadFile('235_pre_load_invalid_algo.dts')
Philippe Reynesb1c50932022-03-28 22:57:04 +02005763
5764 def testPreLoadInvalidKey(self):
5765 """Test an image with a pre-load header with an invalid key"""
Simon Glassefda8ab2023-07-24 09:19:57 -06005766 entry_args = {
5767 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5768 }
Philippe Reynesb1c50932022-03-28 22:57:04 +02005769 with self.assertRaises(ValueError) as e:
Simon Glassefda8ab2023-07-24 09:19:57 -06005770 data = self._DoReadFileDtb('236_pre_load_invalid_key.dts',
5771 entry_args=entry_args)
Roger Quadros47f420a2022-02-19 20:50:04 +02005772
Alper Nebi Yasak67bf2c82022-03-27 18:31:44 +03005773 def _CheckSafeUniqueNames(self, *images):
5774 """Check all entries of given images for unsafe unique names"""
5775 for image in images:
5776 entries = {}
5777 image._CollectEntries(entries, {}, image)
5778 for entry in entries.values():
5779 uniq = entry.GetUniqueName()
5780
5781 # Used as part of a filename, so must not be absolute paths.
5782 self.assertFalse(os.path.isabs(uniq))
5783
5784 def testSafeUniqueNames(self):
5785 """Test entry unique names are safe in single image configuration"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005786 data = self._DoReadFileRealDtb('237_unique_names.dts')
Alper Nebi Yasak67bf2c82022-03-27 18:31:44 +03005787
5788 orig_image = control.images['image']
5789 image_fname = tools.get_output_filename('image.bin')
5790 image = Image.FromFile(image_fname)
5791
5792 self._CheckSafeUniqueNames(orig_image, image)
5793
5794 def testSafeUniqueNamesMulti(self):
5795 """Test entry unique names are safe with multiple images"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005796 data = self._DoReadFileRealDtb('238_unique_names_multi.dts')
Alper Nebi Yasak67bf2c82022-03-27 18:31:44 +03005797
5798 orig_image = control.images['image']
5799 image_fname = tools.get_output_filename('image.bin')
5800 image = Image.FromFile(image_fname)
5801
5802 self._CheckSafeUniqueNames(orig_image, image)
5803
Alper Nebi Yasak8ee4ec92022-03-27 18:31:45 +03005804 def testReplaceCmdWithBintool(self):
5805 """Test replacing an entry that needs a bintool to pack"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005806 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasak8ee4ec92022-03-27 18:31:45 +03005807 expected = U_BOOT_DATA + b'aa'
5808 self.assertEqual(expected, data[:len(expected)])
5809
5810 try:
5811 tmpdir, updated_fname = self._SetupImageInTmpdir()
5812 fname = os.path.join(tmpdir, 'update-testing.bin')
5813 tools.write_file(fname, b'zz')
5814 self._DoBinman('replace', '-i', updated_fname,
5815 '_testing', '-f', fname)
5816
5817 data = tools.read_file(updated_fname)
5818 expected = U_BOOT_DATA + b'zz'
5819 self.assertEqual(expected, data[:len(expected)])
5820 finally:
5821 shutil.rmtree(tmpdir)
5822
5823 def testReplaceCmdOtherWithBintool(self):
5824 """Test replacing an entry when another needs a bintool to pack"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005825 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasak8ee4ec92022-03-27 18:31:45 +03005826 expected = U_BOOT_DATA + b'aa'
5827 self.assertEqual(expected, data[:len(expected)])
5828
5829 try:
5830 tmpdir, updated_fname = self._SetupImageInTmpdir()
5831 fname = os.path.join(tmpdir, 'update-u-boot.bin')
5832 tools.write_file(fname, b'x' * len(U_BOOT_DATA))
5833 self._DoBinman('replace', '-i', updated_fname,
5834 'u-boot', '-f', fname)
5835
5836 data = tools.read_file(updated_fname)
5837 expected = b'x' * len(U_BOOT_DATA) + b'aa'
5838 self.assertEqual(expected, data[:len(expected)])
5839 finally:
5840 shutil.rmtree(tmpdir)
5841
Alper Nebi Yasake2ce4fb2022-03-27 18:31:46 +03005842 def testReplaceResizeNoRepackSameSize(self):
5843 """Test replacing entries with same-size data without repacking"""
5844 expected = b'x' * len(U_BOOT_DATA)
5845 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected)
5846 self.assertEqual(expected, data)
5847
5848 path, fdtmap = state.GetFdtContents('fdtmap')
5849 self.assertIsNotNone(path)
5850 self.assertEqual(expected_fdtmap, fdtmap)
5851
5852 def testReplaceResizeNoRepackSmallerSize(self):
5853 """Test replacing entries with smaller-size data without repacking"""
5854 new_data = b'x'
5855 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', new_data)
5856 expected = new_data.ljust(len(U_BOOT_DATA), b'\0')
5857 self.assertEqual(expected, data)
5858
5859 path, fdtmap = state.GetFdtContents('fdtmap')
5860 self.assertIsNotNone(path)
5861 self.assertEqual(expected_fdtmap, fdtmap)
5862
Alper Nebi Yasak74d3b232022-03-27 18:31:48 +03005863 def testExtractFit(self):
5864 """Test extracting a FIT section"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005865 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak74d3b232022-03-27 18:31:48 +03005866 image_fname = tools.get_output_filename('image.bin')
5867
5868 fit_data = control.ReadEntry(image_fname, 'fit')
5869 fit = fdt.Fdt.FromData(fit_data)
5870 fit.Scan()
5871
5872 # Check subentry data inside the extracted fit
5873 for node_path, expected in [
5874 ('/images/kernel', U_BOOT_DATA),
5875 ('/images/fdt-1', U_BOOT_NODTB_DATA),
5876 ('/images/scr-1', COMPRESS_DATA),
5877 ]:
5878 node = fit.GetNode(node_path)
5879 data = fit.GetProps(node)['data'].bytes
5880 self.assertEqual(expected, data)
5881
5882 def testExtractFitSubentries(self):
5883 """Test extracting FIT section subentries"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005884 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak74d3b232022-03-27 18:31:48 +03005885 image_fname = tools.get_output_filename('image.bin')
5886
5887 for entry_path, expected in [
5888 ('fit/kernel', U_BOOT_DATA),
5889 ('fit/kernel/u-boot', U_BOOT_DATA),
5890 ('fit/fdt-1', U_BOOT_NODTB_DATA),
5891 ('fit/fdt-1/u-boot-nodtb', U_BOOT_NODTB_DATA),
5892 ('fit/scr-1', COMPRESS_DATA),
5893 ('fit/scr-1/blob', COMPRESS_DATA),
5894 ]:
5895 data = control.ReadEntry(image_fname, entry_path)
5896 self.assertEqual(expected, data)
5897
Alper Nebi Yasak99283e52022-03-27 18:31:49 +03005898 def testReplaceFitSubentryLeafSameSize(self):
5899 """Test replacing a FIT leaf subentry with same-size data"""
5900 new_data = b'x' * len(U_BOOT_DATA)
5901 data, expected_fdtmap, _ = self._RunReplaceCmd(
5902 'fit/kernel/u-boot', new_data,
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005903 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak99283e52022-03-27 18:31:49 +03005904 self.assertEqual(new_data, data)
5905
5906 path, fdtmap = state.GetFdtContents('fdtmap')
5907 self.assertIsNotNone(path)
5908 self.assertEqual(expected_fdtmap, fdtmap)
5909
5910 def testReplaceFitSubentryLeafBiggerSize(self):
5911 """Test replacing a FIT leaf subentry with bigger-size data"""
5912 new_data = b'ub' * len(U_BOOT_NODTB_DATA)
5913 data, expected_fdtmap, _ = self._RunReplaceCmd(
5914 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005915 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak99283e52022-03-27 18:31:49 +03005916 self.assertEqual(new_data, data)
5917
5918 # Will be repacked, so fdtmap must change
5919 path, fdtmap = state.GetFdtContents('fdtmap')
5920 self.assertIsNotNone(path)
5921 self.assertNotEqual(expected_fdtmap, fdtmap)
5922
5923 def testReplaceFitSubentryLeafSmallerSize(self):
5924 """Test replacing a FIT leaf subentry with smaller-size data"""
5925 new_data = b'x'
5926 expected = new_data.ljust(len(U_BOOT_NODTB_DATA), b'\0')
5927 data, expected_fdtmap, _ = self._RunReplaceCmd(
5928 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005929 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak99283e52022-03-27 18:31:49 +03005930 self.assertEqual(expected, data)
5931
5932 path, fdtmap = state.GetFdtContents('fdtmap')
5933 self.assertIsNotNone(path)
5934 self.assertEqual(expected_fdtmap, fdtmap)
5935
Alper Nebi Yasak82337bb2022-03-27 18:31:50 +03005936 def testReplaceSectionSimple(self):
Simon Glass7caa3722023-03-02 17:02:44 -07005937 """Test replacing a simple section with same-sized data"""
Alper Nebi Yasak82337bb2022-03-27 18:31:50 +03005938 new_data = b'w' * len(COMPRESS_DATA + U_BOOT_DATA)
Simon Glass7caa3722023-03-02 17:02:44 -07005939 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5940 new_data, dts='241_replace_section_simple.dts')
5941 self.assertEqual(new_data, data)
5942
5943 entries = image.GetEntries()
5944 self.assertIn('section', entries)
5945 entry = entries['section']
5946 self.assertEqual(len(new_data), entry.size)
5947
5948 def testReplaceSectionLarger(self):
5949 """Test replacing a simple section with larger data"""
5950 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
5951 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5952 new_data, dts='241_replace_section_simple.dts')
5953 self.assertEqual(new_data, data)
5954
5955 entries = image.GetEntries()
5956 self.assertIn('section', entries)
5957 entry = entries['section']
5958 self.assertEqual(len(new_data), entry.size)
5959 fentry = entries['fdtmap']
5960 self.assertEqual(entry.offset + entry.size, fentry.offset)
5961
5962 def testReplaceSectionSmaller(self):
5963 """Test replacing a simple section with smaller data"""
5964 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1) + b'\0'
5965 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5966 new_data, dts='241_replace_section_simple.dts')
5967 self.assertEqual(new_data, data)
5968
5969 # The new size is the same as the old, just with a pad byte at the end
5970 entries = image.GetEntries()
5971 self.assertIn('section', entries)
5972 entry = entries['section']
5973 self.assertEqual(len(new_data), entry.size)
5974
5975 def testReplaceSectionSmallerAllow(self):
5976 """Test failing to replace a simple section with smaller data"""
5977 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1)
5978 try:
5979 state.SetAllowEntryContraction(True)
5980 with self.assertRaises(ValueError) as exc:
5981 self._RunReplaceCmd('section', new_data,
5982 dts='241_replace_section_simple.dts')
5983 finally:
5984 state.SetAllowEntryContraction(False)
5985
5986 # Since we have no information about the position of things within the
5987 # section, we cannot adjust the position of /section-u-boot so it ends
5988 # up outside the section
Simon Glass73593e42022-08-13 11:40:46 -06005989 self.assertIn(
Simon Glass7caa3722023-03-02 17:02:44 -07005990 "Node '/section/u-boot': Offset 0x24 (36) size 0x4 (4) is outside "
5991 "the section '/section' starting at 0x0 (0) of size 0x27 (39)",
Simon Glass73593e42022-08-13 11:40:46 -06005992 str(exc.exception))
Alper Nebi Yasak82337bb2022-03-27 18:31:50 +03005993
Simon Glassdfe1db42022-08-13 11:40:48 -06005994 def testMkimageImagename(self):
5995 """Test using mkimage with -n holding the data too"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06005996 self._SetupSplElf()
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005997 data = self._DoReadFile('242_mkimage_name.dts')
Simon Glassdfe1db42022-08-13 11:40:48 -06005998
5999 # Check that the data appears in the file somewhere
6000 self.assertIn(U_BOOT_SPL_DATA, data)
6001
Simon Glassf3543e62022-09-06 20:26:52 -06006002 # Get struct legacy_img_hdr -> ih_name
Simon Glassdfe1db42022-08-13 11:40:48 -06006003 name = data[0x20:0x40]
6004
6005 # Build the filename that we expect to be placed in there, by virtue of
6006 # the -n paraameter
6007 expect = os.path.join(tools.get_output_dir(), 'mkimage.mkimage')
6008
6009 # Check that the image name is set to the temporary filename used
6010 self.assertEqual(expect.encode('utf-8')[:0x20], name)
6011
Simon Glass9db9e932022-08-13 11:40:49 -06006012 def testMkimageImage(self):
6013 """Test using mkimage with -n holding the data too"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06006014 self._SetupSplElf()
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02006015 data = self._DoReadFile('243_mkimage_image.dts')
Simon Glass9db9e932022-08-13 11:40:49 -06006016
6017 # Check that the data appears in the file somewhere
6018 self.assertIn(U_BOOT_SPL_DATA, data)
6019
Simon Glassf3543e62022-09-06 20:26:52 -06006020 # Get struct legacy_img_hdr -> ih_name
Simon Glass9db9e932022-08-13 11:40:49 -06006021 name = data[0x20:0x40]
6022
6023 # Build the filename that we expect to be placed in there, by virtue of
6024 # the -n paraameter
6025 expect = os.path.join(tools.get_output_dir(), 'mkimage-n.mkimage')
6026
6027 # Check that the image name is set to the temporary filename used
6028 self.assertEqual(expect.encode('utf-8')[:0x20], name)
6029
6030 # Check the corect data is in the imagename file
6031 self.assertEqual(U_BOOT_DATA, tools.read_file(expect))
6032
6033 def testMkimageImageNoContent(self):
6034 """Test using mkimage with -n and no data"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06006035 self._SetupSplElf()
Simon Glass9db9e932022-08-13 11:40:49 -06006036 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02006037 self._DoReadFile('244_mkimage_image_no_content.dts')
Simon Glass9db9e932022-08-13 11:40:49 -06006038 self.assertIn('Could not complete processing of contents',
6039 str(exc.exception))
6040
6041 def testMkimageImageBad(self):
6042 """Test using mkimage with imagename node and data-to-imagename"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06006043 self._SetupSplElf()
Simon Glass9db9e932022-08-13 11:40:49 -06006044 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02006045 self._DoReadFile('245_mkimage_image_bad.dts')
Simon Glass9db9e932022-08-13 11:40:49 -06006046 self.assertIn('Cannot use both imagename node and data-to-imagename',
6047 str(exc.exception))
6048
Simon Glassd626e822022-08-13 11:40:50 -06006049 def testCollectionOther(self):
6050 """Test a collection where the data comes from another section"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02006051 data = self._DoReadFile('246_collection_other.dts')
Simon Glassd626e822022-08-13 11:40:50 -06006052 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
6053 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
6054 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
6055 data)
6056
6057 def testMkimageCollection(self):
6058 """Test using a collection referring to an entry in a mkimage entry"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06006059 self._SetupSplElf()
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02006060 data = self._DoReadFile('247_mkimage_coll.dts')
Simon Glassd626e822022-08-13 11:40:50 -06006061 expect = U_BOOT_SPL_DATA + U_BOOT_DATA
6062 self.assertEqual(expect, data[:len(expect)])
6063
Stefan Herbrechtsmeier6aa80002022-08-19 16:25:25 +02006064 def testCompressDtbPrependInvalid(self):
6065 """Test that invalid header is detected"""
6066 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02006067 self._DoReadFileDtb('248_compress_dtb_prepend_invalid.dts')
Stefan Herbrechtsmeier6aa80002022-08-19 16:25:25 +02006068 self.assertIn("Node '/binman/u-boot-dtb': Invalid prepend in "
6069 "'u-boot-dtb': 'invalid'", str(e.exception))
6070
6071 def testCompressDtbPrependLength(self):
6072 """Test that compress with length header works as expected"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02006073 data = self._DoReadFileRealDtb('249_compress_dtb_prepend_length.dts')
Stefan Herbrechtsmeier6aa80002022-08-19 16:25:25 +02006074 image = control.images['image']
6075 entries = image.GetEntries()
6076 self.assertIn('u-boot-dtb', entries)
6077 u_boot_dtb = entries['u-boot-dtb']
6078 self.assertIn('fdtmap', entries)
6079 fdtmap = entries['fdtmap']
6080
6081 image_fname = tools.get_output_filename('image.bin')
6082 orig = control.ReadEntry(image_fname, 'u-boot-dtb')
6083 dtb = fdt.Fdt.FromData(orig)
6084 dtb.Scan()
6085 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
6086 expected = {
6087 'u-boot:size': len(U_BOOT_DATA),
6088 'u-boot-dtb:uncomp-size': len(orig),
6089 'u-boot-dtb:size': u_boot_dtb.size,
6090 'fdtmap:size': fdtmap.size,
6091 'size': len(data),
6092 }
6093 self.assertEqual(expected, props)
6094
6095 # Check implementation
6096 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6097 rest = data[len(U_BOOT_DATA):]
6098 comp_data_len = struct.unpack('<I', rest[:4])[0]
6099 comp_data = rest[4:4 + comp_data_len]
6100 orig2 = self._decompress(comp_data)
6101 self.assertEqual(orig, orig2)
6102
Stefan Herbrechtsmeierec7d27d2022-08-19 16:25:30 +02006103 def testInvalidCompress(self):
6104 """Test that invalid compress algorithm is detected"""
6105 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02006106 self._DoTestFile('250_compress_dtb_invalid.dts')
Stefan Herbrechtsmeierec7d27d2022-08-19 16:25:30 +02006107 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
6108
Stefan Herbrechtsmeierda1af352022-08-19 16:25:32 +02006109 def testCompUtilCompressions(self):
6110 """Test compression algorithms"""
6111 for bintool in self.comp_bintools.values():
6112 self._CheckBintool(bintool)
6113 data = bintool.compress(COMPRESS_DATA)
6114 self.assertNotEqual(COMPRESS_DATA, data)
6115 orig = bintool.decompress(data)
Brandon Maier357bfca2024-06-04 16:16:05 +00006116 self.assertEqual(COMPRESS_DATA, orig)
Stefan Herbrechtsmeierda1af352022-08-19 16:25:32 +02006117
6118 def testCompUtilVersions(self):
6119 """Test tool version of compression algorithms"""
6120 for bintool in self.comp_bintools.values():
6121 self._CheckBintool(bintool)
6122 version = bintool.version()
6123 self.assertRegex(version, '^v?[0-9]+[0-9.]*')
6124
6125 def testCompUtilPadding(self):
6126 """Test padding of compression algorithms"""
Stefan Herbrechtsmeiercd15b642022-08-19 16:25:38 +02006127 # Skip zstd because it doesn't support padding
6128 for bintool in [v for k,v in self.comp_bintools.items() if k != 'zstd']:
Stefan Herbrechtsmeierda1af352022-08-19 16:25:32 +02006129 self._CheckBintool(bintool)
6130 data = bintool.compress(COMPRESS_DATA)
6131 self.assertNotEqual(COMPRESS_DATA, data)
6132 data += tools.get_bytes(0, 64)
6133 orig = bintool.decompress(data)
Brandon Maier357bfca2024-06-04 16:16:05 +00006134 self.assertEqual(COMPRESS_DATA, orig)
Stefan Herbrechtsmeierda1af352022-08-19 16:25:32 +02006135
Stefan Herbrechtsmeiercd15b642022-08-19 16:25:38 +02006136 def testCompressDtbZstd(self):
6137 """Test that zstd compress of device-tree files failed"""
6138 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02006139 self._DoTestFile('251_compress_dtb_zstd.dts')
Stefan Herbrechtsmeiercd15b642022-08-19 16:25:38 +02006140 self.assertIn("Node '/binman/u-boot-dtb': The zstd compression "
6141 "requires a length header", str(e.exception))
6142
Quentin Schulz4d91df02022-09-02 15:10:48 +02006143 def testMkimageMultipleDataFiles(self):
6144 """Test passing multiple files to mkimage in a mkimage entry"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06006145 self._SetupSplElf()
6146 self._SetupTplElf()
Quentin Schulz4d91df02022-09-02 15:10:48 +02006147 data = self._DoReadFile('252_mkimage_mult_data.dts')
6148 # Size of files are packed in their 4B big-endian format
6149 expect = struct.pack('>I', len(U_BOOT_TPL_DATA))
6150 expect += struct.pack('>I', len(U_BOOT_SPL_DATA))
6151 # Size info is always followed by a 4B zero value.
6152 expect += tools.get_bytes(0, 4)
6153 expect += U_BOOT_TPL_DATA
6154 # All but last files are 4B-aligned
6155 align_pad = len(U_BOOT_TPL_DATA) % 4
6156 if align_pad:
6157 expect += tools.get_bytes(0, align_pad)
6158 expect += U_BOOT_SPL_DATA
6159 self.assertEqual(expect, data[-len(expect):])
6160
Marek Vasutfadad3a2023-07-18 07:23:58 -06006161 def testMkimageMultipleExpanded(self):
6162 """Test passing multiple files to mkimage in a mkimage entry"""
6163 self._SetupSplElf()
6164 self._SetupTplElf()
6165 entry_args = {
6166 'spl-bss-pad': 'y',
6167 'spl-dtb': 'y',
6168 }
6169 data = self._DoReadFileDtb('252_mkimage_mult_data.dts',
6170 use_expanded=True, entry_args=entry_args)[0]
6171 pad_len = 10
6172 tpl_expect = U_BOOT_TPL_DATA
6173 spl_expect = U_BOOT_SPL_NODTB_DATA + tools.get_bytes(0, pad_len)
6174 spl_expect += U_BOOT_SPL_DTB_DATA
6175
6176 content = data[0x40:]
6177 lens = struct.unpack('>III', content[:12])
6178
6179 # Size of files are packed in their 4B big-endian format
6180 # Size info is always followed by a 4B zero value.
6181 self.assertEqual(len(tpl_expect), lens[0])
6182 self.assertEqual(len(spl_expect), lens[1])
6183 self.assertEqual(0, lens[2])
6184
6185 rest = content[12:]
6186 self.assertEqual(tpl_expect, rest[:len(tpl_expect)])
6187
6188 rest = rest[len(tpl_expect):]
6189 align_pad = len(tpl_expect) % 4
6190 self.assertEqual(tools.get_bytes(0, align_pad), rest[:align_pad])
6191 rest = rest[align_pad:]
6192 self.assertEqual(spl_expect, rest)
6193
Quentin Schulz4d91df02022-09-02 15:10:48 +02006194 def testMkimageMultipleNoContent(self):
6195 """Test passing multiple data files to mkimage with one data file having no content"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06006196 self._SetupSplElf()
Quentin Schulz4d91df02022-09-02 15:10:48 +02006197 with self.assertRaises(ValueError) as exc:
6198 self._DoReadFile('253_mkimage_mult_no_content.dts')
6199 self.assertIn('Could not complete processing of contents',
6200 str(exc.exception))
6201
Quentin Schulz6cc29dc2022-09-02 15:10:49 +02006202 def testMkimageFilename(self):
6203 """Test using mkimage to build a binary with a filename"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06006204 self._SetupSplElf()
Quentin Schulz6cc29dc2022-09-02 15:10:49 +02006205 retcode = self._DoTestFile('254_mkimage_filename.dts')
6206 self.assertEqual(0, retcode)
6207 fname = tools.get_output_filename('mkimage-test.bin')
6208 self.assertTrue(os.path.exists(fname))
6209
Simon Glass6ad24522022-02-28 07:16:54 -07006210 def testVpl(self):
6211 """Test that an image with VPL and its device tree can be created"""
6212 # ELF file with a '__bss_size' symbol
6213 self._SetupVplElf()
6214 data = self._DoReadFile('255_u_boot_vpl.dts')
6215 self.assertEqual(U_BOOT_VPL_DATA + U_BOOT_VPL_DTB_DATA, data)
6216
6217 def testVplNoDtb(self):
6218 """Test that an image with vpl/u-boot-vpl-nodtb.bin can be created"""
6219 self._SetupVplElf()
6220 data = self._DoReadFile('256_u_boot_vpl_nodtb.dts')
6221 self.assertEqual(U_BOOT_VPL_NODTB_DATA,
6222 data[:len(U_BOOT_VPL_NODTB_DATA)])
6223
6224 def testExpandedVpl(self):
6225 """Test that an expanded entry type is selected for TPL when needed"""
6226 self._SetupVplElf()
6227
6228 entry_args = {
6229 'vpl-bss-pad': 'y',
6230 'vpl-dtb': 'y',
6231 }
6232 self._DoReadFileDtb('257_fdt_incl_vpl.dts', use_expanded=True,
6233 entry_args=entry_args)
6234 image = control.images['image']
6235 entries = image.GetEntries()
6236 self.assertEqual(1, len(entries))
6237
6238 # We only have u-boot-vpl, which be expanded
6239 self.assertIn('u-boot-vpl', entries)
6240 entry = entries['u-boot-vpl']
6241 self.assertEqual('u-boot-vpl-expanded', entry.etype)
6242 subent = entry.GetEntries()
6243 self.assertEqual(3, len(subent))
6244 self.assertIn('u-boot-vpl-nodtb', subent)
6245 self.assertIn('u-boot-vpl-bss-pad', subent)
6246 self.assertIn('u-boot-vpl-dtb', subent)
6247
6248 def testVplBssPadMissing(self):
6249 """Test that a missing symbol is detected"""
6250 self._SetupVplElf('u_boot_ucode_ptr')
6251 with self.assertRaises(ValueError) as e:
6252 self._DoReadFile('258_vpl_bss_pad.dts')
6253 self.assertIn('Expected __bss_size symbol in vpl/u-boot-vpl',
6254 str(e.exception))
6255
Neha Malcom Francis3545e852022-10-17 16:36:25 +05306256 def testSymlink(self):
Andrew Davis15432ea2023-07-22 00:14:44 +05306257 """Test that image files can be symlinked"""
Neha Malcom Francis3545e852022-10-17 16:36:25 +05306258 retcode = self._DoTestFile('259_symlink.dts', debug=True, map=True)
6259 self.assertEqual(0, retcode)
6260 image = control.images['test_image']
6261 fname = tools.get_output_filename('test_image.bin')
6262 sname = tools.get_output_filename('symlink_to_test.bin')
6263 self.assertTrue(os.path.islink(sname))
6264 self.assertEqual(os.readlink(sname), fname)
Alper Nebi Yasak8ee4ec92022-03-27 18:31:45 +03006265
Andrew Davis15432ea2023-07-22 00:14:44 +05306266 def testSymlinkOverwrite(self):
6267 """Test that symlinked images can be overwritten"""
6268 testdir = TestFunctional._MakeInputDir('symlinktest')
6269 self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
6270 # build the same image again in the same directory so that existing symlink is present
6271 self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
6272 fname = tools.get_output_filename('test_image.bin')
6273 sname = tools.get_output_filename('symlink_to_test.bin')
6274 self.assertTrue(os.path.islink(sname))
6275 self.assertEqual(os.readlink(sname), fname)
6276
Simon Glassd2afb9e2022-10-20 18:22:47 -06006277 def testSymbolsElf(self):
6278 """Test binman can assign symbols embedded in an ELF file"""
6279 if not elf.ELF_TOOLS:
6280 self.skipTest('Python elftools not available')
6281 self._SetupTplElf('u_boot_binman_syms')
6282 self._SetupVplElf('u_boot_binman_syms')
6283 self._SetupSplElf('u_boot_binman_syms')
6284 data = self._DoReadFileDtb('260_symbols_elf.dts')[0]
6285 image_fname = tools.get_output_filename('image.bin')
6286
6287 image = control.images['image']
6288 entries = image.GetEntries()
6289
6290 for entry in entries.values():
6291 # No symbols in u-boot and it has faked contents anyway
6292 if entry.name == 'u-boot':
6293 continue
6294 edata = data[entry.image_pos:entry.image_pos + entry.size]
6295 efname = tools.get_output_filename(f'edata-{entry.name}')
6296 tools.write_file(efname, edata)
6297
6298 syms = elf.GetSymbolFileOffset(efname, ['_binman_u_boot'])
6299 re_name = re.compile('_binman_(u_boot_(.*))_prop_(.*)')
6300 for name, sym in syms.items():
6301 msg = 'test'
6302 val = elf.GetSymbolValue(sym, edata, msg)
6303 entry_m = re_name.match(name)
6304 if entry_m:
6305 ename, prop = entry_m.group(1), entry_m.group(3)
6306 entry, entry_name, prop_name = image.LookupEntry(entries,
6307 name, msg)
6308 if prop_name == 'offset':
6309 expect_val = entry.offset
6310 elif prop_name == 'image_pos':
6311 expect_val = entry.image_pos
6312 elif prop_name == 'size':
6313 expect_val = entry.size
6314 self.assertEqual(expect_val, val)
6315
6316 def testSymbolsElfBad(self):
6317 """Check error when trying to write symbols without the elftools lib"""
6318 if not elf.ELF_TOOLS:
6319 self.skipTest('Python elftools not available')
6320 self._SetupTplElf('u_boot_binman_syms')
6321 self._SetupVplElf('u_boot_binman_syms')
6322 self._SetupSplElf('u_boot_binman_syms')
6323 try:
6324 elf.ELF_TOOLS = False
6325 with self.assertRaises(ValueError) as exc:
6326 self._DoReadFileDtb('260_symbols_elf.dts')
6327 finally:
6328 elf.ELF_TOOLS = True
6329 self.assertIn(
6330 "Section '/binman': entry '/binman/u-boot-spl-elf': "
6331 'Cannot write symbols to an ELF file without Python elftools',
6332 str(exc.exception))
6333
Simon Glassefddab62023-01-07 14:07:08 -07006334 def testSectionFilename(self):
6335 """Check writing of section contents to a file"""
6336 data = self._DoReadFile('261_section_fname.dts')
6337 expected = (b'&&' + U_BOOT_DATA + b'&&&' +
6338 tools.get_bytes(ord('!'), 7) +
6339 U_BOOT_DATA + tools.get_bytes(ord('&'), 12))
6340 self.assertEqual(expected, data)
6341
6342 sect_fname = tools.get_output_filename('outfile.bin')
6343 self.assertTrue(os.path.exists(sect_fname))
6344 sect_data = tools.read_file(sect_fname)
6345 self.assertEqual(U_BOOT_DATA, sect_data)
6346
Simon Glassc8c9f312023-01-07 14:07:12 -07006347 def testAbsent(self):
6348 """Check handling of absent entries"""
6349 data = self._DoReadFile('262_absent.dts')
6350 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6351
Simon Glass2f80c5e2023-01-07 14:07:14 -07006352 def testPackTeeOsOptional(self):
6353 """Test that an image with an optional TEE binary can be created"""
6354 entry_args = {
6355 'tee-os-path': 'tee.elf',
6356 }
6357 data = self._DoReadFileDtb('263_tee_os_opt.dts',
6358 entry_args=entry_args)[0]
6359 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6360
6361 def checkFitTee(self, dts, tee_fname):
6362 """Check that a tee-os entry works and returns data
6363
6364 Args:
6365 dts (str): Device tree filename to use
6366 tee_fname (str): filename containing tee-os
6367
6368 Returns:
6369 bytes: Image contents
6370 """
6371 if not elf.ELF_TOOLS:
6372 self.skipTest('Python elftools not available')
6373 entry_args = {
6374 'of-list': 'test-fdt1 test-fdt2',
6375 'default-dt': 'test-fdt2',
6376 'tee-os-path': tee_fname,
6377 }
6378 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
6379 data = self._DoReadFileDtb(dts, entry_args=entry_args,
6380 extra_indirs=[test_subdir])[0]
6381 return data
6382
6383 def testFitTeeOsOptionalFit(self):
6384 """Test an image with a FIT with an optional OP-TEE binary"""
6385 data = self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bin')
6386
6387 # There should be only one node, holding the data set up in SetUpClass()
6388 # for tee.bin
6389 dtb = fdt.Fdt.FromData(data)
6390 dtb.Scan()
6391 node = dtb.GetNode('/images/tee-1')
6392 self.assertEqual(TEE_ADDR,
6393 fdt_util.fdt32_to_cpu(node.props['load'].value))
6394 self.assertEqual(TEE_ADDR,
6395 fdt_util.fdt32_to_cpu(node.props['entry'].value))
6396 self.assertEqual(U_BOOT_DATA, node.props['data'].bytes)
6397
Jonas Karlman49dcd1c2023-07-18 20:34:36 +00006398 with test_util.capture_sys_output() as (stdout, stderr):
6399 self.checkFitTee('264_tee_os_opt_fit.dts', '')
6400 err = stderr.getvalue()
6401 self.assertRegex(
6402 err,
6403 "Image '.*' is missing optional external blobs but is still functional: tee-os")
6404
Simon Glass2f80c5e2023-01-07 14:07:14 -07006405 def testFitTeeOsOptionalFitBad(self):
6406 """Test an image with a FIT with an optional OP-TEE binary"""
6407 with self.assertRaises(ValueError) as exc:
6408 self.checkFitTee('265_tee_os_opt_fit_bad.dts', 'tee.bin')
6409 self.assertIn(
6410 "Node '/binman/fit': subnode 'images/@tee-SEQ': Failed to read ELF file: Magic number does not match",
6411 str(exc.exception))
6412
6413 def testFitTeeOsBad(self):
6414 """Test an OP-TEE binary with wrong formats"""
6415 self.make_tee_bin('tee.bad1', 123)
6416 with self.assertRaises(ValueError) as exc:
6417 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad1')
6418 self.assertIn(
6419 "Node '/binman/fit/images/@tee-SEQ/tee-os': OP-TEE paged mode not supported",
6420 str(exc.exception))
6421
6422 self.make_tee_bin('tee.bad2', 0, b'extra data')
6423 with self.assertRaises(ValueError) as exc:
6424 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad2')
6425 self.assertIn(
6426 "Node '/binman/fit/images/@tee-SEQ/tee-os': Invalid OP-TEE file: size mismatch (expected 0x4, have 0xe)",
6427 str(exc.exception))
6428
Simon Glass67a05012023-01-07 14:07:15 -07006429 def testExtblobOptional(self):
6430 """Test an image with an external blob that is optional"""
6431 with test_util.capture_sys_output() as (stdout, stderr):
6432 data = self._DoReadFile('266_blob_ext_opt.dts')
6433 self.assertEqual(REFCODE_DATA, data)
6434 err = stderr.getvalue()
6435 self.assertRegex(
6436 err,
Jonas Karlman05dec372023-07-18 20:34:34 +00006437 "Image '.*' is missing optional external blobs but is still functional: missing")
Simon Glass67a05012023-01-07 14:07:15 -07006438
Simon Glass0b079fc2023-01-11 16:10:12 -07006439 def testSectionInner(self):
6440 """Test an inner section with a size"""
6441 data = self._DoReadFile('267_section_inner.dts')
6442 expected = U_BOOT_DATA + tools.get_bytes(0, 12)
6443 self.assertEqual(expected, data)
6444
Simon Glass62ef2f72023-01-11 16:10:14 -07006445 def testNull(self):
6446 """Test an image with a null entry"""
6447 data = self._DoReadFile('268_null.dts')
6448 self.assertEqual(U_BOOT_DATA + b'\xff\xff\xff\xff' + U_BOOT_IMG_DATA, data)
6449
Simon Glass9766f692023-01-11 16:10:16 -07006450 def testOverlap(self):
6451 """Test an image with a overlapping entry"""
6452 data = self._DoReadFile('269_overlap.dts')
6453 self.assertEqual(U_BOOT_DATA[:1] + b'aa' + U_BOOT_DATA[3:], data)
6454
6455 image = control.images['image']
6456 entries = image.GetEntries()
6457
6458 self.assertIn('inset', entries)
6459 inset = entries['inset']
6460 self.assertEqual(1, inset.offset);
6461 self.assertEqual(1, inset.image_pos);
6462 self.assertEqual(2, inset.size);
6463
6464 def testOverlapNull(self):
6465 """Test an image with a null overlap"""
6466 data = self._DoReadFile('270_overlap_null.dts')
6467 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6468
6469 # Check the FMAP
6470 fhdr, fentries = fmap_util.DecodeFmap(data[len(U_BOOT_DATA):])
6471 self.assertEqual(4, fhdr.nareas)
6472 fiter = iter(fentries)
6473
6474 fentry = next(fiter)
6475 self.assertEqual(b'SECTION', fentry.name)
6476 self.assertEqual(0, fentry.offset)
6477 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6478 self.assertEqual(0, fentry.flags)
6479
6480 fentry = next(fiter)
6481 self.assertEqual(b'U_BOOT', fentry.name)
6482 self.assertEqual(0, fentry.offset)
6483 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6484 self.assertEqual(0, fentry.flags)
6485
6486 # Make sure that the NULL entry appears in the FMAP
6487 fentry = next(fiter)
6488 self.assertEqual(b'NULL', fentry.name)
6489 self.assertEqual(1, fentry.offset)
6490 self.assertEqual(2, fentry.size)
6491 self.assertEqual(0, fentry.flags)
6492
6493 fentry = next(fiter)
6494 self.assertEqual(b'FMAP', fentry.name)
6495 self.assertEqual(len(U_BOOT_DATA), fentry.offset)
6496
6497 def testOverlapBad(self):
6498 """Test an image with a bad overlapping entry"""
6499 with self.assertRaises(ValueError) as exc:
6500 self._DoReadFile('271_overlap_bad.dts')
6501 self.assertIn(
6502 "Node '/binman/inset': Offset 0x10 (16) ending at 0x12 (18) must overlap with existing entries",
6503 str(exc.exception))
6504
6505 def testOverlapNoOffset(self):
6506 """Test an image with a bad overlapping entry"""
6507 with self.assertRaises(ValueError) as exc:
6508 self._DoReadFile('272_overlap_no_size.dts')
6509 self.assertIn(
6510 "Node '/binman/inset': 'fill' entry is missing properties: size",
6511 str(exc.exception))
6512
Simon Glassc1157862023-01-11 16:10:17 -07006513 def testBlobSymbol(self):
6514 """Test a blob with symbols read from an ELF file"""
6515 elf_fname = self.ElfTestFile('blob_syms')
6516 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6517 TestFunctional._MakeInputFile('blob_syms.bin',
6518 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6519
6520 data = self._DoReadFile('273_blob_symbol.dts')
6521
6522 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6523 addr = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6524 self.assertEqual(syms['_binman_sym_magic'].address, addr)
6525 self.assertEqual(syms['_binman_inset_prop_offset'].address, addr + 4)
6526 self.assertEqual(syms['_binman_inset_prop_size'].address, addr + 8)
6527
6528 sym_values = struct.pack('<LLL', elf.BINMAN_SYM_MAGIC_VALUE, 4, 8)
6529 expected = sym_values
6530 self.assertEqual(expected, data[:len(expected)])
6531
Simon Glass571bc4e2023-01-11 16:10:19 -07006532 def testOffsetFromElf(self):
6533 """Test a blob with symbols read from an ELF file"""
6534 elf_fname = self.ElfTestFile('blob_syms')
6535 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6536 TestFunctional._MakeInputFile('blob_syms.bin',
6537 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6538
6539 data = self._DoReadFile('274_offset_from_elf.dts')
6540
6541 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6542 base = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6543
6544 image = control.images['image']
6545 entries = image.GetEntries()
6546
6547 self.assertIn('inset', entries)
6548 inset = entries['inset']
6549
6550 self.assertEqual(base + 4, inset.offset);
6551 self.assertEqual(base + 4, inset.image_pos);
6552 self.assertEqual(4, inset.size);
6553
6554 self.assertIn('inset2', entries)
6555 inset = entries['inset2']
6556 self.assertEqual(base + 8, inset.offset);
6557 self.assertEqual(base + 8, inset.image_pos);
6558 self.assertEqual(4, inset.size);
6559
Jonas Karlman9b2fd2d2023-01-21 19:01:39 +00006560 def testFitAlign(self):
6561 """Test an image with an FIT with aligned external data"""
6562 data = self._DoReadFile('275_fit_align.dts')
6563 self.assertEqual(4096, len(data))
6564
6565 dtb = fdt.Fdt.FromData(data)
6566 dtb.Scan()
6567
6568 props = self._GetPropTree(dtb, ['data-position'])
6569 expected = {
6570 'u-boot:data-position': 1024,
6571 'fdt-1:data-position': 2048,
6572 'fdt-2:data-position': 3072,
6573 }
6574 self.assertEqual(expected, props)
6575
Jonas Karlmanf584d442023-01-21 19:02:12 +00006576 def testFitFirmwareLoadables(self):
6577 """Test an image with an FIT that use fit,firmware"""
6578 if not elf.ELF_TOOLS:
6579 self.skipTest('Python elftools not available')
6580 entry_args = {
6581 'of-list': 'test-fdt1',
6582 'default-dt': 'test-fdt1',
6583 'atf-bl31-path': 'bl31.elf',
6584 'tee-os-path': 'missing.bin',
6585 }
6586 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
Simon Glass7c4027a2023-02-23 18:18:01 -07006587 with test_util.capture_sys_output() as (stdout, stderr):
6588 data = self._DoReadFileDtb(
6589 '276_fit_firmware_loadables.dts',
6590 entry_args=entry_args,
6591 extra_indirs=[test_subdir])[0]
Jonas Karlmanf584d442023-01-21 19:02:12 +00006592
6593 dtb = fdt.Fdt.FromData(data)
6594 dtb.Scan()
6595
6596 node = dtb.GetNode('/configurations/conf-uboot-1')
6597 self.assertEqual('u-boot', node.props['firmware'].value)
6598 self.assertEqual(['atf-1', 'atf-2'],
6599 fdt_util.GetStringList(node, 'loadables'))
6600
6601 node = dtb.GetNode('/configurations/conf-atf-1')
6602 self.assertEqual('atf-1', node.props['firmware'].value)
6603 self.assertEqual(['u-boot', 'atf-2'],
6604 fdt_util.GetStringList(node, 'loadables'))
6605
6606 node = dtb.GetNode('/configurations/conf-missing-uboot-1')
6607 self.assertEqual('u-boot', node.props['firmware'].value)
6608 self.assertEqual(['atf-1', 'atf-2'],
6609 fdt_util.GetStringList(node, 'loadables'))
6610
6611 node = dtb.GetNode('/configurations/conf-missing-atf-1')
6612 self.assertEqual('atf-1', node.props['firmware'].value)
6613 self.assertEqual(['u-boot', 'atf-2'],
6614 fdt_util.GetStringList(node, 'loadables'))
6615
6616 node = dtb.GetNode('/configurations/conf-missing-tee-1')
6617 self.assertEqual('atf-1', node.props['firmware'].value)
6618 self.assertEqual(['u-boot', 'atf-2'],
6619 fdt_util.GetStringList(node, 'loadables'))
6620
Simon Glassfe7e9242023-02-22 12:14:49 -07006621 def testTooldir(self):
6622 """Test that we can specify the tooldir"""
6623 with test_util.capture_sys_output() as (stdout, stderr):
6624 self.assertEqual(0, self._DoBinman('--tooldir', 'fred',
6625 'tool', '-l'))
6626 self.assertEqual('fred', bintool.Bintool.tooldir)
6627
6628 # Check that the toolpath is updated correctly
6629 self.assertEqual(['fred'], tools.tool_search_paths)
6630
6631 # Try with a few toolpaths; the tooldir should be at the end
6632 with test_util.capture_sys_output() as (stdout, stderr):
6633 self.assertEqual(0, self._DoBinman(
6634 '--toolpath', 'mary', '--toolpath', 'anna', '--tooldir', 'fred',
6635 'tool', '-l'))
6636 self.assertEqual(['mary', 'anna', 'fred'], tools.tool_search_paths)
6637
Simon Glass7caa3722023-03-02 17:02:44 -07006638 def testReplaceSectionEntry(self):
6639 """Test replacing an entry in a section"""
6640 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6641 entry_data, expected_fdtmap, image = self._RunReplaceCmd('section/blob',
6642 expect_data, dts='241_replace_section_simple.dts')
6643 self.assertEqual(expect_data, entry_data)
6644
6645 entries = image.GetEntries()
6646 self.assertIn('section', entries)
6647 section = entries['section']
6648
6649 sect_entries = section.GetEntries()
6650 self.assertIn('blob', sect_entries)
6651 entry = sect_entries['blob']
6652 self.assertEqual(len(expect_data), entry.size)
6653
6654 fname = tools.get_output_filename('image-updated.bin')
6655 data = tools.read_file(fname)
6656
6657 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6658 self.assertEqual(expect_data, new_blob_data)
6659
6660 self.assertEqual(U_BOOT_DATA,
6661 data[entry.image_pos + len(expect_data):]
6662 [:len(U_BOOT_DATA)])
6663
6664 def testReplaceSectionDeep(self):
6665 """Test replacing an entry in two levels of sections"""
6666 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6667 entry_data, expected_fdtmap, image = self._RunReplaceCmd(
6668 'section/section/blob', expect_data,
6669 dts='278_replace_section_deep.dts')
6670 self.assertEqual(expect_data, entry_data)
6671
6672 entries = image.GetEntries()
6673 self.assertIn('section', entries)
6674 section = entries['section']
6675
6676 subentries = section.GetEntries()
6677 self.assertIn('section', subentries)
6678 section = subentries['section']
6679
6680 sect_entries = section.GetEntries()
6681 self.assertIn('blob', sect_entries)
6682 entry = sect_entries['blob']
6683 self.assertEqual(len(expect_data), entry.size)
6684
6685 fname = tools.get_output_filename('image-updated.bin')
6686 data = tools.read_file(fname)
6687
6688 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6689 self.assertEqual(expect_data, new_blob_data)
6690
6691 self.assertEqual(U_BOOT_DATA,
6692 data[entry.image_pos + len(expect_data):]
6693 [:len(U_BOOT_DATA)])
6694
6695 def testReplaceFitSibling(self):
6696 """Test an image with a FIT inside where we replace its sibling"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06006697 self._SetupSplElf()
Simon Glass7caa3722023-03-02 17:02:44 -07006698 fname = TestFunctional._MakeInputFile('once', b'available once')
6699 self._DoReadFileRealDtb('277_replace_fit_sibling.dts')
6700 os.remove(fname)
6701
6702 try:
6703 tmpdir, updated_fname = self._SetupImageInTmpdir()
6704
6705 fname = os.path.join(tmpdir, 'update-blob')
6706 expected = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
6707 tools.write_file(fname, expected)
6708
6709 self._DoBinman('replace', '-i', updated_fname, 'blob', '-f', fname)
6710 data = tools.read_file(updated_fname)
6711 start = len(U_BOOT_DTB_DATA)
6712 self.assertEqual(expected, data[start:start + len(expected)])
6713 map_fname = os.path.join(tmpdir, 'image-updated.map')
6714 self.assertFalse(os.path.exists(map_fname))
6715 finally:
6716 shutil.rmtree(tmpdir)
6717
Simon Glass953d4172023-03-02 17:02:45 -07006718 def testX509Cert(self):
6719 """Test creating an X509 certificate"""
6720 keyfile = self.TestFile('key.key')
6721 entry_args = {
6722 'keyfile': keyfile,
6723 }
6724 data = self._DoReadFileDtb('279_x509_cert.dts',
6725 entry_args=entry_args)[0]
6726 cert = data[:-4]
6727 self.assertEqual(U_BOOT_DATA, data[-4:])
6728
6729 # TODO: verify the signature
6730
6731 def testX509CertMissing(self):
6732 """Test that binman still produces an image if openssl is missing"""
6733 keyfile = self.TestFile('key.key')
6734 entry_args = {
6735 'keyfile': 'keyfile',
6736 }
6737 with test_util.capture_sys_output() as (_, stderr):
6738 self._DoTestFile('279_x509_cert.dts',
6739 force_missing_bintools='openssl',
6740 entry_args=entry_args)
6741 err = stderr.getvalue()
6742 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
6743
Jonas Karlman05b978b2023-02-25 19:01:33 +00006744 def testPackRockchipTpl(self):
6745 """Test that an image with a Rockchip TPL binary can be created"""
Simon Glass176f1f62023-07-24 09:19:58 -06006746 data = self._DoReadFile('291_rockchip_tpl.dts')
Jonas Karlman05b978b2023-02-25 19:01:33 +00006747 self.assertEqual(ROCKCHIP_TPL_DATA, data[:len(ROCKCHIP_TPL_DATA)])
6748
Jonas Karlman40389c22023-02-25 19:01:35 +00006749 def testMkimageMissingBlobMultiple(self):
6750 """Test missing blob with mkimage entry and multiple-data-files"""
6751 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass176f1f62023-07-24 09:19:58 -06006752 self._DoTestFile('292_mkimage_missing_multiple.dts', allow_missing=True)
Jonas Karlman40389c22023-02-25 19:01:35 +00006753 err = stderr.getvalue()
6754 self.assertIn("is missing external blobs and is non-functional", err)
6755
6756 with self.assertRaises(ValueError) as e:
Simon Glass176f1f62023-07-24 09:19:58 -06006757 self._DoTestFile('292_mkimage_missing_multiple.dts', allow_missing=False)
Jonas Karlman40389c22023-02-25 19:01:35 +00006758 self.assertIn("not found in input path", str(e.exception))
6759
Ivan Mikhaylov5b34efe2023-03-08 01:13:40 +00006760 def _PrepareSignEnv(self, dts='280_fit_sign.dts'):
6761 """Prepare sign environment
6762
6763 Create private and public keys, add pubkey into dtb.
6764
6765 Returns:
6766 Tuple:
6767 FIT container
6768 Image name
6769 Private key
6770 DTB
6771 """
Marek Vasutfadad3a2023-07-18 07:23:58 -06006772 self._SetupSplElf()
Ivan Mikhaylov5b34efe2023-03-08 01:13:40 +00006773 data = self._DoReadFileRealDtb(dts)
6774 updated_fname = tools.get_output_filename('image-updated.bin')
6775 tools.write_file(updated_fname, data)
6776 dtb = tools.get_output_filename('source.dtb')
6777 private_key = tools.get_output_filename('test_key.key')
6778 public_key = tools.get_output_filename('test_key.crt')
6779 fit = tools.get_output_filename('fit.fit')
6780 key_dir = tools.get_output_dir()
6781
6782 tools.run('openssl', 'req', '-batch' , '-newkey', 'rsa:4096',
6783 '-sha256', '-new', '-nodes', '-x509', '-keyout',
6784 private_key, '-out', public_key)
6785 tools.run('fdt_add_pubkey', '-a', 'sha256,rsa4096', '-k', key_dir,
6786 '-n', 'test_key', '-r', 'conf', dtb)
6787
6788 return fit, updated_fname, private_key, dtb
6789
6790 def testSignSimple(self):
6791 """Test that a FIT container can be signed in image"""
6792 is_signed = False
6793 fit, fname, private_key, dtb = self._PrepareSignEnv()
6794
6795 # do sign with private key
6796 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6797 ['fit'])
6798 is_signed = self._CheckSign(fit, dtb)
6799
6800 self.assertEqual(is_signed, True)
6801
6802 def testSignExactFIT(self):
6803 """Test that a FIT container can be signed and replaced in image"""
6804 is_signed = False
6805 fit, fname, private_key, dtb = self._PrepareSignEnv()
6806
6807 # Make sure we propagate the toolpath, since mkimage may not be on PATH
6808 args = []
6809 if self.toolpath:
6810 for path in self.toolpath:
6811 args += ['--toolpath', path]
6812
6813 # do sign with private key
6814 self._DoBinman(*args, 'sign', '-i', fname, '-k', private_key, '-a',
6815 'sha256,rsa4096', '-f', fit, 'fit')
6816 is_signed = self._CheckSign(fit, dtb)
6817
6818 self.assertEqual(is_signed, True)
6819
6820 def testSignNonFit(self):
6821 """Test a non-FIT entry cannot be signed"""
6822 is_signed = False
6823 fit, fname, private_key, _ = self._PrepareSignEnv(
6824 '281_sign_non_fit.dts')
6825
6826 # do sign with private key
6827 with self.assertRaises(ValueError) as e:
6828 self._DoBinman('sign', '-i', fname, '-k', private_key, '-a',
6829 'sha256,rsa4096', '-f', fit, 'u-boot')
6830 self.assertIn(
6831 "Node '/u-boot': Updating signatures is not supported with this entry type",
6832 str(e.exception))
6833
6834 def testSignMissingMkimage(self):
6835 """Test that FIT signing handles a missing mkimage tool"""
6836 fit, fname, private_key, _ = self._PrepareSignEnv()
6837
6838 # try to sign with a missing mkimage tool
6839 bintool.Bintool.set_missing_list(['mkimage'])
6840 with self.assertRaises(ValueError) as e:
6841 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6842 ['fit'])
6843 self.assertIn("Node '/fit': Missing tool: 'mkimage'", str(e.exception))
6844
Simon Glass4649bea2023-07-18 07:23:54 -06006845 def testSymbolNoWrite(self):
6846 """Test disabling of symbol writing"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06006847 self._SetupSplElf()
Simon Glass4649bea2023-07-18 07:23:54 -06006848 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_DATA, 0x1c,
6849 no_write_symbols=True)
6850
6851 def testSymbolNoWriteExpanded(self):
6852 """Test disabling of symbol writing in expanded entries"""
6853 entry_args = {
6854 'spl-dtb': '1',
6855 }
6856 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_NODTB_DATA +
6857 U_BOOT_SPL_DTB_DATA, 0x38,
6858 entry_args=entry_args, use_expanded=True,
6859 no_write_symbols=True)
6860
Marek Vasutfadad3a2023-07-18 07:23:58 -06006861 def testMkimageSpecial(self):
6862 """Test mkimage ignores special hash-1 node"""
6863 data = self._DoReadFile('283_mkimage_special.dts')
6864
6865 # Just check that the data appears in the file somewhere
6866 self.assertIn(U_BOOT_DATA, data)
6867
Simon Glassb1e40ee2023-07-18 07:23:59 -06006868 def testFitFdtList(self):
6869 """Test an image with an FIT with the fit,fdt-list-val option"""
6870 entry_args = {
6871 'default-dt': 'test-fdt2',
6872 }
6873 data = self._DoReadFileDtb(
6874 '284_fit_fdt_list.dts',
6875 entry_args=entry_args,
6876 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
6877 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
6878 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
6879
Simon Glasse1ad57e2023-07-18 07:24:01 -06006880 def testSplEmptyBss(self):
6881 """Test an expanded SPL with a zero-size BSS"""
6882 # ELF file with a '__bss_size' symbol
6883 self._SetupSplElf(src_fname='bss_data_zero')
6884
6885 entry_args = {
6886 'spl-bss-pad': 'y',
6887 'spl-dtb': 'y',
6888 }
6889 data = self._DoReadFileDtb('285_spl_expand.dts',
6890 use_expanded=True, entry_args=entry_args)[0]
6891
Simon Glassf6abd522023-07-18 07:24:04 -06006892 def testTemplate(self):
6893 """Test using a template"""
6894 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
6895 data = self._DoReadFile('286_template.dts')
6896 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
6897 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
6898 self.assertEqual(U_BOOT_IMG_DATA + first + second, data)
6899
Simon Glassb2f47a52023-07-22 21:43:52 -06006900 dtb_fname1 = tools.get_output_filename('u-boot.dtb.tmpl1')
6901 self.assertTrue(os.path.exists(dtb_fname1))
6902 dtb = fdt.Fdt.FromData(tools.read_file(dtb_fname1))
6903 dtb.Scan()
6904 node1 = dtb.GetNode('/binman/template')
6905 self.assertTrue(node1)
6906 vga = dtb.GetNode('/binman/first/intel-vga')
6907 self.assertTrue(vga)
6908
Simon Glassaf41b242023-07-22 21:43:56 -06006909 dtb_fname2 = tools.get_output_filename('u-boot.dtb.tmpl2')
6910 self.assertTrue(os.path.exists(dtb_fname2))
6911 dtb2 = fdt.Fdt.FromData(tools.read_file(dtb_fname2))
6912 dtb2.Scan()
6913 node2 = dtb2.GetNode('/binman/template')
6914 self.assertFalse(node2)
6915
Simon Glass35f72fb2023-07-18 07:24:05 -06006916 def testTemplateBlobMulti(self):
6917 """Test using a template with 'multiple-images' enabled"""
6918 TestFunctional._MakeInputFile('my-blob.bin', b'blob')
6919 TestFunctional._MakeInputFile('my-blob2.bin', b'other')
6920 retcode = self._DoTestFile('287_template_multi.dts')
6921
6922 self.assertEqual(0, retcode)
6923 image = control.images['image']
6924 image_fname = tools.get_output_filename('my-image.bin')
6925 data = tools.read_file(image_fname)
6926 self.assertEqual(b'blob@@@@other', data)
6927
Simon Glassdb0e3f12023-07-18 07:24:06 -06006928 def testTemplateFit(self):
6929 """Test using a template in a FIT"""
6930 fit_data = self._DoReadFile('288_template_fit.dts')
6931 fname = os.path.join(self._indir, 'fit_data.fit')
6932 tools.write_file(fname, fit_data)
6933 out = tools.run('dumpimage', '-l', fname)
6934
Simon Glass696f2b72023-07-18 07:24:07 -06006935 def testTemplateSection(self):
6936 """Test using a template in a section (not at top level)"""
6937 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
6938 data = self._DoReadFile('289_template_section.dts')
6939 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
6940 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
6941 self.assertEqual(U_BOOT_IMG_DATA + first + second + first, data)
6942
Simon Glass23b96e92023-07-18 07:24:08 -06006943 def testMkimageSymbols(self):
6944 """Test using mkimage to build an image with symbols in it"""
6945 self._SetupSplElf('u_boot_binman_syms')
6946 data = self._DoReadFile('290_mkimage_sym.dts')
6947
6948 image = control.images['image']
6949 entries = image.GetEntries()
6950 self.assertIn('u-boot', entries)
6951 u_boot = entries['u-boot']
6952
6953 mkim = entries['mkimage']
6954 mkim_entries = mkim.GetEntries()
6955 self.assertIn('u-boot-spl', mkim_entries)
6956 spl = mkim_entries['u-boot-spl']
6957 self.assertIn('u-boot-spl2', mkim_entries)
6958 spl2 = mkim_entries['u-boot-spl2']
6959
6960 # skip the mkimage header and the area sizes
6961 mk_data = data[mkim.offset + 0x40:]
6962 size, term = struct.unpack('>LL', mk_data[:8])
6963
6964 # There should be only one image, so check that the zero terminator is
6965 # present
6966 self.assertEqual(0, term)
6967
6968 content = mk_data[8:8 + size]
6969
6970 # The image should contain the symbols from u_boot_binman_syms.c
6971 # Note that image_pos is adjusted by the base address of the image,
6972 # which is 0x10 in our test image
6973 spl_data = content[:0x18]
6974 content = content[0x1b:]
6975
6976 # After the header is a table of offsets for each image. There should
6977 # only be one image, then a 0 terminator, so figure out the real start
6978 # of the image data
6979 base = 0x40 + 8
6980
6981 # Check symbols in both u-boot-spl and u-boot-spl2
6982 for i in range(2):
6983 vals = struct.unpack('<LLQLL', spl_data)
6984
6985 # The image should contain the symbols from u_boot_binman_syms.c
6986 # Note that image_pos is adjusted by the base address of the image,
6987 # which is 0x10 in our 'u_boot_binman_syms' test image
6988 self.assertEqual(elf.BINMAN_SYM_MAGIC_VALUE, vals[0])
6989 self.assertEqual(base, vals[1])
6990 self.assertEqual(spl2.offset, vals[2])
6991 # figure out the internal positions of its components
6992 self.assertEqual(0x10 + u_boot.image_pos, vals[3])
6993
6994 # Check that spl and spl2 are actually at the indicated positions
6995 self.assertEqual(
6996 elf.BINMAN_SYM_MAGIC_VALUE,
6997 struct.unpack('<I', data[spl.image_pos:spl.image_pos + 4])[0])
6998 self.assertEqual(
6999 elf.BINMAN_SYM_MAGIC_VALUE,
7000 struct.unpack('<I', data[spl2.image_pos:spl2.image_pos + 4])[0])
7001
7002 self.assertEqual(len(U_BOOT_DATA), vals[4])
7003
7004 # Move to next
7005 spl_data = content[:0x18]
7006
Simon Glassd4d97662023-07-22 21:43:57 -06007007 def testTemplatePhandle(self):
7008 """Test using a template in a node containing a phandle"""
7009 entry_args = {
7010 'atf-bl31-path': 'bl31.elf',
7011 }
Simon Glass93a203d2023-08-03 17:23:58 -06007012 data = self._DoReadFileDtb('309_template_phandle.dts',
Simon Glassd4d97662023-07-22 21:43:57 -06007013 entry_args=entry_args)
7014 fname = tools.get_output_filename('image.bin')
7015 out = tools.run('dumpimage', '-l', fname)
7016
7017 # We should see the FIT description and one for each of the two images
7018 lines = out.splitlines()
7019 descs = [line.split()[-1] for line in lines if 'escription' in line]
7020 self.assertEqual(['test-desc', 'atf', 'fdt'], descs)
7021
7022 def testTemplatePhandleDup(self):
7023 """Test using a template in a node containing a phandle"""
7024 entry_args = {
7025 'atf-bl31-path': 'bl31.elf',
7026 }
7027 with self.assertRaises(ValueError) as e:
Simon Glass93a203d2023-08-03 17:23:58 -06007028 self._DoReadFileDtb('310_template_phandle_dup.dts',
Simon Glassd4d97662023-07-22 21:43:57 -06007029 entry_args=entry_args)
7030 self.assertIn(
7031 'Duplicate phandle 1 in nodes /binman/image/fit/images/atf/atf-bl31 and /binman/image-2/fit/images/atf/atf-bl31',
7032 str(e.exception))
7033
Neha Malcom Francis6c66ccf2023-07-22 00:14:24 +05307034 def testTIBoardConfig(self):
7035 """Test that a schema validated board config file can be generated"""
Simon Glassa6b44ac2023-07-24 09:19:59 -06007036 data = self._DoReadFile('293_ti_board_cfg.dts')
Neha Malcom Francis6c66ccf2023-07-22 00:14:24 +05307037 self.assertEqual(TI_BOARD_CONFIG_DATA, data)
7038
Neha Malcom Francis10fee882024-01-05 17:09:17 +05307039 def testTIBoardConfigLint(self):
7040 """Test that an incorrectly linted config file would generate error"""
7041 with self.assertRaises(ValueError) as e:
7042 data = self._DoReadFile('323_ti_board_cfg_phony.dts')
7043 self.assertIn("Yamllint error", str(e.exception))
7044
Neha Malcom Francis6c66ccf2023-07-22 00:14:24 +05307045 def testTIBoardConfigCombined(self):
7046 """Test that a schema validated combined board config file can be generated"""
Simon Glassa6b44ac2023-07-24 09:19:59 -06007047 data = self._DoReadFile('294_ti_board_cfg_combined.dts')
Neha Malcom Francis6c66ccf2023-07-22 00:14:24 +05307048 configlen_noheader = TI_BOARD_CONFIG_DATA * 4
7049 self.assertGreater(data, configlen_noheader)
7050
7051 def testTIBoardConfigNoDataType(self):
7052 """Test that error is thrown when data type is not supported"""
7053 with self.assertRaises(ValueError) as e:
Simon Glassa6b44ac2023-07-24 09:19:59 -06007054 data = self._DoReadFile('295_ti_board_cfg_no_type.dts')
Neha Malcom Francis6c66ccf2023-07-22 00:14:24 +05307055 self.assertIn("Schema validation error", str(e.exception))
Simon Glassefddab62023-01-07 14:07:08 -07007056
Neha Malcom Francis78144822023-07-22 00:14:25 +05307057 def testPackTiSecure(self):
7058 """Test that an image with a TI secured binary can be created"""
7059 keyfile = self.TestFile('key.key')
7060 entry_args = {
7061 'keyfile': keyfile,
7062 }
Simon Glassa6b44ac2023-07-24 09:19:59 -06007063 data = self._DoReadFileDtb('296_ti_secure.dts',
Neha Malcom Francis78144822023-07-22 00:14:25 +05307064 entry_args=entry_args)[0]
7065 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7066
Manorit Chawdhryba512992023-12-29 16:16:27 +05307067 def testPackTiSecureFirewall(self):
7068 """Test that an image with a TI secured binary can be created"""
7069 keyfile = self.TestFile('key.key')
7070 entry_args = {
7071 'keyfile': keyfile,
7072 }
7073 data_no_firewall = self._DoReadFileDtb('296_ti_secure.dts',
7074 entry_args=entry_args)[0]
7075 data_firewall = self._DoReadFileDtb('324_ti_secure_firewall.dts',
7076 entry_args=entry_args)[0]
7077 self.assertGreater(len(data_firewall),len(data_no_firewall))
7078
7079 def testPackTiSecureFirewallMissingProperty(self):
7080 """Test that an image with a TI secured binary can be created"""
7081 keyfile = self.TestFile('key.key')
7082 entry_args = {
7083 'keyfile': keyfile,
7084 }
7085 with self.assertRaises(ValueError) as e:
7086 data_firewall = self._DoReadFileDtb('325_ti_secure_firewall_missing_property.dts',
7087 entry_args=entry_args)[0]
7088 self.assertRegex(str(e.exception), "Node '/binman/ti-secure': Subnode 'firewall-0-2' is missing properties: id,region")
7089
Neha Malcom Francis78144822023-07-22 00:14:25 +05307090 def testPackTiSecureMissingTool(self):
7091 """Test that an image with a TI secured binary (non-functional) can be created
7092 when openssl is missing"""
7093 keyfile = self.TestFile('key.key')
7094 entry_args = {
7095 'keyfile': keyfile,
7096 }
7097 with test_util.capture_sys_output() as (_, stderr):
Simon Glassa6b44ac2023-07-24 09:19:59 -06007098 self._DoTestFile('296_ti_secure.dts',
Neha Malcom Francis78144822023-07-22 00:14:25 +05307099 force_missing_bintools='openssl',
7100 entry_args=entry_args)
7101 err = stderr.getvalue()
7102 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
7103
7104 def testPackTiSecureROM(self):
7105 """Test that a ROM image with a TI secured binary can be created"""
7106 keyfile = self.TestFile('key.key')
7107 entry_args = {
7108 'keyfile': keyfile,
7109 }
Simon Glassa6b44ac2023-07-24 09:19:59 -06007110 data = self._DoReadFileDtb('297_ti_secure_rom.dts',
Neha Malcom Francis78144822023-07-22 00:14:25 +05307111 entry_args=entry_args)[0]
Simon Glassa6b44ac2023-07-24 09:19:59 -06007112 data_a = self._DoReadFileDtb('299_ti_secure_rom_a.dts',
Neha Malcom Francis78144822023-07-22 00:14:25 +05307113 entry_args=entry_args)[0]
Simon Glassa6b44ac2023-07-24 09:19:59 -06007114 data_b = self._DoReadFileDtb('300_ti_secure_rom_b.dts',
Neha Malcom Francis78144822023-07-22 00:14:25 +05307115 entry_args=entry_args)[0]
7116 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7117 self.assertGreater(len(data_a), len(TI_UNSECURE_DATA))
7118 self.assertGreater(len(data_b), len(TI_UNSECURE_DATA))
7119
7120 def testPackTiSecureROMCombined(self):
7121 """Test that a ROM image with a TI secured binary can be created"""
7122 keyfile = self.TestFile('key.key')
7123 entry_args = {
7124 'keyfile': keyfile,
7125 }
Simon Glassa6b44ac2023-07-24 09:19:59 -06007126 data = self._DoReadFileDtb('298_ti_secure_rom_combined.dts',
Neha Malcom Francis78144822023-07-22 00:14:25 +05307127 entry_args=entry_args)[0]
7128 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7129
Christian Taedcke289e6002023-07-17 09:05:54 +02007130 def testEncryptedNoAlgo(self):
7131 """Test encrypted node with missing required properties"""
7132 with self.assertRaises(ValueError) as e:
7133 self._DoReadFileDtb('301_encrypted_no_algo.dts')
7134 self.assertIn(
7135 "Node '/binman/fit/images/u-boot/encrypted': 'encrypted' entry is missing properties: algo iv-filename",
7136 str(e.exception))
7137
7138 def testEncryptedInvalidIvfile(self):
7139 """Test encrypted node with invalid iv file"""
7140 with self.assertRaises(ValueError) as e:
7141 self._DoReadFileDtb('302_encrypted_invalid_iv_file.dts')
7142 self.assertIn("Filename 'invalid-iv-file' not found in input path",
7143 str(e.exception))
7144
7145 def testEncryptedMissingKey(self):
7146 """Test encrypted node with missing key properties"""
7147 with self.assertRaises(ValueError) as e:
7148 self._DoReadFileDtb('303_encrypted_missing_key.dts')
7149 self.assertIn(
7150 "Node '/binman/fit/images/u-boot/encrypted': Provide either 'key-filename' or 'key-source'",
7151 str(e.exception))
7152
7153 def testEncryptedKeySource(self):
7154 """Test encrypted node with key-source property"""
7155 data = self._DoReadFileDtb('304_encrypted_key_source.dts')[0]
7156
7157 dtb = fdt.Fdt.FromData(data)
7158 dtb.Scan()
7159
7160 node = dtb.GetNode('/images/u-boot/cipher')
7161 self.assertEqual('algo-name', node.props['algo'].value)
7162 self.assertEqual('key-source-value', node.props['key-source'].value)
7163 self.assertEqual(ENCRYPTED_IV_DATA,
7164 tools.to_bytes(''.join(node.props['iv'].value)))
7165 self.assertNotIn('key', node.props)
7166
7167 def testEncryptedKeyFile(self):
7168 """Test encrypted node with key-filename property"""
7169 data = self._DoReadFileDtb('305_encrypted_key_file.dts')[0]
7170
7171 dtb = fdt.Fdt.FromData(data)
7172 dtb.Scan()
7173
7174 node = dtb.GetNode('/images/u-boot/cipher')
7175 self.assertEqual('algo-name', node.props['algo'].value)
7176 self.assertEqual(ENCRYPTED_IV_DATA,
7177 tools.to_bytes(''.join(node.props['iv'].value)))
7178 self.assertEqual(ENCRYPTED_KEY_DATA,
7179 tools.to_bytes(''.join(node.props['key'].value)))
7180 self.assertNotIn('key-source', node.props)
7181
7182
Lukas Funke8c1fbd12023-07-18 13:53:13 +02007183 def testSplPubkeyDtb(self):
Simon Glassa56ea602024-07-20 11:49:41 +01007184 """Test u_boot_spl_pubkey_dtb etype"""
7185 data = tools.read_file(self.TestFile("key.pem"))
7186 self._MakeInputFile("key.crt", data)
7187 self._DoReadFileRealDtb('306_spl_pubkey_dtb.dts')
7188 image = control.images['image']
7189 entries = image.GetEntries()
7190 dtb_entry = entries['u-boot-spl-pubkey-dtb']
7191 dtb_data = dtb_entry.GetData()
7192 dtb = fdt.Fdt.FromData(dtb_data)
7193 dtb.Scan()
Lukas Funke8c1fbd12023-07-18 13:53:13 +02007194
Simon Glassa56ea602024-07-20 11:49:41 +01007195 signature_node = dtb.GetNode('/signature')
7196 self.assertIsNotNone(signature_node)
7197 key_node = signature_node.FindNode("key-key")
7198 self.assertIsNotNone(key_node)
7199 self.assertEqual(fdt_util.GetString(key_node, "required"), "conf")
7200 self.assertEqual(fdt_util.GetString(key_node, "algo"), "sha384,rsa4096")
7201 self.assertEqual(fdt_util.GetString(key_node, "key-name-hint"), "key")
Lukas Funke8c1fbd12023-07-18 13:53:13 +02007202
Lukas Funked8a2d3b2023-08-03 17:22:14 +02007203 def testXilinxBootgenSigning(self):
7204 """Test xilinx-bootgen etype"""
7205 bootgen = bintool.Bintool.create('bootgen')
7206 self._CheckBintool(bootgen)
7207 data = tools.read_file(self.TestFile("key.key"))
7208 self._MakeInputFile("psk.pem", data)
7209 self._MakeInputFile("ssk.pem", data)
7210 self._SetupPmuFwlElf()
7211 self._SetupSplElf()
7212 self._DoReadFileRealDtb('307_xilinx_bootgen_sign.dts')
7213 image_fname = tools.get_output_filename('image.bin')
7214
7215 # Read partition header table and check if authentication is enabled
7216 bootgen_out = bootgen.run_cmd("-arch", "zynqmp",
7217 "-read", image_fname, "pht").splitlines()
7218 attributes = {"authentication": None,
7219 "core": None,
7220 "encryption": None}
7221
7222 for l in bootgen_out:
7223 for a in attributes.keys():
7224 if a in l:
7225 m = re.match(fr".*{a} \[([^]]+)\]", l)
7226 attributes[a] = m.group(1)
7227
7228 self.assertTrue(attributes['authentication'] == "rsa")
7229 self.assertTrue(attributes['core'] == "a53-0")
7230 self.assertTrue(attributes['encryption'] == "no")
7231
7232 def testXilinxBootgenSigningEncryption(self):
7233 """Test xilinx-bootgen etype"""
7234 bootgen = bintool.Bintool.create('bootgen')
7235 self._CheckBintool(bootgen)
7236 data = tools.read_file(self.TestFile("key.key"))
7237 self._MakeInputFile("psk.pem", data)
7238 self._MakeInputFile("ssk.pem", data)
7239 self._SetupPmuFwlElf()
7240 self._SetupSplElf()
7241 self._DoReadFileRealDtb('308_xilinx_bootgen_sign_enc.dts')
7242 image_fname = tools.get_output_filename('image.bin')
7243
7244 # Read boot header in order to verify encryption source and
7245 # encryption parameter
7246 bootgen_out = bootgen.run_cmd("-arch", "zynqmp",
7247 "-read", image_fname, "bh").splitlines()
7248 attributes = {"auth_only":
7249 {"re": r".*auth_only \[([^]]+)\]", "value": None},
7250 "encryption_keystore":
7251 {"re": r" *encryption_keystore \(0x28\) : (.*)",
7252 "value": None},
7253 }
7254
7255 for l in bootgen_out:
7256 for a in attributes.keys():
7257 if a in l:
7258 m = re.match(attributes[a]['re'], l)
7259 attributes[a] = m.group(1)
7260
7261 # Check if fsbl-attribute is set correctly
7262 self.assertTrue(attributes['auth_only'] == "true")
7263 # Check if key is stored in efuse
7264 self.assertTrue(attributes['encryption_keystore'] == "0xa5c3c5a3")
7265
7266 def testXilinxBootgenMissing(self):
7267 """Test that binman still produces an image if bootgen is missing"""
7268 data = tools.read_file(self.TestFile("key.key"))
7269 self._MakeInputFile("psk.pem", data)
7270 self._MakeInputFile("ssk.pem", data)
7271 self._SetupPmuFwlElf()
7272 self._SetupSplElf()
7273 with test_util.capture_sys_output() as (_, stderr):
7274 self._DoTestFile('307_xilinx_bootgen_sign.dts',
7275 force_missing_bintools='bootgen')
7276 err = stderr.getvalue()
7277 self.assertRegex(err,
7278 "Image 'image'.*missing bintools.*: bootgen")
7279
Sughosh Ganu809f28e2023-10-10 14:40:57 +05307280 def _GetCapsuleHeaders(self, data):
7281 """Get the capsule header contents
7282
7283 Args:
7284 data: Capsule file contents
7285
7286 Returns:
7287 Dict:
7288 key: Capsule Header name (str)
7289 value: Header field value (str)
7290 """
7291 capsule_file = os.path.join(self._indir, 'test.capsule')
7292 tools.write_file(capsule_file, data)
7293
7294 out = tools.run('mkeficapsule', '--dump-capsule', capsule_file)
7295 lines = out.splitlines()
7296
7297 re_line = re.compile(r'^([^:\-\t]*)(?:\t*\s*:\s*(.*))?$')
7298 vals = {}
7299 for line in lines:
7300 mat = re_line.match(line)
7301 if mat:
7302 vals[mat.group(1)] = mat.group(2)
7303
7304 return vals
7305
Sughosh Ganub6176112023-08-22 23:09:59 +05307306 def _CheckCapsule(self, data, signed_capsule=False, version_check=False,
7307 capoemflags=False):
Sughosh Ganu809f28e2023-10-10 14:40:57 +05307308 fmp_signature = "3153534D" # 'M', 'S', 'S', '1'
7309 fmp_size = "00000010"
7310 fmp_fw_version = "00000002"
7311 capsule_image_index = "00000001"
7312 oemflag = "00018000"
7313 auth_hdr_revision = "00000200"
7314 auth_hdr_cert_type = "00000EF1"
Sughosh Ganub6176112023-08-22 23:09:59 +05307315
Sughosh Ganu809f28e2023-10-10 14:40:57 +05307316 payload_data_len = len(EFI_CAPSULE_DATA)
Sughosh Ganub6176112023-08-22 23:09:59 +05307317
Sughosh Ganu809f28e2023-10-10 14:40:57 +05307318 hdr = self._GetCapsuleHeaders(data)
Sughosh Ganub6176112023-08-22 23:09:59 +05307319
Sughosh Ganu809f28e2023-10-10 14:40:57 +05307320 self.assertEqual(FW_MGMT_GUID.upper(), hdr['EFI_CAPSULE_HDR.CAPSULE_GUID'])
7321
7322 self.assertEqual(CAPSULE_IMAGE_GUID.upper(),
7323 hdr['FMP_CAPSULE_IMAGE_HDR.UPDATE_IMAGE_TYPE_ID'])
7324 self.assertEqual(capsule_image_index,
7325 hdr['FMP_CAPSULE_IMAGE_HDR.UPDATE_IMAGE_INDEX'])
Sughosh Ganub6176112023-08-22 23:09:59 +05307326
7327 if capoemflags:
Sughosh Ganu809f28e2023-10-10 14:40:57 +05307328 self.assertEqual(oemflag, hdr['EFI_CAPSULE_HDR.FLAGS'])
7329
7330 if signed_capsule:
7331 self.assertEqual(auth_hdr_revision,
7332 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.HDR.wREVISION'])
7333 self.assertEqual(auth_hdr_cert_type,
7334 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.HDR.wCERTTYPE'])
7335 self.assertEqual(WIN_CERT_TYPE_EFI_GUID.upper(),
7336 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.CERT_TYPE'])
7337
7338 if version_check:
7339 self.assertEqual(fmp_signature,
7340 hdr['FMP_PAYLOAD_HDR.SIGNATURE'])
7341 self.assertEqual(fmp_size,
7342 hdr['FMP_PAYLOAD_HDR.HEADER_SIZE'])
7343 self.assertEqual(fmp_fw_version,
7344 hdr['FMP_PAYLOAD_HDR.FW_VERSION'])
7345
7346 self.assertEqual(payload_data_len, int(hdr['Payload Image Size']))
Sughosh Ganub6176112023-08-22 23:09:59 +05307347
Sughosh Ganu74aae502023-10-10 14:40:59 +05307348 def _CheckEmptyCapsule(self, data, accept_capsule=False):
7349 if accept_capsule:
7350 capsule_hdr_guid = EMPTY_CAPSULE_ACCEPT_GUID
7351 else:
7352 capsule_hdr_guid = EMPTY_CAPSULE_REVERT_GUID
7353
7354 hdr = self._GetCapsuleHeaders(data)
7355
7356 self.assertEqual(capsule_hdr_guid.upper(),
7357 hdr['EFI_CAPSULE_HDR.CAPSULE_GUID'])
7358
7359 if accept_capsule:
7360 capsule_size = "0000002C"
7361 else:
7362 capsule_size = "0000001C"
7363 self.assertEqual(capsule_size,
7364 hdr['EFI_CAPSULE_HDR.CAPSULE_IMAGE_SIZE'])
7365
7366 if accept_capsule:
7367 self.assertEqual(CAPSULE_IMAGE_GUID.upper(), hdr['ACCEPT_IMAGE_GUID'])
7368
Sughosh Ganub6176112023-08-22 23:09:59 +05307369 def testCapsuleGen(self):
7370 """Test generation of EFI capsule"""
7371 data = self._DoReadFile('311_capsule.dts')
7372
7373 self._CheckCapsule(data)
7374
7375 def testSignedCapsuleGen(self):
7376 """Test generation of EFI capsule"""
7377 data = tools.read_file(self.TestFile("key.key"))
7378 self._MakeInputFile("key.key", data)
7379 data = tools.read_file(self.TestFile("key.pem"))
7380 self._MakeInputFile("key.crt", data)
7381
7382 data = self._DoReadFile('312_capsule_signed.dts')
7383
7384 self._CheckCapsule(data, signed_capsule=True)
7385
7386 def testCapsuleGenVersionSupport(self):
7387 """Test generation of EFI capsule with version support"""
7388 data = self._DoReadFile('313_capsule_version.dts')
7389
7390 self._CheckCapsule(data, version_check=True)
7391
7392 def testCapsuleGenSignedVer(self):
7393 """Test generation of signed EFI capsule with version information"""
7394 data = tools.read_file(self.TestFile("key.key"))
7395 self._MakeInputFile("key.key", data)
7396 data = tools.read_file(self.TestFile("key.pem"))
7397 self._MakeInputFile("key.crt", data)
7398
7399 data = self._DoReadFile('314_capsule_signed_ver.dts')
7400
7401 self._CheckCapsule(data, signed_capsule=True, version_check=True)
7402
7403 def testCapsuleGenCapOemFlags(self):
7404 """Test generation of EFI capsule with OEM Flags set"""
7405 data = self._DoReadFile('315_capsule_oemflags.dts')
7406
7407 self._CheckCapsule(data, capoemflags=True)
7408
7409 def testCapsuleGenKeyMissing(self):
7410 """Test that binman errors out on missing key"""
7411 with self.assertRaises(ValueError) as e:
7412 self._DoReadFile('316_capsule_missing_key.dts')
7413
7414 self.assertIn("Both private key and public key certificate need to be provided",
7415 str(e.exception))
7416
7417 def testCapsuleGenIndexMissing(self):
7418 """Test that binman errors out on missing image index"""
7419 with self.assertRaises(ValueError) as e:
7420 self._DoReadFile('317_capsule_missing_index.dts')
7421
7422 self.assertIn("entry is missing properties: image-index",
7423 str(e.exception))
7424
7425 def testCapsuleGenGuidMissing(self):
7426 """Test that binman errors out on missing image GUID"""
7427 with self.assertRaises(ValueError) as e:
7428 self._DoReadFile('318_capsule_missing_guid.dts')
7429
7430 self.assertIn("entry is missing properties: image-guid",
7431 str(e.exception))
7432
Sughosh Ganu74aae502023-10-10 14:40:59 +05307433 def testCapsuleGenAcceptCapsule(self):
7434 """Test generationg of accept EFI capsule"""
7435 data = self._DoReadFile('319_capsule_accept.dts')
7436
7437 self._CheckEmptyCapsule(data, accept_capsule=True)
7438
7439 def testCapsuleGenRevertCapsule(self):
7440 """Test generationg of revert EFI capsule"""
7441 data = self._DoReadFile('320_capsule_revert.dts')
7442
7443 self._CheckEmptyCapsule(data)
7444
7445 def testCapsuleGenAcceptGuidMissing(self):
7446 """Test that binman errors out on missing image GUID for accept capsule"""
7447 with self.assertRaises(ValueError) as e:
7448 self._DoReadFile('321_capsule_accept_missing_guid.dts')
7449
7450 self.assertIn("Image GUID needed for generating accept capsule",
7451 str(e.exception))
7452
7453 def testCapsuleGenEmptyCapsuleTypeMissing(self):
7454 """Test that capsule-type is specified"""
7455 with self.assertRaises(ValueError) as e:
7456 self._DoReadFile('322_empty_capsule_type_missing.dts')
7457
7458 self.assertIn("entry is missing properties: capsule-type",
7459 str(e.exception))
7460
7461 def testCapsuleGenAcceptOrRevertMissing(self):
7462 """Test that both accept and revert capsule are not specified"""
7463 with self.assertRaises(ValueError) as e:
7464 self._DoReadFile('323_capsule_accept_revert_missing.dts')
7465
Simon Glass404936e2024-06-23 11:55:06 -06007466 def test_assume_size(self):
7467 """Test handling of the assume-size property for external blob"""
7468 with self.assertRaises(ValueError) as e:
7469 self._DoTestFile('326_assume_size.dts', allow_missing=True,
7470 allow_fake_blobs=True)
7471 self.assertIn("contents size 0xa (10) exceeds section size 0x9 (9)",
7472 str(e.exception))
7473
7474 def test_assume_size_ok(self):
7475 """Test handling of the assume-size where it fits OK"""
7476 with test_util.capture_sys_output() as (stdout, stderr):
7477 self._DoTestFile('327_assume_size_ok.dts', allow_missing=True,
7478 allow_fake_blobs=True)
7479 err = stderr.getvalue()
7480 self.assertRegex(
7481 err,
7482 "Image '.*' has faked external blobs and is non-functional: .*")
7483
7484 def test_assume_size_no_fake(self):
7485 """Test handling of the assume-size where it fits OK"""
7486 with test_util.capture_sys_output() as (stdout, stderr):
7487 self._DoTestFile('327_assume_size_ok.dts', allow_missing=True)
7488 err = stderr.getvalue()
7489 self.assertRegex(
7490 err,
7491 "Image '.*' is missing external blobs and is non-functional: .*")
7492
Simon Glass57902e62024-07-20 11:49:47 +01007493 def SetupAlternateDts(self):
7494 """Compile the .dts test files for alternative-fdt
7495
7496 Returns:
7497 tuple:
7498 str: Test directory created
7499 list of str: '.bin' files which we expect Binman to create
7500 """
7501 testdir = TestFunctional._MakeInputDir('dtb')
7502 dtb_list = []
7503 for fname in glob.glob(f'{self.TestFile("alt_dts")}/*.dts'):
7504 tmp_fname = fdt_util.EnsureCompiled(fname, testdir)
7505 base = os.path.splitext(os.path.basename(fname))[0]
7506 dtb_list.append(base + '.bin')
7507 shutil.move(tmp_fname, os.path.join(testdir, base + '.dtb'))
7508
7509 return testdir, dtb_list
7510
Simon Glass7081a942024-07-20 11:49:45 +01007511 def CheckAlternates(self, dts, phase, xpl_data):
7512 """Run the test for the alterative-fdt etype
7513
7514 Args:
7515 dts (str): Devicetree file to process
7516 phase (str): Phase to process ('spl', 'tpl' or 'vpl')
7517 xpl_data (bytes): Expected data for the phase's binary
7518
7519 Returns:
7520 dict of .dtb files produced
7521 key: str filename
7522 value: Fdt object
7523 """
Simon Glass57902e62024-07-20 11:49:47 +01007524 dtb_list = self.SetupAlternateDts()[1]
Simon Glass7081a942024-07-20 11:49:45 +01007525
7526 entry_args = {
7527 f'{phase}-dtb': '1',
7528 f'{phase}-bss-pad': 'y',
7529 'of-spl-remove-props': 'prop-to-remove another-prop-to-get-rid-of',
7530 }
7531 data = self._DoReadFileDtb(dts, use_real_dtb=True, update_dtb=True,
7532 use_expanded=True, entry_args=entry_args)[0]
7533 self.assertEqual(xpl_data, data[:len(xpl_data)])
7534 rest = data[len(xpl_data):]
7535 pad_len = 10
7536 self.assertEqual(tools.get_bytes(0, pad_len), rest[:pad_len])
7537
7538 # Check the dtb is using the test file
7539 dtb_data = rest[pad_len:]
7540 dtb = fdt.Fdt.FromData(dtb_data)
7541 dtb.Scan()
7542 fdt_size = dtb.GetFdtObj().totalsize()
7543 self.assertEqual('model-not-set',
7544 fdt_util.GetString(dtb.GetRoot(), 'compatible'))
7545
7546 pad_len = 10
7547
7548 # Check the other output files
7549 dtbs = {}
7550 for fname in dtb_list:
7551 pathname = tools.get_output_filename(fname)
7552 self.assertTrue(os.path.exists(pathname))
7553
7554 data = tools.read_file(pathname)
7555 self.assertEqual(xpl_data, data[:len(xpl_data)])
7556 rest = data[len(xpl_data):]
7557
7558 self.assertEqual(tools.get_bytes(0, pad_len), rest[:pad_len])
7559 rest = rest[pad_len:]
7560
7561 dtb = fdt.Fdt.FromData(rest)
7562 dtb.Scan()
7563 dtbs[fname] = dtb
7564
7565 expected = 'one' if '1' in fname else 'two'
7566 self.assertEqual(f'u-boot,model-{expected}',
7567 fdt_util.GetString(dtb.GetRoot(), 'compatible'))
7568
7569 # Make sure the FDT is the same size as the 'main' one
7570 rest = rest[fdt_size:]
7571
7572 self.assertEqual(b'', rest)
7573 return dtbs
7574
7575 def testAlternatesFdt(self):
7576 """Test handling of alternates-fdt etype"""
7577 self._SetupTplElf()
7578 dtbs = self.CheckAlternates('328_alternates_fdt.dts', 'tpl',
7579 U_BOOT_TPL_NODTB_DATA)
7580 for dtb in dtbs.values():
7581 # Check for the node with the tag
7582 node = dtb.GetNode('/node')
7583 self.assertIsNotNone(node)
7584 self.assertEqual(5, len(node.props.keys()))
7585
7586 # Make sure the other node is still there
7587 self.assertIsNotNone(dtb.GetNode('/node/other-node'))
7588
7589 def testAlternatesFdtgrep(self):
7590 """Test handling of alternates-fdt etype using fdtgrep"""
7591 self._SetupTplElf()
7592 dtbs = self.CheckAlternates('329_alternates_fdtgrep.dts', 'tpl',
7593 U_BOOT_TPL_NODTB_DATA)
7594 for dtb in dtbs.values():
7595 # Check for the node with the tag
7596 node = dtb.GetNode('/node')
7597 self.assertIsNotNone(node)
7598 self.assertEqual({'some-prop', 'not-a-prop-to-remove'},
7599 node.props.keys())
7600
7601 # Make sure the other node is gone
7602 self.assertIsNone(dtb.GetNode('/node/other-node'))
7603
7604 def testAlternatesFdtgrepVpl(self):
7605 """Test handling of alternates-fdt etype using fdtgrep with vpl"""
7606 self._SetupVplElf()
7607 dtbs = self.CheckAlternates('330_alternates_vpl.dts', 'vpl',
7608 U_BOOT_VPL_NODTB_DATA)
7609
7610 def testAlternatesFdtgrepSpl(self):
7611 """Test handling of alternates-fdt etype using fdtgrep with spl"""
7612 self._SetupSplElf()
7613 dtbs = self.CheckAlternates('331_alternates_spl.dts', 'spl',
7614 U_BOOT_SPL_NODTB_DATA)
7615
7616 def testAlternatesFdtgrepInval(self):
7617 """Test alternates-fdt etype using fdtgrep with invalid phase"""
7618 self._SetupSplElf()
7619 with self.assertRaises(ValueError) as e:
7620 dtbs = self.CheckAlternates('332_alternates_inval.dts', 'spl',
7621 U_BOOT_SPL_NODTB_DATA)
7622 self.assertIn("Invalid U-Boot phase 'bad-phase': Use tpl/vpl/spl",
7623 str(e.exception))
7624
Simon Glass9db7a3a2024-07-20 11:49:46 +01007625 def testFitFdtListDir(self):
7626 """Test an image with an FIT with FDT images using fit,fdt-list-dir"""
7627 self.CheckFitFdt('333_fit_fdt_dir.dts', False)
7628
Simon Glass57902e62024-07-20 11:49:47 +01007629 def testFitFdtCompat(self):
7630 """Test an image with an FIT with compatible in the config nodes"""
7631 entry_args = {
7632 'of-list': 'model1 model2',
7633 'default-dt': 'model2',
7634 }
7635 testdir, dtb_list = self.SetupAlternateDts()
7636 data = self._DoReadFileDtb(
7637 '334_fit_fdt_compat.dts', use_real_dtb=True, update_dtb=True,
7638 entry_args=entry_args, extra_indirs=[testdir])[0]
7639
7640 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
7641
7642 fit = fdt.Fdt.FromData(fit_data)
7643 fit.Scan()
7644
7645 cnode = fit.GetNode('/configurations')
7646 self.assertIn('default', cnode.props)
7647 self.assertEqual('config-2', cnode.props['default'].value)
7648
7649 for seq in range(1, 2):
7650 name = f'config-{seq}'
7651 fnode = fit.GetNode('/configurations/%s' % name)
7652 self.assertIsNotNone(fnode)
7653 self.assertIn('compatible', fnode.props.keys())
7654 expected = 'one' if seq == 1 else 'two'
7655 self.assertEqual(f'u-boot,model-{expected}',
7656 fnode.props['compatible'].value)
7657
Simon Glass404936e2024-06-23 11:55:06 -06007658
Simon Glass9fc60b42017-11-12 21:52:22 -07007659if __name__ == "__main__":
7660 unittest.main()